我正在参加Kaggle Instacart比赛,但我对R来说很陌生并遇到了一些我无法弄清楚的事情。
我有一个包含4列的数据集。第一列是订单ID(id1)。第二列是产品ID(id2)。第三列是我想从订单id1中选择产品id2的概率,我们可以将其视为排名,因此总是在较小的概率上选择更高的概率。最后,第四列是我想从给定订单中选择的产品数量(订单的一个特征)。例如,我在这里有数据帧df的前12行:
id1 id2 prob num
1 17 13107 0.4756982 3
2 17 21463 0.3724126 3
3 17 38777 0.3534422 3
4 17 21709 0.3364623 3
5 17 47766 0.3364623 3
6 17 39275 0.3165896 3
7 34 16083 0.4093785 4
8 34 39475 0.3892882 4
9 34 47766 0.3892882 4
10 34 2596 0.3837562 4
11 34 21137 0.3762758 4
12 34 47792 0.3737032 4
我们可以看到,从id1 = 17我想选择3个元素,而对于id1 = 34,我想选择4个元素。结果应该是
ID1 ID2
17 13107, 21463, 38777
34 16083, 39475, 47766, 2596
或类似的东西。
目前我尝试使用
df %>% group_by(id1) %>% top_n(n = num)
但我收到了错误
Selecting by num
Error in is_scalar_integerish(n) : object 'num' not found
任何人都知道我会这样做吗?
由于
答案 0 :(得分:4)
您可以将分组数据直接导入summarise
语句:
df %>% group_by(id1) %>% summarise(id2 = toString(id2[seq_len(first(num))]))
## A tibble: 2 x 2
# id1 id2
# <int> <chr>
#1 17 13107, 21463, 38777
#2 34 16083, 39475, 47766, 2596
在此声明中,id2[seq_len(first(num))]
用于提取每个组的第一个num
,创建从1到num
的序列,该序列用于对第一个X {进行子集化{1}}值。
id2
为每个id1组创建一个字符串。
这是使用toString
的另一个基本R选项:
aggregate
请注意,我假设数据已按顺序排列(如示例中所示)。
答案 1 :(得分:2)
在基础R中,您可以在ID为Map
的数据框列表中使用split
,以应用head
为每个ID选择相应的行数。通过向感兴趣的列提供tapply
并使用head
选择第一个值来提供所选行的数量。使用带有do.call
的{{1}}返回包含相应行的data.frame。
rbind
返回第一个dat $ num元素的命名列表比较简单,然后列表中的名称对应于id1。
do.call(rbind, Map(head, split(dat, dat$id1), tapply(dat$num, dat$id1, head, 1)))
id1 id2 prob num
17.1 17 13107 0.4756982 3
17.2 17 21463 0.3724126 3
17.3 17 38777 0.3534422 3
34.7 34 16083 0.4093785 4
34.8 34 39475 0.3892882 4
34.9 34 47766 0.3892882 4
34.10 34 2596 0.3837562 4
数据强>
Map(head, split(dat$id2, dat$id1), tapply(dat$num, dat$id1, head, 1))
$`17`
[1] 13107 21463 38777
$`34`
[1] 16083 39475 47766 2596
答案 2 :(得分:2)
每个ID有一行可能看起来不错,但列表列通常最终会让人感到痛苦;它不是“整洁”。这是一个简单的dplyr
管道,它坚持使用有意义的动词:按组分隔,过滤行,重新组合在一起。
df %>%
group_by(id1) %>%
filter(seq_along(num) <= num) %>%
ungroup() %>%
select(id1, id2)
# A tibble: 7 x 2
id1 id2
<int> <int>
1 17 13107
2 17 21463
3 17 38777
4 34 16083
5 34 39475
6 34 47766
7 34 2596
答案 3 :(得分:0)
您可以使用@ lmo的数据
来尝试dat%>%group_by(id1)%>%arrange(-prob)%>%dplyr::summarise(ID2=paste(id2[1:unique(num)],collapse=","))
答案 4 :(得分:0)
使用data.table
:
library(data.table)
setDT(df)[order(-prob), .(id2 = toString(head(id2, first(num)))), by = id1]
id1 id2 1: 17 13107, 21463, 38777 2: 34 16083, 39475, 47766, 2596
此处,df
被强制转换为data.table
,按降低概率排序。对于id1
中的每个组,挑选num
最顶层的值并将其聚合为一个字符串。
这会将id2
作为字符返回。如果需要继续处理,将id2
值分隔在列表中可能很有用:
setDT(df)[order(-prob), .(id2 = list(head(id2, first(num)))), by = id1]
df <- fread(
"rn id1 id2 prob num
1 17 13107 0.4756982 3
2 17 21463 0.3724126 3
3 17 38777 0.3534422 3
4 17 21709 0.3364623 3
5 17 47766 0.3364623 3
6 17 39275 0.3165896 3
7 34 16083 0.4093785 4
8 34 39475 0.3892882 4
9 34 47766 0.3892882 4
10 34 2596 0.3837562 4
11 34 21137 0.3762758 4
12 34 47792 0.3737032 4")