2012-11-21 183 views
1

我有一个由三列组成的数据帧(请参阅代码示例)。第一列包含类别(a),第二列是观测数量(b),第三列是这些观测值的平均值(c)。R:在条件下替换数据帧中的值

#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不适用

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

#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

所以,很显然,这将不起作用了...

任何人都可以帮我重新安排功能吗?我很新的节目,它仍然是一个很大的挑战,我设计短期和goodworking功能...

编辑:

我想输出是: [1] 1.000000 2.000000 3.20000 4.000000 5.000000 6.000000 7.000000 5.000000

使得组aaa的平均(3.20000)代入AAA NA值和组DDD的平均值(5.0000000)代入NA在DDD ...

+0

目前尚不清楚你想要的最后一种情况下可能返回的。 –

+0

他会想'[1] 1.000000 2.000000 3.333333 4.000000 5.000000 6.000000 7.000000 5.00000'我相信。 –

+0

考虑到问题的陈述,我不认为所提供的答案都是正确的。如果三个项目在值为'= c(1,2,7)'的类别“aaa”中,计数为“= c(3,4,3)',那么加权平均值不是3.3333,而是3.2。如果我对问题陈述的理解是错误的,那么也许可以修改这个问题来澄清为什么计数不能用于计算平均值? –

回答

1

为了与多个列进行一个类别,你将需要使用的东西,分割数据帧,然后作用于组件内工作。 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 

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

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 
+0

为我工作。甚至没有考虑先拆分它,但这是完全合理的。谢谢! – Joschi

0

I”米不太清楚你的意思,但如果你的意思是包括所有这样的行,你可以在%中使用%。

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

0

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"),...