3

您将如何从数据框中创建一个向量,该向量为每一行提供该行中“NA”(或自定义值)的列数以及上面的n行和下面的m行。

因此,如果m = n = 1 (即每行中有多少列是 NA 并且在前后有 NA )并且我的数据框是

structure(list(X = 1:8, A = c(3L, NA, 10L, NA, 6L, NA, 5L, NA
), B = c(6L, NA, NA, NA, 8L, NA, 13L, NA), C = c(NA, 12L, 14L,  
NA, NA, NA, 9L, NA), D = c(NA, NA, NA, NA, NA, 11L, 7L, NA)), .Names = c("X", 
"A", "B", "C", "D"), class = "data.frame", row.names = c(NA, 
-8L))

IE

 t X  A  B  C  D
1 1  3  6 NA NA 
2 2 NA NA 12 NA 
3 3 10 NA 14 NA 
4 4 NA NA NA NA
5 5  6  8 NA NA
6 6 NA NA NA 11
7 7  5 13  9  7
8 8 NA NA NA NA

我想要矢量图

count
0
1
2
1
1
0
0
0

(如果第一个和最后一个条目是NA' 很好)。我试图模仿COUNTIFSExcel 中的一个函数,即COUNTIFS(B2:F2,"",B3:F3,"",B4:F4,"")第 3 行。

4

5 回答 5

3

这应该会产生预期的结果 -

y = is.na(yourDataFrame)

rowSums(y & rbind(rep(F,5), y[-nrow(yourDataFrame),]) & rbind(y[-1,], rep(F,5)))
于 2013-04-09T05:57:04.330 回答
2

我想我明白你的意思。

假设数据帧被调用x

首先,对于 中的每个 ( row, column) x,我们需要查看NA该单元格中是否有一个,并且对于之前的行和之后的NA行在同一列中是否有一个。nm

首先,让我们在单行的情况下执行此操作,例如行i = 2。我们也有n = 1m = 1(来自问题中的示例)。

i <- 2
n <- 1
m <- 1

让我们计算每列中包含的行的 NA 数i - ni + m如果当前值为 NA,则is.na返回,给出列总和)TRUEcolSums

y <- colSums(is.na(x[(i - n):(i + m), ]))
# X A B C D 
# 0 1 2 1 3 

现在如果我们计算 3 秒,我们只有NA在上一行、当前行和下一行中都有一个NA(即这里只有 D 列符合条件):

y == n + m + 1
#     X     A     B     C     D 
# FALSE FALSE FALSE FALSE  TRUE

所以满足我们标准的列i(因此是输出的第 th 个元素)是:

sum(y == n + m + 1)
# 1 

然后我们可以将sapply其应用于每一行:

countifs <- function (df, n, m) {
    sapply(1:nrow(df),
           function (i) {
               nrows <- nrow(df)
               startRow <- max(i - n, 1)
               endRow   <- min(i + m, nrows)
               y <- colSums(is.na(x[startRow:endRow, ]))
               sum(y == n + m + 1)
           })
}

countifs(x, 1, 1)
# [1] 0 1 2 1 1 0 0 0

您还提到您可能希望与自定义值进行比较,而不是NA. 在这种情况下is.na(x[...]),您可以只做而不是做x[...] == value(但不是 if valueis NA,您在其中使用is.na

sapply此外,您可以通过仅使用on rows n + 1tonrow(df) - m - 1并将第一个n和最后一个m元素自动设置为 0来节省一些工作。

于 2013-04-09T05:55:30.870 回答
2

这是一个函数,它将识别NA运行中心的值length = .length

foo <- function(x,.length){
  x <- is.na(x)
  if( .length < 2L ||.length %%2L == 0L ){stop('.length must be an odd number greater than 2')}
  lx <- length(x)
  if(lx <.length) {return(rep_len(FALSE, lx))}
  midpoints <- seq.int(2L, lx-1L, by = 1L)
  c(FALSE,sapply(midpoints, function(xx) all(x[(xx-1L):(xx+1L)])),FALSE)
}

我们可以将它与 rowSums 一起使用并sapply得到你想要的。

rowSums(sapply(xx, foo, .length = 3))
## [1] 0 1 2 1 1 0 0 0

无需重新发明轮子(滚动的东西)

或者你可以rollapplyzoo包中使用

library(zoo)
rowSums(sapply(xx, function(x) {
    rollapply(is.na(x), width = 3, fill = FALSE, FUN = all)
   }))

甚至只是

rowSums(rollapply(is.na(xx),width=3, FUN=all, fill = FALSE))
于 2013-04-09T06:00:40.437 回答
1

您可以使用describejust 来获取每列中的 NA 数量。

describe(traindata)

输出如下所示:

Column_3 
      n missing  unique    Mean     .05     .10     .25     .50     .75     .90     .95 
    646      23     283  0.2792  0.0000  0.0000  0.0000  0.1455  0.4798  0.9305  1.0000 

检查missing值。

于 2013-04-09T05:30:21.630 回答
1

我想不出一个矢量化的版本,所以这里是一个使用一个很好的旧 for 循环的版本:

x <- structure(list(X = 1:8, A = c(3L, NA, 10L, NA, 6L, NA, 5L, NA
), B = c(6L, NA, NA, NA, 8L, NA, 13L, NA), C = c(NA, 12L, 14L,  
NA, NA, NA, 9L, NA), D = c(NA, NA, NA, NA, NA, 11L, 7L, NA)), .Names = c("X", 
"A", "B", "C", "D"), class = "data.frame", row.names = c(NA, 
-8L))

y <- x
y[is.na(y)] <- -99
out <- vector("numeric", nrow(y))

n <- 1
m <- 1
for (c in (1+n):(nrow(y)-m)) {
    out[c] <- sum((y[(c-n),] == -99) & (y[(c),] == -99) & (y[(c+m),] == -99))
}
out

这应该可以解决问题(即使允许 n 和 m):

> out
[1] 0 1 2 1 1 0 0 0

请注意,我使用了两个技巧。由于使用NAs 是有问题的,因此我将它们交换-99(尽管这不是完全必要的)。然后我不会遍历前 n 行和最后 m 行。

如果有人提出矢量化版本,他/她肯定会得到我的支持。

于 2013-04-09T05:51:32.180 回答