首页 > 解决方案 > 如何根据所在组的大小为项目添加权重

问题描述

我有一个看起来像这样的数据集

product  material
product1 wheat
product1 water
product1 tomato
product2 milk
product3 basil
product3 garlic

我有一条规则,如果产品由一种材料组成,那么该材料就是产品的 100%。如果它由两种材料组成,第一种材料占总数的 60%,第二种材料占总数的 40%。如果一个产品由 3 种材料组成,第一种材料占 70%,第二种材料占 20%,最后一种材料占 10%。我想添加一列这些权重,但我不知道如何解决这个问题。规则最多5种材料,重量需要容易改变。最后我希望上面的数据看起来像这样

product  material weight
product1 wheat    0.7
product1 water    0.2
product1 tomato   0.1
product2 milk     1
product3 basil    0.6
product3 pizza    0.4

我就是这样开始的

df = tribble(
  ~product, ~material_type,
  "product1", "wheat",
  "product1", "Water",
  "product1", "tomato",
  "product2", "milk",
  "product3", "basil",
  "product3", "garlic")

df %>% 
  group_by(product) %>% 
  mutate(n = n())

  product  material_type     n
  <chr>    <chr>         <int>
1 product1 wheat             3
2 product1 Water             3
3 product1 tomato            3
4 product2 milk              1
5 product3 basil             2
6 product3 garlic            2

这确实给了我每组中有多少材料,从这里我不知道如何进一步了解,希望这里有人有一个可以帮助我的好主意。

编辑:

我尝试添加 case_when 建议,但没有奏效:

df %>% 
  group_by(product) %>% 
  mutate(n = n()) %>% 
  mutate(weight = case_when(n == 5 ~ c(.4, .3, .1, .1, .1),
                            n== 4 ~ c(.5, .3, .1, .1),
                            n ==3 ~ c(.7, .2, .1),
                            n == 2 ~ c(0.6, 0.4),
                            TRUE ~ 1))

Error: `n == 5 ~ c(0.4, 0.3, 0.1, 0.1, 0.1)`, `n == 4 ~ c(0.5, 0.3, 0.1, 0.1)`, `n == 2 ~ c(0.6, 0.4)` must be length 3 or one, not 5, 4, 2
Call `rlang::last_error()` to see a backtrace.

标签: r

解决方案


我们可以创建一个键/值,list然后n()根据namelist

library(dplyr)
library(tidyr)
lst1 <- list(`5` =  c(.4, .3, .1, .1, .1), `4` = c(.5, .3, .1, .1),
        `3` = c(.7, .2, .1), `2` =c(0.6, 0.4), `1` = 1 )

df %>%
     group_by(product) %>%
     summarise(weight = list(lst1[[as.character(n())]])) %>%   
     unnest(c(weight)) %>%
     select(-product) %>% 
     bind_cols(df, .)
# A tibble: 6 x 3
#  product  material_type weight
#* <chr>    <chr>         <dbl>
#1 product1 wheat           0.7
#2 product1 Water           0.2
#3 product1 tomato          0.1
#4 product2 milk            1  
#5 product3 basil           0.6
#6 product3 garlic          0.4

或者unnest同时使用“material_type”和“weight”并避免bind_cols

df %>% 
   group_by(product) %>% 
   summarise(material_type = list(material_type),
            weight = list(lst1[[as.character(n())]])) %>% 
   unnest(c(material_type, weight))

或者另一种选择是if/else

df %>%
   group_by(product) %>%
   mutate(weight = if(n() == 5)  c(.4, .3, .1, .1, .1)
            else if(n() == 4)  c(.5, .3, .1, .1)
            else if(n() == 3) c(.7, .2, .1) 
            else if(n() == 2) c(0.6, 0.4)
            else 1)

推荐阅读