我有一个列表矩阵,其中一个“列”是一个列表(我意识到它是一个奇数数据集,但我发现它对其他操作很有用)。列表的每个条目都是; (1)空(整数(0)),(2)整数,或(3)整数向量。
E.g。 R对象“d.f”,d.f $ ID是索引向量,d.f $ Basket_List列表。
ID <- c(1,2,3,4,5,6,7,8,9)
Basket_List <- list(integer(0),c(123,987),c(123,123),456,
c(456,123),456,c(123,987),c(987,123),987)
d.f <- data.frame(ID)
d.f$Basket_List <- Basket_List
我想根据“Basket_List”是否包含某些值来创建一个新数据集,该数据集是初始数据集的子集。例如。 d.f中所有行的子集,使得Bask_list具有“123”或“123”&amp; “987” - 或其他更复杂的条件。
我已尝试过以下各种变体,但无济于事。
d.f2 <- subset(d.f, 123 %in% Basket_List)
d.f2 <- subset(d.f, 123 == any(Basket_List))
d.f2 <- d.f[which(123 %in% d.f$Basket_List,]
# should return the subset, with rows 2,3,5,7 & 8
我的另一个问题是,我将在数百万行(它的交易数据)上运行此操作,所以我想尽可能地优化速度(我现在有一个复杂的for循环,但这需要太多时间)。
如果您认为它可能有用,则数据也可能设置如下:
ID <- c(1,2,2,3,3,4,5,5,6,7,7,8,8,9)
Basket <- c(NA,123,987,123,123,456,456,123,456,123,987,987,123,987)
alt.d.f <- data.frame(ID,Basket)
答案 0 :(得分:6)
您可以使用sapply
:
ID <- c(1,2,3,4,5,6,7,8,9)
Basket_List <- list(integer(0),c(123,987),c(123,123),456,
c(456,123),456,c(123,987),c(987,123),987)
d.f <- data.frame(ID)
sel <- sapply( Basket_List, function(bl,searchItem) {
any(searchItem %in% bl)
}, searchItem=c(123) )
> sel
[1] FALSE TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE
> d.f[sel,,drop=FALSE]
ID
2 2
3 3
5 5
7 7
8 8
请注意您的术语。 data.frame不是矩阵。这是一种列表。
速度方面,sapply
并不是最快的,但选择速度非常快,因为它是矢量化的。如果您需要更快的速度,data.table
时间。
答案 1 :(得分:4)
与@AriB类似的方法是使用any
运算符,apply
跨行,如下所示:
d.f[ apply( d.f , 1 , function(x) any(unlist(x) %in% 123) ) , ]
# ID Basket_List
#2 2 123, 987
#3 3 123, 123
#5 5 456, 123
#7 7 123, 987
#8 8 987, 123
通过第二次设置你的数据,我想它会非常快,因为你可以像这样简单地进行分组:
df[ df$Basket %in% 123 , ]
# ID Basket
#NA NA NA
#2 2 123
#4 3 123
#5 3 123
#8 5 123
#10 7 123
#13 8 123
如果您只想要包含Basket
值的行的第一个实例,则可以随后将match
与唯一ID一起使用,因为match
返回其第一个参数的第一个匹配这是第二个:
df2 <- df[ df$Basket %in% 123 , ]
df2[ match( unique(df2$ID) , df2$ID),]
# ID Basket
#NA NA NA
#2 2 123
#4 3 123
#8 5 123
#10 7 123
#13 8 123
您的数据的第二次设置将远远快于我认为的第一次。事实上,让我们在100万行表上做一个粗略的基准测试:
DF <- data.frame( ID = sample(ID , 1e6 , repl=TRUE) , Basket = sample(Basket , 1e6 , repl = TRUE) )
df<-DF
system.time({
df2 <- df[ df$Basket %in% 123 , ]
df2[ match( unique(df2$ID) , df2$ID),]
})
# user system elapsed
# 0.16 0.00 0.16
nrow(df)
#[1] 1000000
nrow(df2)
#[1] 428187
答案 2 :(得分:1)
使用purrr&amp; amp; amp;更易读的解决方案dplyr库(和magrittr管道运算符)将是:
library(dplyr)
library(purrr)
d.f %>% filter(map_lgl(Basket_List,contains,as.integer(123)))