首页 > 解决方案 > 是否有一个 R 函数可以仅根据条件部分更改多个变量名称?

问题描述

我有一个数据集,其中的变量代表个人的几个方面,用连字符分隔。我一直在使用 dplyr 包 'select' 和 'contains' 功能来总结各个方面。

然而,一个方面可以描述为“其他”并在另一列中指定。我希望能够更改部分变量名称以反映另一列中的条目。

例如:

#Key: b = big; s = small
> #   : g = green, p = purple, o = other
> 
> oth<- c("red", NA, NA, "yellow")
> b_g<- c(1, 2, 3, 2)
> s_g<- c(2, 3, 1, 4)
> b_p<- c(1, 2, 3, 2)
> s_p<- c(2, 3, 1, 4)
> b_o<- c(3, 0, 0, 1)
> s_o<- c(2, 0, 0, 4)
> 
> 
> df<- data.frame(oth, b_g, s_g, b_p, s_p, b_o, s_o)
> df
     oth b_g s_g b_p s_p b_o s_o
1    red   1   2   1   2   3   2
2   <NA>   2   3   2   3   0   0
3   <NA>   3   1   3   1   0   0
4 yellow   2   4   2   4   1   4
> 
> #To summerise for green only I would use: 
> 
> green<- df %>% select(contains("_g")) %>% mutate(totalg = rowSums(.[1:2]))
> summary(green$totalg)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   3.00    3.75    4.50    4.50    5.25    6.00 
> 

我想更改数据框中变量的名称,以便它从另一列中提取,如果可能的话,在途中将其转换(例如将“红色”编码为“r”),以便我最终得到以下内容

df
     oth b_g s_g b_p s_p b_o s_o b_r s_r b_y s_y
1    red   1   2   1   2   3   2   3   2   0   0
2   <NA>   2   3   2   3   0   0   0   0   0   0
3   <NA>   3   1   3   1   0   0   0   0   0   0
4 yellow   2   4   2   4   1   4   0   0   1   4

我将非常感谢任何建议。如果我遗漏了任何内容,第一次发帖道歉

标签: rdplyrdata-cleaning

解决方案


给定您所需输出的示例,这对您有什么作用?

library(dplyr)
library(purrr)

df2 <- df %>%
    split(coalesce(oth,'NA')) %>%
    imap(~{
        if(.y == 'NA') return(.x %>% select(-ends_with('_o')))
        colnames(.x) <- gsub('(?<=_)o', substr(.y,1,1), colnames(.x), perl = T)
        .x
    }) %>%
    bind_rows() %>%
    mutate(across(.cols = where(is.numeric), .fns = ~coalesce(.,0)))

但是,这split确实混淆了条目的顺序。

如果要避免这种情况,我认为以下方法也有效:

library(dplyr)
library(tidyr)

df3 <- df %>%
    nest(other_cols = ends_with('_o')) %>%
    mutate(
    other_cols = map2(other_cols, oth, ~{
        if(is.na(.y)) return(tibble())
        colnames(.x) <- gsub('(?<=_)o', substr(.y,1,1), colnames(.x), perl = T)
        .x
      })
    ) %>%
    unnest(other_cols, keep_empty = T) %>%
    mutate(across(.cols = where(is.numeric), .fns = ~coalesce(.,0)))

推荐阅读