R数据帧的高效过滤(用户定义的不同过滤器)
我希望在R中过滤一个数据框,original.data。这个数据框可以有大约100-200万个观察值。dataframe有几个字段,名称可能会有所不同。用户可以选择要根据哪些字段进行筛选。这些字段名存储在名称(all.filters)中,其中all.filters是可变长度的列表。然后,用户可以选择名称(all.filters)中每个字段的级别。例如,此列表可能类似于:R数据帧的高效过滤(用户定义的不同过滤器),r,filtering,performance,R,Filtering,Performance,我希望在R中过滤一个数据框,original.data。这个数据框可以有大约100-200万个观察值。dataframe有几个字段,名称可能会有所不同。用户可以选择要根据哪些字段进行筛选。这些字段名存储在名称(all.filters)中,其中all.filters是可变长度的列表。然后,用户可以选择名称(all.filters)中每个字段的级别。例如,此列表可能类似于: > all.filters $Period [1] "2010-12-31" "2011-03-31" "2011-06
> all.filters
$Period
[1] "2010-12-31" "2011-03-31" "2011-06-30" "2011-09-30" "2011-12-31"
[6] "2012-03-31" "2012-06-30" "2012-09-30"
$Size
[1] "L" "VL"
$Number
[1] "11" "21" "35" "42" "45" "47" "49" "52" "57"
我使用以下代码应用所选的过滤器:
attach(original.data)
filter.names <- names(all.filters)
flag <- 1
for(filter in filter.names){
flag <- flag*(is.element(get(filter),all.filters[[filter]]))
}
filtered.data <- original.data[flag==1,]
附加(原始数据)
filter.names看起来您想要的是与任何筛选器选项匹配的数据?比如说,不管时间长短,是“L”还是“VL”
在这种情况下,我只想:
Filtered.Data <- subset(original.data, Period %in% all.filters$Period |
Size %in% all.filters$Size | Number %in% all.filters$Number)
Filtered.Data一种稍微通用的方法,它不依赖于对字段名称进行硬编码:假设您的Data.frame
和您的过滤器具有相同顺序的相同列/字段:
foo <- data.frame(Period=sample(x=c("2010-12-31","2011-01-01"),size=100,replace=TRUE),
Size=sample(x=c("S","L","VL"),size=100,replace=TRUE),
Number=sample(x=c("9","11","21"),size=100,replace=TRUE))
all.filters <- list(
Period=c("2010-12-31","2011-03-31"),
Size=c("L","VL"),
Number=c("11","21","35"))
最后,我们提取所有过滤器匹配的foo
行:
foo[apply(bar,1,all),]
您可以使用带有适当设置键的data.table
。这将节省内存
然后,您可以将过滤器的列表
传递给[.data.table
.period <- seq(from = as.Date("2010/1/1", "%Y/%m/%d"), to = as.Date("2012/1/1",
"%Y/%m/%d"), by = "3 months")
.size <- c("XS", "S", "M", "L", "XL")
.number <- as.character(1:100)
DF <- expand.grid(Period = .period, Size = .size, Number = .number, stringsAsFactors = F)
DF$other <- rnorm(nrow(DF))
library(data.table)
DT <- as.data.table(DF)
DT[, `:=`(Period, as.IDate(.period))]
## Period Size Number other
## 1: 2010-01-01 XS 1 0.17947
## 2: 2010-04-01 XS 1 1.43252
## 3: 2010-07-01 XS 1 -0.97142
## 4: 2010-10-01 XS 1 -0.98021
## 5: 2011-01-01 XS 1 -0.62964
## ---
## 4496: 2011-01-01 XL 100 0.65831
## 4497: 2011-04-01 XL 100 -0.45277
## 4498: 2011-07-01 XL 100 -0.14236
## 4499: 2011-10-01 XL 100 -0.02376
## 4500: 2012-01-01 XL 100 -0.11525
all_filters <- list(Period = as.IDate(as.Date("2010/1/1", format = "%Y/%m/%d")),
Size = "L", Number = c("11", "21", "35", "42", "45", "47", "49", "52", "57"))
setkeyv(DT, names(all_filters))
DT[all_filters]
## Period Size Number other
## 1: 2010-01-01 L 11 1.4122
## 2: 2010-01-01 L 21 -0.4923
## 3: 2010-01-01 L 35 1.1262
## 4: 2010-01-01 L 42 1.3527
## 5: 2010-01-01 L 45 -0.3758
## 6: 2010-01-01 L 47 -0.1847
## 7: 2010-01-01 L 49 -0.8503
## 8: 2010-01-01 L 52 -1.0645
## 9: 2010-01-01 L 57 -0.6092
你也可以这样做
setkeyv(DT, names(all_filters))
DT[do.call(CJ,all_filters)]
干杯,这里的%in%运算符很有用。但是,您可能会注意到,在我的代码中,我没有直接提到句点、大小和数字。这是因为all.filter是由另一个用户定义的。在他们更新过滤器后,代码应该自动应用它们,也就是说,无需显式键入变量的名称。我可以执行以下操作:以下内容:粘贴(“子集(原始.data)”,获取(过滤器),%in%all.filters[[filter]]),sep=“”)然而,我仍然需要做一个循环来应用每个可变数量的过滤器,然后找到结果数据集的交集。干得好!我需要做的唯一更改是:filtered.data+1-你提到的假设不是一个:只要做foo@flodel:如果我错了,请纠正我,但是rowSums(bar)>0
将选择至少一个筛选器命中的行,而不是所有筛选器(相当于任何
),对吗?我现在已经很晚了……但无论如何,谢谢你的支持!你是对的,我编辑了我的评论。我还想说,rowSums
将比apply
@flodel:对我担心的警告做了很好的补充,+1感谢你的帮助。起初我认为这是完美的-高效的和优雅的-然而,存在一个问题。在列表所有\u过滤器
中,期间
和大小
都有一个级别。当所有\u过滤器的两个或多个元素都有多个级别时(例如,如果所有\u过滤器
与上面相同,除了大小=c(“L”,“XL”)
),此代码不起作用。这种过滤方法速度非常快,所以我将尝试解决这个问题。希望我能解决如何在没有循环的情况下进行过滤。谢谢。我假设有某种方法可以获得交叉连接而不是相等连接(这是正确的术语吗?)。这很有效!
all_filters <- list(Period = as.IDate(as.Date("2010/1/1", format = "%Y/%m/%d")),
Size = c("L",'XL'), Number = c("11", "21", "35", "42", "45", "47", "49", "52", "57"))
cj_filter <- do.call(CJ, all_filters)
# note you could avoid this `do.call` line by
# cj_filter <- CJ(Period = as.IDate(as.Date("2010/1/1", format = "%Y/%m/%d")),
Size = c("L",'XL'), Number = c("11", "21", "35", "42", "45", "47", "49", "52", "57"))
setkeyv(DT, names(cj_filter))
DT[cj_filter]
Period Size Number other
1: 2010-01-01 L 11 0.36289104
2: 2010-01-01 L 21 1.26356767
3: 2010-01-01 L 35 -0.18629723
4: 2010-01-01 L 42 0.92267902
5: 2010-01-01 L 45 1.68796072
6: 2010-01-01 L 47 1.75107447
7: 2010-01-01 L 49 0.24048407
8: 2010-01-01 L 52 0.06675221
9: 2010-01-01 L 57 0.49665392
10: 2010-01-01 XL 11 0.33682495
11: 2010-01-01 XL 21 0.67642271
12: 2010-01-01 XL 35 -0.16412768
13: 2010-01-01 XL 42 0.72863394
14: 2010-01-01 XL 45 -0.55527588
15: 2010-01-01 XL 47 1.30850591
16: 2010-01-01 XL 49 1.08688166
17: 2010-01-01 XL 52 -0.31157250
18: 2010-01-01 XL 57 0.43626422
setkeyv(DT, names(all_filters))
DT[do.call(CJ,all_filters)]