我的数据框看起来像:
d<-data.frame(id=(1:9),
grp_id=(c(rep(1,3), rep(2,3), rep(3,3))),
a=rep(NA, 9),
b=c("No", rep(NA, 3), "Yes", rep(NA, 4)),
c=c(rep(NA,2), "No", rep(NA,6)),
d=c(rep(NA,3), "Yes", rep(NA,2), "No", rep(NA,2)),
e=c(rep(NA, 7), "No", NA),
f=c(NA, "No", rep(NA,3), "No", rep(NA,2), "No"))
>d
id grp_id a b c d e f
1 1 1 NA No <NA> <NA> <NA> <NA>
2 2 1 NA <NA> <NA> <NA> <NA> No
3 3 1 NA <NA> No <NA> <NA> <NA>
4 4 2 NA <NA> <NA> Yes <NA> <NA>
5 5 2 NA Yes <NA> <NA> <NA> <NA>
6 6 2 NA <NA> <NA> <NA> <NA> No
7 7 3 NA <NA> <NA> No <NA> <NA>
8 8 3 NA <NA> <NA> <NA> No <NA>
9 9 3 NA <NA> <NA> <NA> <NA> No
在每个组(grp_id)中,只有1&#34;是&#34;或&#34;否&#34;与每个列a:f。
相关联的值我想为每个grp_id创建一行,以获得如下所示的数据框:
grp_id a b c d e f
1 NA No No <NA> <NA> No
2 NA Yes <NA> Yes <NA> No
3 NA <NA> <NA> No No No
我认识到tidyr包可能是最好的工具,第一步可能是
d %>%
group_by(grp_id) %>%
summarise()
我非常感谢您对汇总中的命令或任何解决方案的帮助。谢谢。
答案 0 :(得分:1)
我们可以使用summarise_at
并对第一个非NA元素进行子集
library(dplyr)
d %>%
group_by(grp_id) %>%
summarise_at(2:7, funs(.[!is.na(.)][1]))
# A tibble: 3 x 7
# grp_id a b c d e f
# <dbl> <lgl> <fctr> <fctr> <fctr> <fctr> <fctr>
#1 1 NA No No <NA> <NA> No
#2 2 NA Yes <NA> Yes <NA> No
#3 3 NA <NA> <NA> No No No
在示例数据集中,列&#39; a&#39;到了&#39; f&#39;都是factors
,其中一些只有&#39;否&#39;水平。如果需要使用具有相同levels
的所有列进行标准化,那么我们可能需要在factor
中使用levels
c('Yes', 'No')
来调用summarise_at
} {ie summarise_at(2:7, funs(factor(.[!is.na(.)][1], levels = c('Yes', 'No'))))
答案 1 :(得分:1)
我们可以使用aggregate
。没有包使用。
YN <- function(x) c(na.omit(as.character(x)), NA)[1]
aggregate(d[3:8], d["grp_id"], YN)
,并提供:
## grp_id a b c d e f
## 1 1 <NA> No No <NA> <NA> No
## 2 2 <NA> Yes <NA> Yes <NA> No
## 3 3 <NA> <NA> <NA> No No No
上面给出了字符列。如果您更喜欢因子列,请使用:
YNfac <- function(x) factor(YN(x), c("No", "Yes"))
aggregate(d[3:8], d["grp_id"], YNfac)
注意: YN的其他替代实现是:
YN <- function(x) sort(as.character(x), na.last = TRUE)[1]
YN <- function(x) if (all(is.na(x))) NA_character_ else na.omit(as.character(x))[1]
library(zoo)
YN <- function(x) na.locf0(as.character(x), fromLast = TRUE)[1]
答案 2 :(得分:1)
您已收到一些好的答案,但它们都没有实际使用tidyr
包。 (summarize()
和summarize_at()
系列函数来自dplyr
。)
事实上,tidyr
- 仅针对您的问题的解决方案是非常可行的。
d %>%
gather(col, value, -id, -grp_id, factor_key=TRUE) %>%
na.omit() %>%
select(-id) %>%
spread(col, value, fill=NA, drop=FALSE)
唯一困难的部分是确保您在输出中获得a
列。对于您的示例数据,它完全是NA
。诀窍是factor_key=TRUE
的{{1}}参数和gather()
的{{1}}参数。如果没有设置这两个参数,则输出将没有drop=FALSE
列,并且只包含至少有一个非spread()
条目的列。
以下是对其工作原理的描述:
a
整理您的数据 - 它有效地用新列NA
和gather(col, value, -id, -grp_id, factor_key=TRUE) %>%
替换列a
- f
,形成一个长格式的“整洁”数据框。 col
列中的条目为字母value
- col
。由于我们使用了a
,因此此列是因子,其中包含级别,而不仅仅是字符向量。
f
这将删除长数据中的所有factor_key=TRUE
值。
na.omit() %>%
这消除了NA
列。
select(-id) %>%
这会重新扩展数据,使用id
列中的值来定义新列名称,并使用spread(col, value, fill=NA, drop=FALSE)
列中的值来填充新列的条目。如果缺少数据,则会使用值col
(此处为value
)。而fill
表示当NA
是一个因素时,每个级别的因子都会有一列,无论该级别是否出现在数据中。将drop=FALSE
设置为一个因素,将col
作为输出列。
我个人觉得这种方法比需要子集或col
的方法更具可读性。此外,如果您的数据实际上并不是热门的话,这种方法将失败,而其他方法可能会“起作用”并为您提供意外的输出。这种方法的缺点是输出列a
- lapply
不是因子,而是字符向量。如果您需要因子输出,您应该能够(未经测试)
a
在f
和mutate(value = factor(value, levels=c('Yes', 'No', NA))) %>%
函数之间的任何位置,以确保因子输出。