基于唯一ID合并数据框的行

3

我有一个数据框,在所有参与者中,一个唯一的主体ID会重复两次。接下来的数据似乎由一列组成,在其中一个条目的值为NA,在另一个条目中存在一个值(尽管这不确定,我使用的方法应该考虑到这种可能性不存在)。

以下是一个示例:

Name <- c("Jon", "Jon", "Maria", "Maria", "Tina", "Tina", "dan", 'dan', 'wen', 'wen')
a <- c(1, 1, 2, 2, 3, 4, 4, 4, 5, 6)
b <- c(NA, 1, NA, 2, NA, 3, NA, 4, NA, 5)
c <- c(1, NA, 2, NA, 3, NA, 4, NA, 5, NA)
df <- data.frame(Name, a, b, c)

到目前为止,我想到的解决方案是循环遍历所有唯一的ID(在上面的例子中是名称),并为每个条目创建单独的数据框。类似于这样:
#Instantiate list of lists that will become dfs
firstdf <- c()
seconddf <- c()

#Loop through existing df by unique ID (Name) and create 
# list containing values of 1 entry and list of the other 
for (i in unique(df$Name)) {
  innerlist1 <- c()
  innerlist2 <- c()
  
  for (x in c(1:length(df[df['Name'] == i]))) {
    if (x%%2 == 1) {
      # Takes one set of entries per ID
      innerlist1 <- c(innerlist1, df[df['Name'] == i][x])
      
    } else if (x%%2 == 0) {
      # Takes other set of entries per ID
      innerlist2 <- c(innerlist2, df[df['Name'] == i][x])
    }
  }
  firstdf <- c(firstdf, list(innerlist1))
  seconddf <- c(seconddf, list(innerlist2))
}
# Make dfs from lists
firstdf <- do.call(rbind.data.frame, firstdf)
names(firstdf) <- names(df)

seconddf <- do.call(rbind.data.frame, seconddf)
names(seconddf) <- names(df)

我会使用类似于合并的方法,通过by="Name"将dfs组合起来。 我的原始数据集很大,这种方法不是特别高效或优雅。有没有人能提出改进意见?

3个回答

1
您可以通过排除组中的NA来保留第一个值:
library(dplyr)

df %>%
  group_by(Name) %>%
  summarise(a = first(stats::na.omit(a)), 
            b = first(stats::na.omit(b)), 
            c = first(stats::na.omit(c)))
# A tibble: 5 x 4
  Name      a     b     c
  <chr> <dbl> <dbl> <dbl>
1 dan       4     4     4
2 Jon       1     1     1
3 Maria     2     2     2
4 Tina      3     3     3
5 wen       5     5     5

这很有帮助,但我注意到例如在Tina的实例中只取了值3,而更合适的是取3和4的平均值或者像“3,4”这样的东西。 - JED HK
1
你可以用 meanpaste 的值来替换 first - Clemsang

1

如果一个ID对应多个非NA值,您可以使用toString函数来将它们合并。您可以使用以下代码:

library(dplyr)
df %>% 
  group_by(Name) %>% 
  summarise_all(funs(toString(na.omit(.))))

输出:

# A tibble: 5 × 4
  Name  a     b     c    
  <chr> <chr> <chr> <chr>
1 dan   4, 4  4     4    
2 Jon   1, 1  1     1    
3 Maria 2, 2  2     2    
4 Tina  3, 4  3     3    
5 wen   5, 6  5     5 

-1

顺便说一句,对于未来的读者,我最终做的是按奇偶索引逐个获取每个ID的条目,并创建两个数据框,如下:

firstdf <- df[seq_len(nrow(df))%%2 == 1, ]
seconddf <- df[seq_len(nrow(df))%%2 == 0, ]

在此之后,只需删除所有条目均为NAs的列,然后将dfs合并,同时处理两个dfs在同一位置都有非NA值的情况(例如,通过取两个值的平均值)。

我在现实生活中还需要采取一些额外的步骤,这个例子的简单性并没有涵盖,包括:

  1. 对df进行排序并重置索引,以便在两个dfs中保持df中条目的位置一致,就像这样:
df <- df[order(df$Name), ]
rownames(df) <- NULL 

检查每个名称是否恰好出现了两次,不多也不少:
#Using dplyr 
library(dplyr)
df %>% 
     count(Name) %>%
     filter(n!=2)
# Should return 0 rows 

如果有超过两个或少于两个条目的情况,我会执行以下操作:
more <- df %>% 
        count(name) %>%
        filter(n>2)

df_more_than_two <- df[df$Name %in% more$Name]

# Change sign in filter function to < 2 for those with only one entry 

我随后创建了三个数据框(一个条目、两个条目和三个条目的那些数据框),但本质上执行了相同的步骤。

不是我给你点的踩,但可能的解释是:在你的问题中,"为了未来读者"这样的编辑会更好。自己回答问题是被看作不受欢迎的行为。而且,这个具体的回答也更像是对你自己问题的一个状态更新,而不是一个真正的回答。 - Omniswitcher

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