【问题标题】:how to calculate mean based on conditions in for loop in r如何根据r中for循环中的条件计算平均值
【发布时间】:2021-06-19 09:35:24
【问题描述】:

我有一个我认为很简单的问题,但我想不通!我有一个包含多列的数据框。这是一个通用示例:

colony = c('29683','25077','28695','4865','19858','2235','1948','1849','2370','23196')
age = c(21,23,4,25,7,4,12,14,9,7)
activity = c(19,45,78,33,2,49,22,21,112,61)
test.df = data.frame(colony,age,activity)
test.df

我希望 R 根据数据框中的菌落年龄计算平均活动。具体来说,我希望它只计算与该行中的菌落年龄相同或更老的菌落的平均活动,不包括该行中菌落的活动。例如,菌落 29683 是 21 岁。对于我的这行数据,我想要 21 岁以上的菌落的平均活动。这将包括殖民地 25077 和殖民地 4865;平均值为 (45+33)/2 = 39。我希望 R 通过识别当前行中菌落的年龄来对数据的每一行执行此操作,然后识别比该菌落更老的菌落,然后平均这些菌落的活动。

我尝试在 R 的 for 循环中执行此操作。这是我使用的代码:

test.avg = vector("numeric",nrow(test.df))`
for (i in 1:10){ 
test.avg[i] <- mean(subset(test.df$activity,test.df$age >= age[i])[-i])
}

R 返回一个值列表,其中一半是正确的,另一半不是(我什至不确定它是如何计算出这些不正确的数字的......)。与它们在数据框中的列出方式相比,正确的数字也是无序的。它显然能够为循环的某些迭代做正确的事情,但不是全部。如果有人可以帮助我编写代码,我将不胜感激!

【问题讨论】:

    标签: r for-loop subset mean


    【解决方案1】:
    colony = c('29683','25077','28695','4865','19858','2235','1948','1849','2370','23196')
    age = c(21,23,4,25,7,4,12,14,9,7)
    activity = c(19,45,78,33,2,49,22,21,112,61)
    test.df = data.frame(colony,age,activity)
    
    library(tidyverse)
    test.df %>% 
      mutate(result = map_dbl(age, ~mean(activity[age > .x])))
    #>    colony age activity   result
    #> 1   29683  21       19 39.00000
    #> 2   25077  23       45 33.00000
    #> 3   28695   4       78 39.37500
    #> 4    4865  25       33      NaN
    #> 5   19858   7        2 42.00000
    #> 6    2235   4       49 39.37500
    #> 7    1948  12       22 29.50000
    #> 8    1849  14       21 32.33333
    #> 9    2370   9      112 28.00000
    #> 10  23196   7       61 42.00000
    
    # base
    test.df$result <- with(test.df, sapply(age, FUN = function(x) mean(activity[age > x])))
                             
    test.df 
    #>    colony age activity   result
    #> 1   29683  21       19 39.00000
    #> 2   25077  23       45 33.00000
    #> 3   28695   4       78 39.37500
    #> 4    4865  25       33      NaN
    #> 5   19858   7        2 42.00000
    #> 6    2235   4       49 39.37500
    #> 7    1948  12       22 29.50000
    #> 8    1849  14       21 32.33333
    #> 9    2370   9      112 28.00000
    #> 10  23196   7       61 42.00000
    

    reprex package (v1.0.0) 于 2021-03-22 创建

    【讨论】:

      【解决方案2】:

      您的解决方案中的问题是索引将应用于原始 data.frame,但您将其子集化,因此它不再匹配。

      尝试这样的操作:首先找到最小年龄,然后排除当前索引并计算年龄 >= 预先计算的最小年龄的病例的平均活动。

      for (i in 1:10){ 
        test.avg[i] <- {amin=age[i]; mean(subset(test.df[-i,], age >= amin)$activity)}
      }
      

      【讨论】:

      • 天哪,这成功了!!!!太感谢了!!我在这方面工作的时间比我想承认的要长,但这正是我所需要的(我实际上理解这个解决方案背后的逻辑)!!
      【解决方案3】:

      您可以使用 map_df :

        library(tidyverse)
        test.df  %>% 
              mutate(map_df(1:nrow(test.df), ~
                           test.df %>% 
                           filter(age >= test.df$age[.x]) %>% 
                           summarise(av_acti= mean(activity))))
      

      【讨论】:

      • OP 特别想排除他正在计算平均活动的行中的菌落活动。您可以在管道中执行以下操作:mutate(test.df, map_df(1:nrow(test.df), ~ test.df %&gt;% mutate(amin = test.df$age[.x]) %&gt;% "["(.,-.x,) %&gt;% filter(age &gt;= amin) %&gt;% summarise(av_acti= mean(activity)))) 以获得他正在寻找的结果。
      猜你喜欢
      • 2021-06-20
      • 1970-01-01
      • 2021-02-02
      • 1970-01-01
      • 2016-12-22
      • 1970-01-01
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多