R引用多个数据帧列以排除数据

时间:2015-06-23 20:40:50

标签: r dataframe

我正在使用一个大型数据框,我需要从中排除包含除少数字符之外的所有字符。

目前我正在使用以下代码这样做并且它工作正常,但我似乎只能一次将它应用于单个列,这不仅效率低,而且耗费时间,因为我有很多列通过工作。

df <- df[(df$column_name_01 %in% c("a", "b", "c", "d")),]

到目前为止,我已经尝试过像这样引用多个列(因为这种方法适用于单个列):

df <- df[(df[, 1:10] %in% c("a", "b", "c", "d")),]

但这显然不符合预期。是否有一种简洁的方法可以从包含某些字符的数据框中排除行(或者哪种方式与某些字符不匹配)?

2 个答案:

答案 0 :(得分:0)

您可以计算是否希望10列中的每一行合并为Reduce"&"的单个向量:

df[Reduce("&", lapply(df[,1:10], function(x) x %in% c("a", "b", "c", "d"))),]
#    NA NA NA NA NA NA NA NA NA NA
# 14  a  c  a  d  d  c  d  c  c  c
# 25  b  a  a  a  b  a  c  a  a  c
# 29  d  d  d  a  a  a  b  c  c  a
# 31  c  b  b  d  b  c  a  b  b  c
# 33  b  a  c  b  a  d  c  a  a  c
# 36  c  d  c  b  d  a  c  a  a  a
# 42  b  b  a  a  b  c  d  b  d  d
# 45  c  c  b  b  d  a  b  a  d  b

您也可以通过将数据框转换为矩阵并使用rowSums来确保行中的所有值都落在所需的集合中来执行此操作:

df[rowSums(matrix(unlist(df[,1:10]) %in% c("a", "b", "c", "d"), nrow(df))) == 10,]
#    NA NA NA NA NA NA NA NA NA NA
# 14  a  c  a  d  d  c  d  c  c  c
# 25  b  a  a  a  b  a  c  a  a  c
# 29  d  d  d  a  a  a  b  c  c  a
# 31  c  b  b  d  b  c  a  b  b  c
# 33  b  a  c  b  a  d  c  a  a  c
# 36  c  d  c  b  d  a  c  a  a  a
# 42  b  b  a  a  b  c  d  b  d  d
# 45  c  c  b  b  d  a  b  a  d  b

这两个解决方案都应该比基于apply的大型矩阵解决方案更快(我在这里对100k行数据帧进行基准测试)因为它们在少量列而不是大量行上运行,更好地利用矢量化:

josilber.lapply <- function(df) df[Reduce("&", lapply(df[,1:10], function(x) x %in% c("a", "b", "c", "d"))),]
josilber.rowSums <- function(df) df[rowSums(matrix(unlist(df[,1:10]) %in% c("a", "b", "c", "d"), nrow(df))) == 10,]
crimson.apply <- function(df) df[apply(df[,1:10], 1, function(x) all(x %in% c("a", "b", "c", "d"))),]
library(microbenchmark)
microbenchmark(josilber.lapply(big.df), josilber.rowSums(big.df), crimson.apply(big.df))
# Unit: milliseconds
#                      expr       min       lq      mean    median        uq       max neval
#   josilber.lapply(big.df)  67.17092  71.0628  83.36787  74.74011  86.00722  231.6794   100
#  josilber.rowSums(big.df)  98.75142 116.3975 136.28880 128.28851 149.55155  301.9346   100
#     crimson.apply(big.df) 676.66290 725.6616 789.45954 762.74171 805.72437 2681.8203   100

数据:

set.seed(144)
df <- unname(do.call(data.frame, replicate(10, sample(letters[1:5], 50, replace=TRUE), simplify=FALSE)))
set.seed(144)
big.df <- unname(do.call(data.frame, replicate(10, sample(letters[1:5], 100000, replace=TRUE), simplify=FALSE)))

答案 1 :(得分:0)

我想你想在这里定期申请:

df[apply(df[,1:10], 1, function(x) all(x %in% c("a", "b", "c", "d"))),]

或不匹配的行

df[apply(df[,1:10], 1, function(x) all(! x %in% c("a", "b", "c", "d"))),]