我有一个数据帧,其中唯一的主题ID为所有参与者重复两次。下面的数据似乎由一列组成,其中的值是其中一个条目,还有一列,其中有一个条目的值(虽然这是不确定的,我使用的方法应该考虑到这不是真的可能性)。下面是一个例子:
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(在上面的示例中是Names),并为每个条目创建单独的数据框架。像这样:
#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)
然后我将继续使用合并之类的东西来组合dfs,与by="Name"
。我的原始数据集很大,这不是特别有效或优雅。有人能提出改进建议吗?
可以按组保留第一个值,不包括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
如果每个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
顺便说一句,为了将来的读者,我最终做的是通过奇数/偶数索引获取每个ID的每个条目,并创建两个数据框,如下所示:
firstdf <- df[seq_len(nrow(df))%%2 == 1, ]
seconddf <- df[seq_len(nrow(df))%%2 == 0, ]
在这一点之后,它只是一个删除所有条目都是NAs的列的问题,然后合并dfs,同时处理两个dfs在相同位置具有非na值的情况(例如,通过取两个值的平均值)。
在我的现实生活中,我还必须采取一些额外的步骤,而这个例子的简单性并没有捕捉到这些步骤,包括:
- 对df进行排序并重置索引,以便df中条目的位置在两个dfs中保持一致,如下所示:
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
然后我创建了三个数据帧(包含1个条目,包含2个条目和包含3个条目),但基本上执行了相同的步骤