R - 在每行计算“行邻域”中仅包含NA的列数

时间:2013-04-09 05:20:36

标签: r apply

如何从数据框创建一个向量,该向量为每一行提供该行中“NA”(或自定义值)的列数以及上面的 n 行和<下面是em> 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))

 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那就没问题)。我正在尝试模仿Excel中的COUNTIFS函数,即第3行COUNTIFS(B2:F2,"",B3:F3,"",B4:F4,"")

5 个答案:

答案 0 :(得分:3)

这应该产生预期的结果 -

y = is.na(yourDataFrame)

rowSums(y & rbind(rep(F,5), y[-nrow(yourDataFrame),]) & rbind(y[-1,], rep(F,5)))

答案 1 :(得分:2)

我想我明白你的意思。

假设数据框名为x

首先,对于row中的每个(columx n),我们需要查看该单元格中是否有NA和{{1}在{em>同一列之前的NA行和n行之后。

首先,让我们在单行的情况下这样做,行m说。 我们还有i = 2n = 1(来自问题中的示例)。

m = 1

如果当前值为NA i <- 2 n <- 1 m <- 1 ,我们会计算行i - ni + m的每列中的NAs数量(is.na返回TRUE给出列总和)

colSums

如果我们计算3 y <- colSums(is.na(x[(i - n):(i + m), ])) # X A B C D # 0 1 2 1 3 s(即此处只有D列符合条件),我们在前一行,当前行和下一行中只有一个NA

NA

所以符合我们标准的列的数字(因此是输出的y == n + m + 1 # X A B C D # FALSE FALSE FALSE FALSE TRUE 元素)是:

i

然后我们可以使用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[...] == valuevalue NA,而您使用is.na

此外,您只需使用行sapplyn + 1上的nrow(df) - m - 1并设置第一个n和最后m个元素,即可节省一些工作量自动为0。

答案 2 :(得分: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

没有重新发明轮子(滚动的东西)

或者您可以使用rollapply

中的zoo
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))

答案 3 :(得分:1)

您可以使用describe来获取每列中的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值。

答案 4 :(得分: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

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

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