【问题标题】:Group by name and add up the columns count in r按名称分组并将 r 中的列数相加
【发布时间】:2021-06-22 08:42:07
【问题描述】:

我有一个包含 405 个观察值和 39 个变量的数据集。但只有两列对进一步分析很重要。

我想将具有相似名称的第一行组合在一起,然后将第二列中的数字相加。

可重现的数据集如下所示:

df1 <- data.frame(name=c("Google Ads", "Google Doubleclick","Facebook Login",
"Facebook Ads","Twitter MoPub","Flurry","Amazon advertisment","Microsoft ","Ad4screen","imobi"),
value=c(10,20,30,40,50,60,70,80,90,100),unimportant=c(1,2,3,4,5,6,7,8,9,10))

结果应该在一个新的 data.frame 中,如下所示:

 df2 <- data.frame (name=c("Google","Facebook","Twitter","Flurry","Amazon","Microsoft","Others"),
value=c(30,70,50,60,70,80,190))

【问题讨论】:

  • 我们如何确定哪些行是重要的?即我们如何解释 unimportant 的 1:10 值?谢谢
  • 只是名称和值列很重要。不重要的列不重要。
  • others. 的标准是什么?对于其他群体,它似乎是名字?是吗?如何将something microsoft之类的字符串分组到somethingmicrosoft中?
  • 这将是字符串中的一个单词(无论在字符串中的哪个位置) - 我要搜索的单词保存在 df2$name 中。其他组的条件是没有来自 df2$names 的匹配词。

标签: r string


【解决方案1】:

tidyverse 的做法。

  • 首先将所有有效名称存储在一个向量中,比如valid_names
  • 此后在df1 中创建一个新列all_names 由-
    • 首先使用str_split 在空间' ' 处拆分所有字符串
    • 之后使用purrr::map_chr() 检查是否有任何拆分字符串与您的valid_names 匹配,如果是,则仅检索该字符串,否则获取others
  • 此后group_by 在此字段上。 (我先省略了一步mutate,然后group_by,直接在group_by语句中创建了新字段,有效)
  • 现在根据需要总结您的 important 值。
valid_names =c("Google","Facebook","Twitter","Flurry","Amazon","Microsoft")

valid_names
#> [1] "Google"    "Facebook"  "Twitter"   "Flurry"    "Amazon"    "Microsoft"

df1 <- data.frame(name=c("Google Ads", "Google Doubleclick","Facebook Login",
                         "Facebook Ads","Twitter MoPub","Flurry","Amazon advertisment","Microsoft ","Ad4screen","imobi"),
                  value=c(10,20,30,40,50,60,70,80,90,100),unimportant=c(1,2,3,4,5,6,7,8,9,10))
df1
#>                   name value unimportant
#> 1           Google Ads    10           1
#> 2   Google Doubleclick    20           2
#> 3       Facebook Login    30           3
#> 4         Facebook Ads    40           4
#> 5        Twitter MoPub    50           5
#> 6               Flurry    60           6
#> 7  Amazon advertisment    70           7
#> 8           Microsoft     80           8
#> 9            Ad4screen    90           9
#> 10               imobi   100          10
library(tidyverse)

df1 %>% group_by(all_names = str_split(name, ' '),
               all_names = map_chr(all_names, ~ ifelse(any(.x %in% valid_names),.x[.x %in% valid_names], 'others'))) %>%
  summarise(value = sum(value), .groups = 'drop')
#> # A tibble: 7 x 2
#>   all_names value
#>   <chr>     <dbl>
#> 1 Amazon       70
#> 2 Facebook     70
#> 3 Flurry       60
#> 4 Google       30
#> 5 Microsoft    80
#> 6 others      190
#> 7 Twitter      50

reprex package (v2.0.0) 于 2021-06-22 创建

【讨论】:

    【解决方案2】:

    这适用于使用adist 函数和partial=TRUE 来查看部分字符串匹配的示例数据。它需要定义已知组,而不是试图找到它们。我认为这项工作是值得的,因为一旦知道输出,它就会大大简化问题

    df1 <- data.frame(name=c("Google Ads", "Google Doubleclick","Facebook Login",
                             "Facbook Ads","Twitter MoPub","Flurry","Amazon advertisment","Microsoft ","Ad4screen","imobi"),
                      value=c(10,20,30,40,50,60,70,80,90,100),unimportant=c(1,2,3,4,5,6,7,8,9,10))
    
    # types we want to map. known is the groupings
    types <- unique(df1$name)
    known <- c("Google","Facebook","Twitter","Flurry","Amazon","Microsoft")
    
    # use distrance measures, and look for matches on partial strings eg
    # ignore the Doubleclick part when matching on Google
    distance <- adist(known, types, partial=TRUE)
    
    # cap controls leniancy in matching e.g. Facbook and Facebook have a dist of 1
    # whilst Facebook and Facebook is a perfect match with score of 0
    # Raise to be more leniant
    cap <- 1
    # loop through the types
    map_all <- sapply(seq_along(types), function(i){
      # find minimum value, check if its below the cap. If so, assign to the closest
      # group, else assign to others
      v <- min(distance[,i])
      if(v <= cap){
        map_i <- known[which.min(distance[,i])]
      }else{
        map_i <- "Others"
      }
      map_i
    })
    
    # now merge in to df1, then sum out using your preferred method
    df_map <- data.frame(name=types, group=map_all)
    df_merged <- merge(df1, df_map, by="name")
    df2 <- aggregate(value ~ group, sum, data=df_merged)
    df2
          group value
    1    Amazon    70
    2  Facebook    70
    3    Flurry    60
    4    Google    30
    5 Microsoft    80
    6    Others   190
    7   Twitter    50
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      • 2021-06-13
      • 1970-01-01
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多