基于“列”列表的内容子集数据帧

时间:2013-04-28 20:53:41

标签: r list object dataframe subset

建立

我有一个列表矩阵,其中一个“列”是一个列表(我意识到它是一个奇数数据集,但我发现它对其他操作很有用)。列表的每个条目都是; (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

我的问题

第1期

我想根据“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

第2期

我的另一个问题是,我将在数百万行(它的交易数据)上运行此操作,所以我想尽可能地优化速度(我现在有一个复杂的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)

3 个答案:

答案 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)))