【问题标题】:R - Sum by Group Name and recalculate columnR - 按组名求和并重新计算列
【发布时间】:2015-04-15 03:49:53
【问题描述】:

我正在使用 R 从 Google Analytics API 获取一些数据。在这个特定场景中,我获得了按性别和年龄组划分的用户的兴趣爱好相关信息。我得到的数据结构类似于:

gender ageGroup interest        sessions
male   18-24    Autos           4
male   18-24    Autos/Luxury    1
male   18-24    Autos/Vans      1
male   25-34    Autos           8
male   25-34    Autos/Luxury    2
male   25-34    Autos/Vans      2
male   25-34    Autos/Compacts  1
...
female 65+      Fashion         20

然而,这种结构的问题是,作为主要兴趣的汽车也包含子类别的会话,如果我在数据透视表中使用这些数据,我会得到错误的信息。

因此,我将子类别“通才”添加到每个主要类别中作为其自己的子类别,并将此列一分为二:

for (i2 in 1:nrow(ga.genderAgeAffinityTable) ) {

# main categories <- chrFound = integer(0)            
chrFound <- grep("[/]", ga.genderAgeAffinityTable$interest[i2] )

if (length(chrFound) < 1) {
ga.genderAgeAffinityTable$interest[i2] <- 
sprintf("%s/Generalists", ga.genderAgeAffinityTable$interest[i2])
}

ga.genderAgeAffinityTable <- as.data.frame
(cSplit(ga.genderAgeAffinityTable, "interest", sep = "/"))

}

View(ga.genderAgeAffinityTable)

            gender ageGroup interest        subcategory        sessions
            male   18-24    Autos           Generalists        4
            male   18-24    Autos           Luxury             1
            male   18-24    Autos           Vans               1
            male   25-34    Autos           Generalists        8
            male   25-34    Autos           Luxury             2
            male   25-34    Autos           Vans               2
            male   25-34    Autos           Compacts           1
            ...
            female 65+      Fashion         Generalists        20

我仍然必须摆脱错误的会话计算,至于第一组(男性,18-24 岁,汽车爱好者),通才应该只有 2 个会话(会话 - 总和(其他子类别))。我正在使用 auxId (genderAgeInterestSubcategory) 执行此操作,按该 auxId 汇总所有会话,将聚合的会话合并为我的数据框中的新列并重新计算子类别“通才”的会话:

ga.genderAgeAffinityTable$auxId <- sprintf("%s%s%s",
ga.genderAgeAffinityTable$gender, ga.genderAgeAffinityTable$age,
ga.genderAgeAffinityTable$interest_1 )

ga.interestAggregated <- aggregate(ga.genderAgeAffinityTable[,c("sessions")],
by=list(ga.genderAgeAffinityTable$auxId), "sum")

colnames(ga.interestAggregated) <- c("auxId", "aggregated")

ga.genderAgeAffinityTable <- (merge(ga.genderAgeAffinityTable,
ga.interestAggregated, by = 'auxId'))

for (i3 in 1:nrow(ga.genderAgeAffinityTable) ) {

if (ga.genderAgeAffinityTable$interest_2[i3] == "Generalists" ) {

# Do not recalculate sessions for interests with only Generalists as subcategory          
if (ga.genderAgeAffinityTable$aggregated[i3] -
ga.genderAgeAffinityTable$sessions[i3] != 0 ) {

ga.genderAgeAffinityTable$sessions[i3] <-
ga.genderAgeAffinityTable$aggregated[i3] -
ga.genderAgeAffinityTable$sessions[i3]
}

}

}

您知道不使用 auxid 的更直接的方法吗?

【问题讨论】:

标签: r


【解决方案1】:

你看过data.table 包吗?它具有惊人的汇总功能,可能会对您有所帮助。

例如

library(data.table)
results <- DT[ , sum(sessions), by = subcategory]
# would give you total sessions per sub interest
#  which could help you subset when you then focus on Generalists.
#  to do multiple groups you would use by = .(gender, subcategory)

您可以使用 := 创建列以访问您的子集。 data.table 在右手中非常强大,可以防止你需要做的所有循环。您需要键入数据。

我还是一个初学者,所以下面的其他人可能有更高效的代码。

请查看data.table wikicheatsheet。 DT 大师/传奇人物 Matt 和 @Arun 在 SO 上非常活跃,如果您走这条路,他们很可能会参与其中并可能会为您提供帮助。

我们可能需要更多关于您希望如何转换数据的详细信息。即“通才应该只有 2 个会话”,请确认您期望的输出是什么。您是否需要这只是每个通才网络会话的每个性别/年龄组/兴趣的输出?

数据

为了帮助其他人参与,这里是使用dput的前两个类别的数据

library(data.table)
DT <- data.table(gender = c("male", "male", "male", "male", "male","male", "male"), 
ageGroup = c("18-24", "18-24", "18-24", "25-34","25-34", "25-34", "25-34"),
interest = c("Autos", "Autos", "Autos","Autos", "Autos", "Autos", "Autos"),
subcategory = c("Generalists","Luxury", "Vans", "Generalists", "Luxury", "Vans", "Compacts"), 
sessions = c(4L, 1L, 1L, 8L, 2L, 2L, 1L) )

解决方案

分阶段构建,以帮助解释并向您展示 的强大功能。这将得到除通才之外的所有内容。

notgensum <- DT[subcategory  != "Generalists", mysum := sum(sessions),
                by = .(gender, ageGroup, interest)]

    gender ageGroup interest subcategory sessions mysum
1:   male    18-24    Autos Generalists        4    NA
2:   male    18-24    Autos      Luxury        1     2
3:   male    18-24    Autos        Vans        1     2
4:   male    25-34    Autos Generalists        8    NA
5:   male    25-34    Autos      Luxury        2     5
6:   male    25-34    Autos        Vans        2     5
7:   male    25-34    Autos    Compacts        1     5

更进一步,我们减去通才的非通才人数(我使用平均忽略 NA 来得到这个数字)关闭通才的会话数。这使得 myadjsessions:2 代表第一个 (4 -2 ),3 代表 25-34 个男性汽车,如您所愿。

genadjsum2 <- notgensum[, myadjsessions := (sessions - mean(mysum, na.rm = T)),
                        by = .(gender, ageGroup, interest)]

#   gender ageGroup interest subcategory sessions mysum myadjsessions   
#1:   male    18-24    Autos Generalists        4    NA             2
#2:   male    18-24    Autos      Luxury        1     2            -1
#3:   male    18-24    Autos        Vans        1     2            -1
#4:   male    25-34    Autos Generalists        8    NA             3
#5:   male    25-34    Autos      Luxury        2     5            -3
#6:   male    25-34    Autos        Vans        2     5            -3
#7:   male    25-34    Autos    Compacts        1     5            -4

Data.table 可以链接,即 DT[do this][and this],所以如果你只想要通才的结果。

genadjsum3 <- notgensum[, 
             myadjsessions := (sessions - mean(mysum, na.rm = T)),
             by = .(gender, ageGroup, interest)][subcategory  == "Generalists"]

#  gender ageGroup interest subcategory sessions mysum myadjsessions
#1:   male    18-24    Autos Generalists        4    NA             2
#2:   male    25-34    Autos Generalists        8    NA             3

最后,如果要去掉mysum临时列,语法是

genadjsum3[, mysum := NULL]

而且你不会喜欢任何循环!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    相关资源
    最近更新 更多