【问题标题】:Replace specific chr values within groups for multiple variables in R为 R 中的多个变量替换组内的特定 chr 值
【发布时间】:2021-06-17 15:11:02
【问题描述】:

1.总结问题

嗨,我对 R 比较陌生,这是我关于堆栈的第一个问题overflow,但我已经从这个网站学习了一段时间。我发现了类似的问题,但它们解释了如何删除 missing values、使用 numerical values 或仅适用于 small number of IDs

我有一个大型数据框(200 000+ 行),其中一个变量是代表唯一候选者的字母数字 ID,而其他变量代表不同的特征。一些候选项在文件中包含多次,但对于同一特征具有不同的值。我想解决这些差异,以便以后能够删除重复项。数据结构类似这样:

df <- tibble(ID = c("123abc", "123abc", "123abc", "456def", "456def", "789ghi"),
                 var1 = c("No", "Yes", "No", "No", "No", "No"),
                 var2 = c("No", "No", "No", "Yes", "No", "No"),
                 var3 = c("No", "No", "No", "No", "No", "Yes"))

我的目标是首先基于 ID 创建子组,然后在每个 ID 中搜索以查看它们是否具有至少一个值“是”,如果是,则将其所有值更改为“是”。我想对几个变量(var1、var2、var3)重复此操作。这是我想要的结果:

df <- tibble(ID = c("123abc", "123abc", "123abc", "456def", "456def", "789ghi"),
              var1 = c("Yes", "Yes", "Yes", "No", "No", "No"),
              var2 = c("No", "No", "No", "Yes", "Yes", "No"),
              var3 = c("No", "No", "No", "No", "No", "Yes"))

在此之后,我将删除重复的行以仅保留我需要的数据。

df <- distinct(df, across(), .keep_all = TRUE)

2。描述你的尝试

我找到了部分解决方案,但很难将它们组合在一起。我可以使用 dplyr 中的 group_by 按 ID 重新组合我的数据,但我在将其他功能应用于组时遇到问题:

df <- df %>% group_by(ID)

我可以使用if 结合any 将“否”替换为“是”,但如果没有组,它会更改 var1 中的所有值:

if(any(df$var1 == "Yes"))
  {  df$var1 = "Yes"  }

我尝试创建的解决方案类似于Creating loop for slicing the data, loop through the duplicated positions,使用for 循环ID,然后循环变量,但不替换为随机值。

【问题讨论】:

  • 感谢您在发布问题之前阅读提示。我认为这应该适合你:df %&gt;% group_by(ID) %&gt;% summarise(across(var1:var3, ~ if_else(any(. == "Yes"),"Yes","No"))) 或者 df %&gt;% group_by(ID) %&gt;% mutate(across(var1:var3, ~ if(any(. == "Yes"))rep("Yes",length(.)) else .))

标签: r


【解决方案1】:

我已将我的评论提升为答案以进行更多解释。

首先,我们需要决定是使用dplyr::summarise 还是dplyr::mutatesummarise 为每个组创建一行,而 mutate 使数据保持相同的维度。

在您的示例数据中,每个组中的所有行在转换后都将相同,那么您真的需要重复吗?也许你的真实数据还有其他变量,所以mutate 可能有意义。

从这里开始,我们只需要使用dplyr::across 对每一列执行相同的操作。第一个参数是选择列,第二个是你要应用的函数。

对于变异,我们可以使用dplyr::ifelse 来测试是否有任何变量是"Yes"。如果是,我们可以重复"Yes" 的次数与该组中的行数一样多。否则,我们可以不理会数据。对于across,数据由. 表示。

df %>% 
  group_by(ID) %>%
  mutate(across(var1:var3, ~ ifelse(any(. == "Yes"),rep("Yes",length(.)),.)))
# A tibble: 6 x 4
# Groups:   ID [3]
  ID     var1  var2  var3 
  <chr>  <chr> <chr> <chr>
1 123abc Yes   No    No   
2 123abc Yes   No    No   
3 123abc Yes   No    No   
4 456def No    Yes   No   
5 456def No    Yes   No   
6 789ghi No    No    Yes  

【讨论】:

  • 谢谢!正如您所描述的,这两个答案都有效,但是由于我确实有其他变量,因此具有 mutate 的那个效果最好。感谢您花时间解释!
【解决方案2】:

如果您愿意使用data.table,您可以使用lapply 完成所有这些操作。这是基于@ricardo-saporta 对Summarizing multiple columns with data.table 的回答。

library(tibble)
library(data.table)

df <- tibble(ID = c("123abc", "123abc", "123abc", "456def", "456def", "789ghi"),
  var1 = c("No", "Yes", "No", "No", "No", "No"),
  var2 = c("No", "No", "No", "Yes", "No", "No"),
  var3 = c("No", "No", "No", "No", "No", "Yes"))

setDT(df)

any_yes <- function(x) {
  if (any(x == 'Yes')) {
    return('Yes')
  }
  
  'No'
}

df[, lapply(.SD, any_yes), by = ID]

【讨论】:

    【解决方案3】:

    我从亲爱的@akrun 那里学到了更多方法,这消除了使用ifelse 的需要

    library(dplyr)
    
    df %>% 
      group_by(ID) %>%
      mutate(across(var1:var3, ~  c('No', 'Yes')[1 + as.logical(sum(. == 'Yes'))]))
    
    #> # A tibble: 6 x 4
    #> # Groups:   ID [3]
    #>   ID     var1  var2  var3 
    #>   <chr>  <chr> <chr> <chr>
    #> 1 123abc Yes   No    No   
    #> 2 123abc Yes   No    No   
    #> 3 123abc Yes   No    No   
    #> 4 456def No    Yes   No   
    #> 5 456def No    Yes   No   
    #> 6 789ghi No    No    Yes
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 2018-11-09
      • 1970-01-01
      • 2019-05-07
      相关资源
      最近更新 更多