【问题标题】:Coalescing/merging rows but retaining "dominant" values合并/合并行但保留“主导”值
【发布时间】:2021-12-23 08:45:35
【问题描述】:

我的问题似乎很琐碎,但似乎我没有找到合适的搜索词。

我的数据是这样的:

data <- data.frame(ID = c(1,1,2,3,3),
                   V1 = c("A","B","A","B","C"),
                   V2 = c("C","B",NA,"B","A"),
                   V3 = c("A","B","C","B",NA))

我想按 ID 合并或合并行,并且每个 ID 只保留一行,每列中的“最高”值。在我的示例中,我希望 C 优先于 B 而不是 A。

完成所需的操作后,我的数据将如下所示:

| ID | V1 | V2 | V3 |
| -- | -- | -- | -- |
|  1 | B  | C  | B  |
|  2 | A  | NA | C  |
|  3 | C  | B  | B  |

任何提示将不胜感激! Dplyr 是首选,但没有必要。谢谢!

编辑:解决方案(谢谢!)都利用了字母在 R 中“有序”这一事实。

让我们以这个示例数据为例:

data <- data.frame(ID = c(1,1,2,3,3),
                   V1 = c("yes","no","yes","no","unsure"),
                   V2 = c("unsure","no",NA,"no","yes"),
                   V3 = c("yes","no","unsure","no",NA))

期望的结果是“是”优先于“否”而不是“不确定”。

【问题讨论】:

  • 听起来您可能会交替将其表述为“我想优先考虑 B 而不是 C 而不是 A。”

标签: r dataframe dplyr character aggregate


【解决方案1】:

编辑:添加了更简单的 dplyr-only

library(dplyr)
data %>%
  group_by(ID) %>%
  summarize(across(V1:V3, max))

# A tibble: 3 × 4
     ID V1    V2    V3   
  <dbl> <chr> <chr> <chr>
1     1 B     C     B    
2     2 A     NA    C    
3     3 C     B     NA   

如果您想要有序因子,这里有一种方法,我们指定排序,将其应用于 V1:V3 中的数据,然后像以前一样继续。

data <- data.frame(ID = c(1,1,2,3,3),
                   V1 = c("yes","no","yes","no","unsure"),
                   V2 = c("unsure","no",NA,"no","yes"),
                   V3 = c("yes","no","unsure","no",NA))

var_order <- c("yes", "no", "unsure")


# Note addition of `ordered = TRUE` to make the `min` work
data %>%
  mutate(across(V1:V3, ~factor(.x, levels = var_order, ordered = TRUE))) %>%
  group_by(ID) %>%
  summarize(across(V1:V3, ~min(., na.rm = TRUE)))


# A tibble: 3 × 4
     ID V1    V2    V3    
  <dbl> <ord> <ord> <ord> 
1     1 yes   no    yes   
2     2 yes   NA    unsure
3     3 no    yes   no 

使用 tidyr 重塑的早期解决方案。这在没有 ordered = TRUE 标志集的情况下工作,但对于更大的数据集效率低下。

library(dplyr); library(tidyr)
data %>%
  mutate(across(V1:V3, ~factor(.x, levels = var_order))) %>%
  pivot_longer(-ID) %>%
  group_by(ID, name) %>%
  slice_min(value) %>%
  ungroup() %>% 
  pivot_wider(names_from = name)


# A tibble: 3 × 4
     ID V1    V2    V3    
  <dbl> <fct> <fct> <fct> 
1     1 yes   no    yes   
2     2 yes   NA    unsure
3     3 no    yes   no   

【讨论】:

  • 非常感谢您。您的方法有效,因为字母在 R 中是“有序的”。我应该让我的问题更精确:我希望能够自定义优先级,例如 B 优先于 C 优先于 A,因为在我的真实数据中,我正在处理的字符串是不按字母顺序。
  • 将 V1:V3 中的值转换为按您想要的方式排序的有序因子可能是最简单的。
  • 这听起来完全合理。非常感谢!
  • 查看编辑以获取使用有序因子的示例。
  • 再次,非常感谢您提供最有用的解决方案。我可以问一下您为什么在这里选择枢轴方法吗?根据我的经验,随着更大的数据集,这些变得相当资源密集。我现在只是将字符串转换为因子,对它们进行排序,在第一个 mutate 函数中将它们转换为数字,然后应用您的 dplyr 解决方案并使用第二个 mutate 函数 (case_when()) 将数字转换回字符。跨度>
【解决方案2】:

既然我们可以从字母表中得到一个字母的最大值,我们可以使用:

library(tidyverse)

data %>%
  group_by(ID) %>%
  summarize(across(everything(), ~ max(., na.rm = TRUE)))

这给出了:

# A tibble: 3 x 4
     ID V1    V2    V3   
  <dbl> <chr> <chr> <chr>
1     1 B     C     B    
2     2 A     <NA>  C    
3     3 C     B     B

【讨论】:

  • %&gt;% summarise_all(max, na.rm = T) 会更简洁一些
  • 不。随着 dplyr 1.0.0 (IIRC) 的发布,..._all 动词版本已被across() 取代。请参阅?summarize_all:“作用域动词 (_if, _at, _all) 已被现有动词中的 cross() 使用所取代。有关详细信息,请参阅 vignette("colwise")。”
  • 酷,不知道。不知道我是否觉得它更好。无论如何+1
  • mutate_if(is.factor, as.character) 我们也需要这个
  • 如果数据包含因子列,那么是的。 TO 提供的样本数据没有。
【解决方案3】:

这是base中的解决方案:

aggregate(data[,-1], by = list(ID=data$ID), FUN = max, na.rm = T)

#   ID V1   V2 V3
# 1  1  B    C  B
# 2  2  A <NA>  C
# 3  3  C    B  B

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-19
    • 1970-01-01
    相关资源
    最近更新 更多