【问题标题】:Keeping specific column data while aggregating and summing other columns在聚合和汇总其他列时保留特定列数据
【发布时间】:2015-08-31 13:35:32
【问题描述】:

我是 R 新手,正在使用一家中型零售店的交易数据进行练习。我想创建一个数据框,其中包含每个客户在不同类别产品中的购买百分比,以及他们的总购买量。通过这种方式,我们可以向在特定类别中具有明显偏好的人发送营销电子邮件,但排除购买次数少于五次的人。

示例数据(除了现实中的近 100 个类别和大约 250,000 行):

+-------------+-------------+--------------------+------+------+------+
| Transaction | Customer_ID | Email              | Cat1 | Cat2 | Cat3 |
+-------------+-------------+--------------------+------+------+------+
| 55          | 1           | email@address.com  | 1    | 0    | 0    |
| 55          | 1           | email@address.com  | 1    | 0    | 0    |
| 56          | 2           | email2@address.com | 0    | 0    | 2    |
| 57          | 3           | email3@address.com | 3    | 0    | 0    |
+-------------+-------------+--------------------+------+------+------+

第 1 步:按客户 ID 汇总,我使用了以下代码:

segmented <- aggregate(df[4:6], list(Customer_ID=orders$Customer_ID), FUN = sum)    

第 2 步:为了将这些汇总数字转换为百分比,我使用了以下代码:

segmented_percentage <- cbind(id = segmented[, 1], segmented[, -1]/rowSums(segmented[, -1])*100)

但是,我在第 1 步中丢失了电子邮件地址,当我尝试将数据框与以下内容合并时,它从未完成处理(我已经等了几个小时)。

merge(segmented_percentage, df)

简而言之:我如何将这么多部分重新组合在一起以获取具有明显偏好和总购买量的电子邮件?

(非常感谢 Stack Overflow 的所有其他答案。我在上面所做的完全是谷歌搜索的结果,并在这里找到了好的答案。)

【问题讨论】:

    标签: r


    【解决方案1】:

    我们也可以使用Email 作为分组变量,在“segmented”中获取“Email”列,假设特定的“Customer_ID”具有相同的“Email”。

    segmented <- aggregate(.~Customer_ID+Email, df1[-1], FUN=sum)
    

    如果我们想在原始数据集中创建列,请使用 mutate from library(dplyr)

    library(dplyr)
    df2 <- df1 %>% 
             group_by(Customer_ID) %>% 
             mutate_each(funs(sum= sum(., na.rm=TRUE)), starts_with('Cat'))
    

    我们从“Cat”列中获取百分比,并分配输出以用百分比替换列。

    ind <- grep('Cat', names(df2))
    df2[ind] <- df2[ind]/rowSums(df2[ind])*100
    

    或者我们可以使用prop.tablemargin=1

    df2[ind] <-  100*prop.table(as.matrix(df2[ind] ), 1)
    

    我们也可以使用data.table 来做到这一点。我们将“data.frame”转换为“data.table”(setDT(df1)),将我们要更改的列的class更改为numericlapply(.SD, as.numeric))。可以在 .SDcols 中指定要选择的列,我们可以将输出分配 (:=) 回具有数字列索引的列。按“Customer_ID”分组,我们使用lapply 遍历列4:6 并获得sum。我们使用Reduce+lapply 输出进行元素求和(类似于rowSums),将sum 除以Reduce 内的Reduce 输出并分配输出到 4:6 列。

    library(data.table)
     setDT(df1)[, (4:6) := lapply(.SD, as.numeric), .SDcols=4:6][,
       (4:6) := {tmp <- lapply(.SD, sum, na.rm=TRUE)
                 Map(f1, tmp, Reduce(`+`, tmp))}, by = Customer_ID, .SDcols=4:6]
    

    数据

    df1 <- structure(list(Transaction = c(55L, 55L, 56L, 57L), 
    Customer_ID = c(1L, 
    1L, 2L, 3L), Email = c("email@address.com", "email@address.com", 
    "email2@address.com", "email3@address.com"), Cat1 = c(1L, 1L, 
    0L, 3L), Cat2 = c(0L, 0L, 0L, 0L), Cat3 = c(0L, 0L, 2L, 0L)),
    .Names = c("Transaction", 
    "Customer_ID", "Email", "Cat1", "Cat2", "Cat3"), 
     class = "data.frame", row.names = c(NA,  -4L))
    

    【讨论】:

    • 感谢您的回答!然而,为了让事情更清楚,我简单地标记了这些列。实际上,它们都有唯一的名称,例如FC、BA、AGE、HP等。有没有办法使用具有唯一列名的出色代码? (我已经成功使用了你的第一行代码——谢谢!)
    • @UMG 如果它们具有唯一名称,则可以使用列索引。例如,这里我们可以使用mutate_each(funs(sum), 4:6)。检查?select。它有多种选择
    • 我担心具有所有唯一列名的 ind 子集始终是一个列表。 ind &lt;- df2[c(4:99)]ind &lt;- as.data.frame(ind) 无济于事,并且在尝试用百分比替换时出现“下标类型无效”的错误。但我敢肯定,如果我的问题中的列名是准确的,那么您的编码会起作用。
    • @UMG 根据示例,df2[4:6] &lt;- df2[4:6]/rowSums(df2[4:6])*100 有效。我的代码中的 ind 只是一个列索引,但您的 ind 是列的子集。
    猜你喜欢
    • 2018-07-23
    • 2016-12-29
    • 1970-01-01
    • 2022-07-21
    • 1970-01-01
    • 2020-12-18
    • 2013-04-05
    • 1970-01-01
    • 2019-03-25
    相关资源
    最近更新 更多