合并具有相似信息的行

3

我有一个包含多行数据的数据框,我需要将具有相同ID的行合并。

a=read.csv("a.csv")
view(a)

ID  Value1  Value2  Value3  Value4  Value5  Value6
1076    2940    NA  NA  2   NA  NA
1076    2940    1   A-  NA  302 549
1109    2940    NA  NA  3   NA  NA
1109    2940    NA  A-  NA  700 150

我需要类似以下的结果

ID  Value1  Value2  Value3  Value4  Value5  Value6
1076    2940    1   A-  2   302 549
1109    2940    NA  A-  3   700 150                     

我已经查看了一个类似问题的答案 (合并共享信息的行)。但是我的结果出现了错误。

library(dplyr)
f <- function(x) {
  x <- na.omit(x)
  if (length(x) > 0) paste(x,collapse='-') else NA
}
a_merge <- a %>% group_by(ID)%>%summarise_all(list(f))

但是我遇到了以下错误。
Error: Column `Value2` can't promote group 1 to character

请帮忙。

3个回答

3

一种选择是使用 if/else 创建一个条件,当列中所有值都为NA时返回NA,否则获取一个list中唯一的非NA元素。

library(dplyr)
a %>% 
   group_by(ID) %>%
   summarise_all(list(~ list(if(all(is.na(.))) NA else unique(.[!is.na(.)]))))
# A tibble: 2 x 7
#     ID Value1    Value2    Value3    Value4    Value5    Value6   
#  <int> <list>    <list>    <list>    <list>    <list>    <list>   
#1  1076 <int [1]> <int [1]> <chr [1]> <int [1]> <int [1]> <int [1]>
#2  1109 <int [1]> <lgl [1]> <chr [1]> <int [1]> <int [1]> <int [1]>

编辑:

1)包装在一个列表

2)@Gregor的评论 - 仅获取唯一的非NA元素

数据

a <- structure(list(ID = c(1076L, 1076L, 1109L, 1109L), Value1 = c(2940L, 
2940L, 2940L, 2940L), Value2 = c(NA, 1L, NA, NA), Value3 = c(NA, 
"A-", NA, "A-"), Value4 = c(2L, NA, 3L, NA), Value5 = c(NA, 302L, 
NA, 700L), Value6 = c(NA, 549L, NA, 150L)), class = "data.frame", row.names = c(NA, 
-4L))

1
我更喜欢作为一个列表 - Looper
4
根据操作者的用例,对于 list(unique(.[!is.na(.)])) 添加一个 unique() 可能更好。 - Gregor Thomas
1
@Looper 我认为问题在于 list 包装。我将其更改为 list(if(all。请尝试。 - akrun
1
@Looper 在这种情况下,使用 toString(unique(.[!is.na(.)])) 并删除 list 包装器。 - akrun
1
@Looper a %>% group_by(ID) %>% summarise_all(list(~ if(all(is.na(.))) NA_character_ else toString(unique(.[!is.na(.)])))) - akrun
显示剩余4条评论

2
这里有一个基于R语言的方法:

最初的回答

setNames(do.call(rbind.data.frame, lapply(split(df, df$ID), function(i) 
                                       sapply(i, function(j) j[!is.na(j)][1]))), names(df))

#    ID Value1 Value2 Value3 Value4 Value5 Value6
#1 1076   2940      1     A-      2    302    549
#2 1109   2940   <NA>     A-      3    700    150

1
如果您使用data.table,则可以避免将所有列转换为列表,只需在必要时转换即可。
library(data.table)
setDT(df)

df[, lapply(.SD, function(x)
          if(length(vals <- unique(x[!is.na(x)])) > 1)
            list(vals)
          else vals), 
  by = ID]

#      ID Value1 Value2 Value3 Value4 Value5 Value6
# 1: 1076   2940    2,1     A-      2    302    549
# 2: 1109   2940            A-      3    700    150

如果您正在使用 toString,您可以删除 if 并简化事情。这也适用于 dplyr。
df[, lapply(.SD, function(x) toString(unique(x[!is.na(x)]))),
  by = ID]
# 1: 1076   2940   2, 1     A-      2    302    549
# 2: 1109   2940            A-      3    700    150

修改后的示例数据(添加了一个具有>1个不同值的情况)

df <- fread('
ID  Value1  Value2  Value3  Value4  Value5  Value6
1076    2940    2  NA  2   NA  NA
1076    2940    1   A-  NA  302 549
1109    2940    NA  NA  3   NA  NA
1109    2940    NA  A-  NA  700 150
')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接