R 折叠行,其中一些行全部为NA,其他行与某些NAs不相交

R 折叠行,其中一些行全部为NA,其他行与某些NAs不相交,r,aggregate,na,R,Aggregate,Na,我有一个简单的数据框架: 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     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
s不遵循简单模式,除了
NA
s是不相交的,每个
ID
正好有3行)

第一步:删除只有
NA
值的行

表面上看这很简单,但我遇到了一些问题

complete.cases(DF)
返回all
FALSE
,因此我不能像在
DF[complete.cases(DF),]
中那样用它来删除所有
NA
s的行。这是因为所有行至少包含一个
NA

由于
NA
s想要自我传播,因此使用
is.NA
的其他方案也因同样的原因失败

第二步:将其余两行折叠为一行

考虑使用
aggregate
之类的方法来实现这一点,但必须有一种比这更简单的方法,它根本不起作用

谢谢你的建议。

简单的方法是:

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)))

temp以下是一些聚合尝试:

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。在进行任何分组之前,忽略整个数据,它将删除
dat
的每一行,因为它们都至少包含一个
na
值。试试看:
nrow(na.omit(dat))
返回
0
。因此,在这种情况下,在
aggregate
中使用
na.pass
,然后使用
na.ommit
跳过通过的
na
s

或者,不要使用公式界面并指定要手动聚合的列:

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
试一试


编辑:为了说明某个
ID
的一列包含所有
NAs
的情况,我们需要
sum\u NA()
函数,如果所有
NAs
都是

txt <- "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     NA      30      NA      NA
        2     NA      NA      35      40"
DF <- read.table(text = txt, header = TRUE)

# original code
DF %>% 
  group_by(ID) %>% 
  summarise_each(funs(sum(., na.rm = TRUE)))

# `summarise_each()` is deprecated.
# Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
# To map `funs` over all variables, use `summarise_all()`
# A tibble: 2 x 5
     ID  Col1  Col2  Col3  Col4
  <int> <int> <int> <int> <int>
1     1     5    10    15    20
2     2     0    30    35    40

sum_NA <- function(x) {if (all(is.na(x))) x[NA_integer_] else sum(x, na.rm = TRUE)}

DF %>%
  group_by(ID) %>%
  summarise_all(funs(sum_NA))

DF %>%
  group_by(ID) %>%
  summarise_if(is.numeric, funs(sum_NA))

# A tibble: 2 x 5
     ID  Col1  Col2  Col3  Col4
  <int> <int> <int> <int> <int>
1     1     5    10    15    20
2     2    NA    30    35    40
txt%
总结每一项(funs(sum(,na.rm=TRUE)))
#“summary_each()”已弃用。
#改为使用'summary_all()'、'summary_at()'或'summary_if()'。
#要在所有变量上映射'funs',请使用'summary_all()`
#一个tibble:2x5
ID Col1 Col2 Col3 Col4
1     1     5    10    15    20
2     2     0    30    35    40
总额%
分组依据(ID)%>%
总结所有(funs(sum_NA))
DF%>%
分组依据(ID)%>%
总结如果(是数字,funs(总和))
#一个tibble:2x5
ID Col1 Col2 Col3 Col4
1     1     5    10    15    20
2 2 NA 30 35 40

这是一种数据表方法,它在列之间使用
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

由于
dplyr 1.0.0
,您还可以(使用@Khashaa提供的数据):

df%>%
分组依据(ID)%>%
总结(跨越所有内容(),~first(na.省略())
ID Col1 Col2 Col3 Col4
1     1     5    10    15    20
2 2 NA 30 35 40

数据总是100%数字吗?相关:每个组的每列中总是有一个非NA值,还是会有更多?更多!无论好坏,省略是聪明的。优于
sum
,适用于非数字数据。我将谨慎地编辑…如果任何列都有某个ID的所有NAs,则此解决方案不起作用。我认为
对每个列进行总结(funs(na.omit(.))
也有效是,但我认为,如果任何一列有两个以上的非NA观测值,那么这将产生一个稍微不协调的结果。如果任何一列在某个
ID
上都有
NA
s,那么这个解决方案就不起作用。例如,将
Col1
中的
ID=2
替换为
NA
。而
funs(na.omit(.))
将抛出错误
error:列Col1必须是长度1(摘要值),而不是0
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
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