删除某些列中所有 NA 的行
Remove rows which have all NAs in certain columns
假设您有一个包含 9 列的数据框。您想要删除列 5:9 中所有 NA 的个案。如果 1:4.
列中有 NA,则完全不相关
到目前为止,我已经找到了允许您删除在 5:9 列的 any 中具有 NA 的行的函数,但我特别需要仅删除那些在 5:9.
列中有 all 个 NA
我编写了自己的函数来执行此操作,但由于我有 300k+ 行,所以速度非常慢。我想知道有没有更有效的方法?这是我的代码:
remove.select.na<-function(x, cols){
nrm<-vector("numeric")
for (i in 1:nrow(x)){
if (sum(is.na(x[i,cols]))<length(cols)){
nrm<-c(nrm,i)
}
#Console output to track the progress
cat('\r',paste0('Checking row ',i,' of ',nrow(x),' (', format(round(i/nrow(x)*100,2), nsmall = 2),'%).'))
flush.console()
}
x<-x[nrm,]
rm(nrm)
return(x)
}
其中 x 是数据框,cols 是一个向量,其中包含应检查 NA 的列的名称。
lines=
'V1 V2 V3 V4
A 10 20 NA
B NA NA NA
C 5 20 3
D 15 20 4
E NA 10 5'
df = read.table(textConnection(lines), header = T)
df[is.na(df)] = 'X'
attach(df)
x = subset(df, V2 == 'X' & V3 == 'X' & V4 == 'X')
df_new = df[-as.numeric(row.names(x)),]
df_new
# V1 V2 V3 V4
#1 A 10 20 X
#3 C 5 20 3
#4 D 15 20 4
#5 E X 10 5
detach(df)
我不知道它是否比您的函数快,但也许您可以对数据框的每一行使用 !any
和 is.na
。使用此示例数据:
set.seed(1234)
x = do.call(cbind, lapply(1:9, function(x) runif(10)))
x[sample(length(x), size = 70)] <- NA
x <- data.frame(x)
> x
X1 X2 X3 X4 X5 X6 X7 X8 X9
1 0.11 NA NA 0.46 0.55 0.07 NA NA NA
2 0.62 NA NA NA NA NA 0.04 NA NA
3 NA NA NA 0.30 NA NA NA 0.01 NA
4 0.62 NA 0.04 0.51 NA NA NA NA NA
5 0.86 NA NA 0.18 NA NA NA NA 0.2
6 0.64 NA NA NA NA 0.50 NA 0.52 NA
7 NA NA NA NA 0.68 NA NA NA NA
8 NA NA NA NA NA NA NA NA NA
9 NA NA NA NA NA 0.17 NA NA NA
10 NA NA 0.05 NA NA NA NA NA NA
看起来应该删除第 4、8 和 10 行。因此,您可以使用 apply
遍历每一行以查看是否满足条件 - 任何在第 5 至第 9 列中具有除 NA
以外的任何值的行将 return TRUE
,因此您可以将其用作数据框的索引器。
keep.rows <- apply(x[, 5:9], 1, FUN = function(row){
any(!is.na(row))
})
> x[keep.rows, ]
X1 X2 X3 X4 X5 X6 X7 X8 X9
1 0.11 NA NA 0.46 0.55 0.07 NA NA NA
2 0.62 NA NA NA NA NA 0.04 NA NA
3 NA NA NA 0.30 NA NA NA 0.01 NA
5 0.86 NA NA 0.18 NA NA NA NA 0.2
6 0.64 NA NA NA NA 0.50 NA 0.52 NA
7 NA NA NA NA 0.68 NA NA NA NA
9 NA NA NA NA NA 0.17 NA NA NA
同样,不确定它是否比您的函数快,但是...也许吧?
这是一行代码,用于删除 5 到 9 之间所有列中带有 NA 的行。通过组合 rowSums()
和 is.na()
可以很容易地检查这 5 列中的所有条目是否都是NA
:
x <- x[rowSums(is.na(x[,5:9]))!=5,]
这里有两个dplyr
选项:
library(dplyr)
df <- data_frame(a = c(0, NA, 0, 4, NA, 0, 6), b = c(1, NA, 0, 4, NA, 0, NA), c = c(1, 0, 1, NA, NA, 0, NA))
# columns b and c would be the columns you don't want all NAs
df %>%
filter_at(vars(b, c), any_vars(!is.na(.)))
df %>%
filter_at(vars(b, c), any_vars(complete.cases(.)))
# A tibble: 5 x 3
a b c
<dbl> <dbl> <dbl>
1 0 1 1
2 NA NA 6
3 0 6 1
4 4 4 NA
5 0 0 0
您可以使用 all
和 apply
来查找所有值为 NA
:
的行
x[!apply(is.na(x[,5:9]), 1, all),]
或否定 is.na
并测试 any
:
x[apply(!is.na(x[,5:9]), 1, any),]
或在不需要计算所选行数的情况下使用 rowSums
,例如 :
x[rowSums(!is.na(x[,5:9])) > 0,]
假设您有一个包含 9 列的数据框。您想要删除列 5:9 中所有 NA 的个案。如果 1:4.
列中有 NA,则完全不相关到目前为止,我已经找到了允许您删除在 5:9 列的 any 中具有 NA 的行的函数,但我特别需要仅删除那些在 5:9.
列中有 all 个 NA我编写了自己的函数来执行此操作,但由于我有 300k+ 行,所以速度非常慢。我想知道有没有更有效的方法?这是我的代码:
remove.select.na<-function(x, cols){
nrm<-vector("numeric")
for (i in 1:nrow(x)){
if (sum(is.na(x[i,cols]))<length(cols)){
nrm<-c(nrm,i)
}
#Console output to track the progress
cat('\r',paste0('Checking row ',i,' of ',nrow(x),' (', format(round(i/nrow(x)*100,2), nsmall = 2),'%).'))
flush.console()
}
x<-x[nrm,]
rm(nrm)
return(x)
}
其中 x 是数据框,cols 是一个向量,其中包含应检查 NA 的列的名称。
lines=
'V1 V2 V3 V4
A 10 20 NA
B NA NA NA
C 5 20 3
D 15 20 4
E NA 10 5'
df = read.table(textConnection(lines), header = T)
df[is.na(df)] = 'X'
attach(df)
x = subset(df, V2 == 'X' & V3 == 'X' & V4 == 'X')
df_new = df[-as.numeric(row.names(x)),]
df_new
# V1 V2 V3 V4
#1 A 10 20 X
#3 C 5 20 3
#4 D 15 20 4
#5 E X 10 5
detach(df)
我不知道它是否比您的函数快,但也许您可以对数据框的每一行使用 !any
和 is.na
。使用此示例数据:
set.seed(1234)
x = do.call(cbind, lapply(1:9, function(x) runif(10)))
x[sample(length(x), size = 70)] <- NA
x <- data.frame(x)
> x
X1 X2 X3 X4 X5 X6 X7 X8 X9
1 0.11 NA NA 0.46 0.55 0.07 NA NA NA
2 0.62 NA NA NA NA NA 0.04 NA NA
3 NA NA NA 0.30 NA NA NA 0.01 NA
4 0.62 NA 0.04 0.51 NA NA NA NA NA
5 0.86 NA NA 0.18 NA NA NA NA 0.2
6 0.64 NA NA NA NA 0.50 NA 0.52 NA
7 NA NA NA NA 0.68 NA NA NA NA
8 NA NA NA NA NA NA NA NA NA
9 NA NA NA NA NA 0.17 NA NA NA
10 NA NA 0.05 NA NA NA NA NA NA
看起来应该删除第 4、8 和 10 行。因此,您可以使用 apply
遍历每一行以查看是否满足条件 - 任何在第 5 至第 9 列中具有除 NA
以外的任何值的行将 return TRUE
,因此您可以将其用作数据框的索引器。
keep.rows <- apply(x[, 5:9], 1, FUN = function(row){
any(!is.na(row))
})
> x[keep.rows, ]
X1 X2 X3 X4 X5 X6 X7 X8 X9
1 0.11 NA NA 0.46 0.55 0.07 NA NA NA
2 0.62 NA NA NA NA NA 0.04 NA NA
3 NA NA NA 0.30 NA NA NA 0.01 NA
5 0.86 NA NA 0.18 NA NA NA NA 0.2
6 0.64 NA NA NA NA 0.50 NA 0.52 NA
7 NA NA NA NA 0.68 NA NA NA NA
9 NA NA NA NA NA 0.17 NA NA NA
同样,不确定它是否比您的函数快,但是...也许吧?
这是一行代码,用于删除 5 到 9 之间所有列中带有 NA 的行。通过组合 rowSums()
和 is.na()
可以很容易地检查这 5 列中的所有条目是否都是NA
:
x <- x[rowSums(is.na(x[,5:9]))!=5,]
这里有两个dplyr
选项:
library(dplyr)
df <- data_frame(a = c(0, NA, 0, 4, NA, 0, 6), b = c(1, NA, 0, 4, NA, 0, NA), c = c(1, 0, 1, NA, NA, 0, NA))
# columns b and c would be the columns you don't want all NAs
df %>%
filter_at(vars(b, c), any_vars(!is.na(.)))
df %>%
filter_at(vars(b, c), any_vars(complete.cases(.)))
# A tibble: 5 x 3
a b c
<dbl> <dbl> <dbl>
1 0 1 1
2 NA NA 6
3 0 6 1
4 4 4 NA
5 0 0 0
您可以使用 all
和 apply
来查找所有值为 NA
:
x[!apply(is.na(x[,5:9]), 1, all),]
或否定 is.na
并测试 any
:
x[apply(!is.na(x[,5:9]), 1, any),]
或在不需要计算所选行数的情况下使用 rowSums
,例如
x[rowSums(!is.na(x[,5:9])) > 0,]