4

设置

我有一个列表矩阵,其中一个“列”是一个列表(我意识到这是一个奇怪的数据集,但我发现它对其他操作很有用)。列表的每个条目都是;(1) 空 (integer(0)),(2) 整数,或 (3) 整数向量。

例如,R 对象“df”,df$ID 是索引向量,df$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”是否包含某些值来创建一个新数据集,它是初始数据集的子集。例如,df 中所有行的子集,使得 Bask_list 具有“123”或“123”和“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)
4

3 回答 3

7

您可以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时间。

于 2013-04-28T21:01:56.800 回答
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

如果您只想要包含Basketvalue 的行的第一个实例,您可以随后将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
于 2013-04-28T21:58:02.947 回答
1

使用 purrr & dplyr 库(和 magrittr 管道运算符)的更易读的解决方案是:

library(dplyr)
library(purrr)    

d.f %>% filter(map_lgl(Basket_List,contains,as.integer(123)))
于 2017-05-30T07:14:18.527 回答