我有一个data.frame,可以包含N列(N在运行时定义),我想得到数据帧中满足N-1条件的行,换句话说我想只得到行前N-1列的特定值。
例如,如果我有一个包含四列(A,B,C,D)和五行的数据框:
A B C D
1 2 3 4
9 9 9 9
1 2 9 5
4 3 2 1
1 2 3 8
我会得到A == 1&的所有行B == 2& C == 3,即:
A B C D
1 2 3 4
1 2 3 8
但如上所述,数据框可以由任意数量的行和列组成(在运行时定义),条件的值可能会发生变化。
我实现了这个功能(简化):
getRows<-function(dataFrame, values) {
conditions=rep(TRUE, dim(dataFrame)[1])
for (k in 1:length(values)) {
conditions=conditions&(dataFrame[,k]==values[k])
}
return(dataFrame[conditions,])
}
当然,这假设值向量中的值是根据数据帧的列顺序排序的,并且向量的长度是N-1。
该函数有效,但我觉得创建布尔矢量,以这种方式评估布尔表达式等等并不是很有效...特别是如果数据帧包含许多数据。
我找到的另一个解决方案是:
getRows<-function(dataFrame, values) {
tmp=dataFrame
for (k in 1:length(values)) {
tmp=tmp[tmp[,k]==values[k],]
}
return(tmp)
}
基本上,这会通过过滤掉不满足每个条件的所有行来“减少”数据帧。但我认为这甚至是最糟糕的,因为它为每个条件创建了一个新的数据框对象(好吧总是更小,但无论如何......)。
所以我的问题是:有没有办法更有效地做到这一点?
答案 0 :(得分:2)
一种可能性:
# if you are only checking for equalities
f <- function(df, values){
# values must be a list with the columns names of df as names and the conditions
# if you
y <- paste(names(values), unlist(values), sep="==", collapse=" & ")
return(df[eval(parse(text=y), envir=df),])
}
l <- as.vector(1:3, "list")
names(l) <- colnames(df)[-ncol(df)]
f(df, l)
A B C D
1 1 2 3 4
5 1 2 3 8
# you can also use other conditions
f <- function(df, values){
# values must be a list with the columns names of df as names and the conditions
# if you
y <- paste(names(values), unlist(values), collapse=" & ")
return(df[eval(parse(text=y), envir=df),])
}
l <- as.vector(paste0(c("==", "<=", "=="), 1:3), "list")
names(l) <- colnames(df)[-ncol(df)]
f(df, l)
A B C D
1 1 2 3 4
5 1 2 3 8
答案 1 :(得分:1)
有时矩阵比data.frames更快,所以有些东西:
mat <- t(as.matrix(df[-ncol(df)))
boolMat <- (mat==values) # if necessary use match to reorder values to match columns of df
ind <- colSums(boolMat)==nrow(boolMat)
df[ind,]
我们的想法是values
将沿着矩阵的列(数据帧的行)进行回收。 colSums
意味着比apply
更快,因此与apply(boolMat, 2, all)
相比,最后一行应该稍微优化。
最佳解决方案取决于数据的大小和比例;条目是否都是整数;也许你在数据中得到的比例是多少。所以@droopy提到,你需要进行基准测试。我的方法涉及创建数据的副本,因此如果您的数据已经接近内存限制,那么它可能会很困难 - 但也许您可以生成矩阵而不是data.frame格式的数据以保存重复。