【问题标题】:Can dplyr add the values from merged columns together?dplyr 可以将合并列中的值加在一起吗?
【发布时间】:2021-03-30 22:37:56
【问题描述】:

我有一个数据框,工作人员(约 8 个不同的职位)分配在许多(约 70 多个)不同的位置,例如

Location Job1 Job2 Job3 Total
A 1 2 3 6
B 4 5 6 7

我有另一个带有开口(无人值守职位)的数据框,但列的顺序不同。例如

Location Job2 Job1 Job3 Total
A 0 1 1 2
B 1 4 1 6

我最终是在寻找一个按位置/职位显示人员配备率的汇总表,例如

Location Job1 Job2 Job3 Total
A 0.50 1.00 0.75 0.75
B 0.50 0.83 0.86 0.54

到目前为止,我已经成功地将前两个表合并在一起(使用left_join,因为有些位置没有空缺职位,这些职位根本不存在于短缺表中),by = location, suffix = c(".f", ".uf") 用于填充和未填充,导致一个看起来像这样的表:

Location Job1.f Job2.f Job3.f Total.f Job2.uf Job1.uf Job3.uf Total.uf
A 1 2 3 6 0 1 1 2
B 4 5 6 7 1 4 1 6

问题:是否有任何方法(除了循环作业类型,如果可能,使用dplyr)根据匹配的名称更改列,例如data %>% mutate(fill_rate1 = Job1.f / (Job1.f + Job1.uf)),而无需为每个作业类型手动键入单独的行?我的倾向是应该有一些“通配符”/正则表达式匹配技术,但到目前为止我还没有运气。

编辑:下面的可重现代码

library(tidyverse)

locations <- c("A","B","C","D","E")
job1 <- c(1,2,3,4,5)
job2 <- c(6,7,8,9,10)
job3 <- c(11,12,13,14,15)
total <- c(18, 21, 24, 27, 30)

loc_uf <- c("A","B","E")
uf1 <- c(0,2,4)
uf2 <- c(3,6,9)
uf3 <- c(7,3,0)
uftotal <- c(10, 11, 13)

filled <- data_frame(locations = locations, Job1 = job1, Job2 = job2, Job3 = job3,
                     total = total)

unfilled <- data_frame(locations = loc_uf, Job2 = uf2, Job1 = uf1, Job3 = uf3,
                       total = uftotal)

merged <- left_join(filled, unfilled, by = "locations", suffix = c(".f", ".uf")) %>%
          replace(is.na(.), 0)

【问题讨论】:

  • 您能否分享一段可重现的数据,以便其他人使用?

标签: r dplyr


【解决方案1】:

我认为如果您使用tidyr::pivot_longer 将数据重新整形为长格式,这会更容易,因为作业在一个列中,而值在另一列中。

library(dplyr)
library(tidyr)

df1 %>% 
  pivot_longer(cols = -Location) %>% 
  left_join(pivot_longer(df2, cols = -Location), by = c("Location", "name")) %>%
  mutate(rate = value.x / (value.x + value.y))

结果:

# A tibble: 8 x 5
  Location name  value.x value.y  rate
  <chr>    <chr>   <int>   <int> <dbl>
1 A        Job1        1       1 0.5  
2 A        Job2        2       0 1    
3 A        Job3        3       1 0.75 
4 A        Total       6       2 0.75 
5 B        Job1        4       4 0.5  
6 B        Job2        5       1 0.833
7 B        Job3        6       1 0.857
8 B        Total       7       6 0.538

数据:

df1 <- structure(list(Location = c("A", "B"), 
                      Job1 = c(1L, 4L), 
                      Job2 = c(2L, 5L), 
                      Job3 = c(3L, 6L), 
                      Total = 6:7), 
                      class = "data.frame", row.names = c(NA, -2L))

df2 <- structure(list(Location = c("A", "B"), 
                      Job2 = 0:1, 
                      Job1 = c(1L, 4L), 
                      Job3 = c(1L, 1L), 
                      Total = c(2L, 6L)), 
                      class = "data.frame", row.names = c(NA, -2L))

【讨论】:

    【解决方案2】:

    另一种方法是使用across

    library(dplyr)
    library(stringr)
    data %>%
      mutate(across(contains(".f"),
                    ~ ./(. + get(str_replace(cur_column(),".f",".uf"))),
                    .names = "fillrate_{.col}"))
    #  Location Job1.f Job2.f Job3.f Total.f Job2.uf Job1.uf Job3.uf Total.uf fillrate_Job1.f fillrate_Job2.f fillrate_Job3.f fillrate_Total.f
    #1        A      1      2      3       6       0       1       1        2             0.5       1.0000000       0.7500000        0.7500000
    #2        B      4      5      6       7       1       4       1        6             0.5       0.8333333       0.8571429        0.5384615
    

    【讨论】:

    • 我想我曾经使用过这种基于get 的方法来解决问题(不确定之前是否有人这样做过)。在当前版本中它可以工作,但它可能需要一些更改,因为我发现很多问题都在问类似的问题。使用 pivot_longer 方法了解这种方法的效率也很好
    • @akrun 我同意有一个比较效率的强大问答会很有帮助,特别是因为这个问题会弹出not infrequently
    猜你喜欢
    • 2021-11-13
    • 2014-12-24
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多