【问题标题】:How to manipulate (aggregate) the data in R?如何操作(聚合)R中的数据?
【发布时间】:2020-03-28 13:08:25
【问题描述】:

我有一个如下所示的数据集:

df <- tribble(
  ~id,  ~price, ~number_of_book,        
  "1",    10,         3,        
  "1",     5,         1,         
  "2",     7,         4,
  "2",     6,         2, 
  "2",     3,         4,
  "3",     4,         1,
  "4",     5,         1,
  "4",     6,         1,
  "5",     1,         2,
  "5",     9,         3,
)

正如您在数据集中看到的,如果 id 为“1”,则有 3 本书每本书的价格为 10 美元,而 1 本书的价格为 5 美元。基本上,我想查看每个价格箱的图书数量的份额(%)。这是我想要的数据集:

df <- tribble(
  ~id,    ~less_than_three,   ~three-five,  ~five-six, ~more_than_six,     
  "1",          "0%",              "25%",     "0%",         "75%",
  "2",          "0%",              "40%",     "20%",        "40%",
  "3",          "0%",              "100%",    "0%",         "0%",  
  "4",          "0%",              "50%",     "50%",        "0%",
  "5",          "40%",             "0%",      "0%",         "60%",
)

现在,我首先对价格进行聚类。为此,我运行以下代码:

out <- cut(df$price, breaks = c(0, 3, 5, 6, 10),
           labels = c("<3","3-5","5-6", ">6")) 

out = table(out) / sum(table(out)) 

但不幸的是,由于缺乏编码知识,我无法更进一步。你能帮我得到想要的数据吗?

【问题讨论】:

    标签: r dataframe dplyr tidyverse intervals


    【解决方案1】:

    我们可以使用cut获取区间,然后使用tidyr将数据转换为宽格式,最后使用janitor添加百分比。

    library(dplyr)
    library(tidyr)
    library(janitor)
    
    df %>% 
      mutate(interval = cut(price, c(0,3,5,6,Inf))) %>% 
      select(-price) %>% 
      pivot_wider(names_from = interval, values_from = number_of_book) %>% 
      adorn_percentages()
    
    #>  id (6,Inf] (3,5] (5,6] (0,3]
    #>   1    0.75  0.25    NA    NA
    #>   2    0.40    NA   0.2   0.4
    #>   3      NA  1.00    NA    NA
    #>   4      NA  0.50   0.5    NA
    #>   5    0.60    NA    NA   0.4
    

    【讨论】:

    • 您可以在pivot_wider 中使用values_fill = list(percentage_of_book = 0) 来避免NAs
    • 请注意,这假定每个 (interval, id) 组只有 1 行。尝试在第 1 行和第 2 行之间增加一行,价格 = 4,看看我的意思。
    • @akraf-ReinstateMonica 我知道这一点,但不喜欢用零替换 NA,因为它们具有不同的含义。
    • @IceCreamToucan 一个简单的group_by %&gt;% summarise 会解决这个问题,正如您在回答中所展示的那样。干杯 +1。
    • 感谢您的帮助@M--,我的真实数据集中出现以下错误: as_tabyl(dat) 中的错误:至少有一个列 2:n 必须属于类numeric 另外:警告消息:number_of_book 中的值不是唯一标识的;输出将包含 list-cols。
    【解决方案2】:

    使用 dplyr,您可以添加一个列 cols,该列将用于列名。然后,您可以将每个 id 中每个 col 的书籍数量相加。接下来,您可以通过将这些数字除以该 id 的总和来计算百分比,然后应用scales::percent 将格式设置为百分比而不是小数。现在您只需要 pivot_wider 提供从中获取名称和值的变量,并对列重新排序以匹配原始标签顺序。 (这比其他答案涉及更多一点,因为它说明了给定 (id, cols/interval) 对有 >1 行的情况,并且看门人简化了事情)

    labels = c("less_than_three","three_to_five","five_to_six", "more_than_six")
    
    df %>% 
      group_by(id, cols = cut(price, breaks = c(0, 3, 5, 6, 10), labels = labels)) %>% 
      summarise(n = sum(number_of_book)) %>% 
      group_by(id) %>% 
      mutate(pct = scales::percent(n/sum(n), 1)) %>% 
      pivot_wider(id_cols = id, names_from = cols, values_from = pct) %>% 
      select_at(c('id', labels)) %>% 
      ungroup
    
    # # A tibble: 5 x 5
    #   id    less_than_three three_to_five five_to_six more_than_six
    #   <chr> <chr>           <chr>         <chr>       <chr>        
    # 1 1     NA              25%           NA          75%          
    # 2 2     40%             NA            20%         40%          
    # 3 3     NA              100%          NA          NA           
    # 4 4     NA              50%           50%         NA           
    # 5 5     40%             NA            NA          60%       
    

    如果您想用 0% 替换 NA(我认为这在这种情况下是有意义的,并且与问题中显示的输出相匹配),您可以使用下面评论中提到的方法。

    df %>% 
      group_by(id, cols = cut(price, breaks = c(0, 3, 5, 6, 10), labels = labels)) %>% 
      summarise(n = sum(number_of_book)) %>% 
      group_by(id) %>% 
      mutate(pct = scales::percent(n/sum(n), 1)) %>% 
      pivot_wider(id_cols = id, names_from = cols, values_from = pct,
                  values_fill = list(pct = '0%')) %>% 
      select_at(c('id', labels)) %>% 
      ungroup
    
    # # A tibble: 5 x 5
    #   id    less_than_three three_to_five five_to_six more_than_six
    #   <chr> <chr>           <chr>         <chr>       <chr>        
    # 1 1     0%              57%           0%          43%          
    # 2 2     40%             0%            20%         40%          
    # 3 3     0%              100%          0%          0%           
    # 4 4     0%              50%           50%         0%           
    # 5 5     40%             0%            0%          60%         
    

    【讨论】:

    • 您可以在pivot_wider 中使用values_fill = list(percentage_of_book = 0) 来避免NAs
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 2016-05-17
    • 2021-11-17
    • 2020-09-03
    • 2019-03-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多