我有一个简单的数据框:
ID Col1 Col2 Col3 Col4
1 NA NA NA NA
1 5 10 NA NA
1 NA NA 15 20
2 NA NA NA NA
2 25 30 NA NA
2 NA NA 35 40
我想重新格式化:
ID Col1 Col2 Col3 Col4
1 5 10 15 20
2 25 30 35 40
(请注意:真实数据集有数千行,值来自生物数据 - NA
不遵循简单模式,除了NA
s是不相交的,是的每个ID
只有3行。
第一步:删除只有NA
个值的行。
表面上看起来很简单,但我遇到了一些问题。
complete.cases(DF)
会返回所有FALSE
,因此我无法使用此功能删除所有NA
的行,如DF[complete.cases(DF),]
中所示。这是因为所有行都包含至少一个NA
。
由于NA
想要自己传播,因此使用is.na
的其他方案由于同样的原因而失败。
第二步:将剩下的两行折叠成一行。
考虑使用像aggregate
之类的东西来解决这个问题,但必须有一个比this更简单的方法,这根本不起作用。
感谢您的任何建议。
答案 0 :(得分:16)
这是一种数据表方法,在列中使用na.omit()
,按ID分组。
library(data.table)
setDT(df)[, lapply(.SD, na.omit), by = ID]
# ID Col1 Col2 Col3 Col4
# 1: 1 5 10 15 20
# 2: 2 25 30 35 40
答案 1 :(得分:10)
尝试
library(dplyr)
DF %>% group_by(ID) %>% summarise_each(funs(sum(., na.rm = TRUE)))
修改:要考虑一列中某个NAs
的所有ID
的情况,我们需要sum_NA()
函数返回{{1}如果所有都是NA
NAs
答案 2 :(得分:6)
以下是几次合计尝试:
aggregate(. ~ ID, data=dat, FUN=na.omit, na.action="na.pass")
# ID Col1 Col2 Col3 Col4
#1 1 5 10 15 20
#2 2 25 30 35 40
由于aggregate
的公式接口默认在进行任何分组之前对整个数据使用na.omit
,因此它会删除dat
的每一行,因为它们都包含至少一个NA
1}}价值。试一试:nrow(na.omit(dat))
返回0
。因此,在这种情况下,请使用na.pass
中的aggregate
,然后使用na.omit
来跳过通过的NA
。
或者,不要使用公式界面并指定要手动聚合的列:
aggregate(dat[-1], dat[1], FUN=na.omit )
aggregate(dat[c("Col1","Col2","Col3","Col4")], dat["ID"], FUN=na.omit)
# ID Col1 Col2 Col3 Col4
#1 1 5 10 15 20
#2 2 25 30 35 40
答案 3 :(得分:1)
简单的方法是:
as.data.frame(lapply(myData[,c('Col1','Col2','Col3','Col4')],function(x)[!is.na(x)]))
但是如果不是所有列都具有相同数量的非NA
值,那么您需要像这样修剪它们:
temp <- lapply(myData[,c('Col1','Col2','Col3','Col4')],function(x)x[!is.na(x)])
len <- min(sapply(temp,length))
as.data.frame(lapply(temp,`[`,seq(len)))
答案 4 :(得分:0)
自dplyr 1.0.0
起,您也可以(使用@Khashaa提供的数据):
df %>%
group_by(ID) %>%
summarize(across(everything(), ~ first(na.omit(.))))
ID Col1 Col2 Col3 Col4
<int> <int> <int> <int> <int>
1 1 5 10 15 20
2 2 NA 30 35 40