用组值替换NA值

9
我有一个数据框,其中包括5个家庭的20个人。 家庭内的一些人缺少是否拥有医疗卡的数据。 我希望为这些人提供与其家庭内其他人相同的值(而不是NA值),这个值是二进制值0或1。
我尝试了下面的代码,我认为它是正确的一步,但并不完全正确,因为a)如果每个家庭的第一个med_card值为NA,则该代码无法运行; b)它不能替换家庭1中所有人的NA值。
DF<- ddply(df, .(hhold_no), function(df) {df$med_card[is.na(df$med_card)] <- head(df$med_card, na.rm=TRUE); return(df)})

任何指针都将不胜感激,谢谢。
样例数据框。
df
   person_id hhold_no med_card
1          1        1        1
2          2        1        1
3          3        1       NA
4          4        1       NA
5          5        1       NA
6          6        2        0
7          7        2        0
8          8        2        0
9          9        2        0
10        10        3       NA
11        11        3       NA
12        12        3       NA
13        13        3        1
14        14        3        1
15        15        4        1
16        16        4        1
17        17        5        1
18        18        5        1
19        19        5       NA
20        20        5       NA

并编写代码使其可用

person_id<-as.numeric(c(1:20))
hhold_no<-as.numeric(c(1,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,5,5,5,5))
med_card<-as.numeric(c(1,1,NA,NA,NA,0,0,0,0,NA,NA,NA,1,1,1,1,1,1,NA,NA))
df<-data.frame(person_id,hhold_no, med_card)

期望输出。
df
   person_id hhold_no med_card med_card_new
1          1        1        1            1
2          2        1        1            1
3          3        1       NA            1
4          4        1       NA            1
5          5        1       NA            1
6          6        2        0            0
7          7        2        0            0
8          8        2        0            0
9          9        2        0            0
10        10        3       NA            1
11        11        3       NA            1
12        12        3       NA            1
13        13        3        1            1
14        14        3        1            1
15        15        4        1            1
16        16        4        1            1
17        17        5        1            1
18        18        5        1            1
19        19        5       NA            1
20        20        5       NA            1
5个回答

10
尝试使用 ave,它可以将函数应用到组中。详见 ?ave,例如:
df$med_card_new <- ave(df$med_card, df$hhold_no, FUN=function(x)unique(x[!is.na(x)]))

#   person_id hhold_no med_card med_card_new
#1          1        1        1            1
#2          2        1        1            1
#3          3        1       NA            1
#4          4        1       NA            1
#5          5        1       NA            1
#6          6        2        0            0
#7          7        2        0            0
#8          8        2        0            0
#9          9        2        0            0

请注意,只有在家庭中不是所有值都为NA且不应该不同(例如,人1 == 1,人2 == 0)的情况下,此方法才可行。

谢谢!我曾经尝试过使用ave,但是我的尝试非常笨拙,无法让它为我工作。再次感谢! :) - user2363642

7

data.table 解决方案

library(data.table)
setDT(df)[, med_card2 := unique(med_card[!is.na(med_card)]), by = hhold_no]

#     person_id hhold_no med_card med_card2
#  1:         1        1        1         1
#  2:         2        1        1         1
#  3:         3        1       NA         1
#  4:         4        1       NA         1
#  5:         5        1       NA         1
#  6:         6        2        0         0
#  7:         7        2        0         0
#  8:         8        2        0         0
#  9:         9        2        0         0
# 10:        10        3       NA         1
# 11:        11        3       NA         1
# 12:        12        3       NA         1
# 13:        13        3        1         1
# 14:        14        3        1         1
# 15:        15        4        1         1
# 16:        16        4        1         1
# 17:        17        5        1         1
# 18:        18        5        1         1
# 19:        19        5       NA         1
# 20:        20        5       NA         1

6
这正是zoo包中na.aggregate函数所实现的内容(链接)。
library(zoo)

transform(df, med_card_new = na.aggregate(med_card, by = hhold_no))

这里使用了mean函数;但是,你可以指定任何你想要的函数。例如,如果你希望在一个组中所有的项都为NA时返回NA(而不是当给定一个长度为零的向量时,mean将返回NaN),那么:
meanNA <- function(x, ...) if (all(is.na(x))) NA else mean(x, ...)
transform(df, med_card_new = na.aggregate(med_card, by = hhold_no, FUN = meanNA))

谢谢,我以前从未见过这个。非常方便。 :) - user2363642
刚刚使用这个工具非常好,但是对于没有数据可以聚合的情况下得到了NaN。在将NaN正确转换为NA时遇到了麻烦,发现最好的方法是 df[is.na(df)] <- NA - cparmstrong
这就是mean的工作原理。如果你对一个长度为零的向量进行平均值计算,它会返回NaN。如果你不想这样,可以指定另一个函数。请参见上面添加的代码。 - G. Grothendieck

2
使用dplyr,您还可以使用group_by()函数,并利用带有na.rm参数的max函数返回每个组的所有数字。
library(dplyr)
df %>% group_by(hhold_no) %>% mutate(med_card_new = max(med_card, na.rm = T))

考虑到组中的非缺失值是数字且恒定的,您也可以使用meanmin而不是max


0

虽然有点晚了,但如果你正在处理一个数字列,请尝试这个:

require(data.table)

setDT(df)[,'record_year':=mean( med_card,na.rm = T),by = c('hhold_no')]

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