从R

时间:2017-07-25 14:21:55

标签: r dataframe

我正在参加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

任何人都知道我会这样做吗?

由于

5 个答案:

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