R:在一定条件下替换数据帧中的值



我得到了一个由三列组成的数据帧(请参阅代码中的示例)。第一列包含类别(a),第二列包含观测次数(b),第三列包含这些观测的平均值(c)。

#create a test df
a<-factor(c("aaa","aaa","aaa","ddd","eee","ddd","aaa","ddd"))
b<-c(3,4,1,3,5,7,3,2)
c<-c(1,2,NA,4,5,6,7,NA)
df.abc<-data.frame(a=a,b=b,c=c)
df.abc

如果观察次数为1或2,则将条目标记为缺失值(NA)。

因此,我的函数的目的是用每个类别的平均值来代替这些缺失的值。

我花了一段时间,但我得到了一个函数,它将所有缺失的值替换为一个类别(如果观察值为1)。它看起来像这样:

#function to substitue the missing values in row c by their means 
#according to their categories
function.abc<-function(x){
ifelse(
(df.abc[,1]==x)&(df.abc[,2]==1),
mean(df.abc$c[df.abc$a ==x],na.rm=TRUE),
df.abc[,3]
)
}

测试此功能:

#test the function for the category "ccc"
function.abc("aaa")

它工作得很好(但只是平均值,而不是平均值)输出为:

[1] 1.000000 2.000000 3.333333 4.000000 5.000000 6.000000 7.000000 NA

现在我的问题是,我有很多类别(n=32),我试图将这个函数应用于包含我的类别的向量。在这种情况下,一个简单的例子是:

#test the function for a testvector
test.vector<-c("aaa","ddd")
function.abc(test.vector)

输出为:

[1] 1.0 2.0 4.5 4.0 5.0 6.0 7.0 NA-

很明显,这不会奏效。。。

有人能帮我重新安排一下吗?我对编程还很陌生,设计短而有效的函数对我来说仍然是一个巨大的挑战。。。

编辑:

我希望输出为:[1] 1.000000 2.000000 3.20000 4.000000 5.000000 6.000000 7.000000 5.000000

使得组aaa的平均值(3.20000)代替了aaa中的NA值,并且组ddd的平均数(50000000)代替了ddd中的NA。。。

为了在一个类别中同时处理多个列,您需要使用拆分数据帧然后处理组件的东西。lapply( split(df, fac), function(x) {...})范式对此效果良好。或者您可以使用transformplyr软件包。

> lapply( split( df.abc, df.abc$a), 
function(dfrm) { dfrm[is.na(dfrm$c), "c"] <- 
weighted.mean(dfrm[!is.na(dfrm$c) , "c"], dfrm[!is.na(dfrm$c), "b"])
dfrm} )  
# need to evaluate dfrm in order to return the full value.
$aaa
a b   c
1 aaa 3 1.0
2 aaa 4 2.0
3 aaa 1 3.2
7 aaa 3 7.0
$ddd
a b   c
4 ddd 3 4.0
6 ddd 7 6.0
8 ddd 2 5.4
$eee
a b c
5 eee 5 5

然后,您可以使用`do.call:来rbind它们

do.call( rbind, lapply( split( df.abc, df.abc$a), 
function(dfrm) { dfrm[is.na(dfrm$c), "c"] <-
weighted.mean(dfrm[!is.na(dfrm$c) , "c"], dfrm[!is.na(dfrm$c), "b"])
dfrm} ) )
a b   c
aaa.1 aaa 3 1.0
aaa.2 aaa 4 2.0
aaa.3 aaa 1 3.2
aaa.7 aaa 3 7.0
ddd.4 ddd 3 4.0
ddd.6 ddd 7 6.0
ddd.8 ddd 2 5.4
eee   eee 5 5.0

我不太确定你的意思,但如果你想包括所有这样的行,你可以在%中使用%。

function.abc<-function(x){
ifelse(
(df.abc[,1] %in% x)&(df.abc[,2]==1),
mean(df.abc$c[df.abc$a %in% x],na.rm=TRUE),
df.abc[,3]
)
}
> function.abc("aaa")
[1] 1.000000 2.000000 3.333333 4.000000 5.000000 6.000000 7.000000       NA
> test.vector<-c("aaa","ddd")
> function.abc(test.vector)
[1]  1  2  4  4  5  6  7 NA

最后一个元素是NA,因为列"b"不是1。

CatMeans <- tapply(df.abc$c, df.abc$a, function(x) mean(x, na.rm==T))将为您分类。

aaa      ddd      eee 
3.333333 5.000000 5.000000 

因此,为他们所有人做这件事:

> CatMeans <- tapply(df.abc$c, df.abc$a, function(x) mean(x, na.rm==T))
> ifelse(is.na(df.abc$c), CatMeans[df.abc$a], df.abc$c)
[1] 1.000000 2.000000 3.333333 4.000000 5.000000 6.000000 7.000000 5.000000

我相信你可以把它变成一个函数。如果你只想要"aaa""ddd",那么你可以有ifelse(is.na(df.abc$c) & df.abc$a %in% c("aaa","ddd"),...

最新更新