【问题标题】:R loop through multiple sub groups with using functionsR使用函数循环遍历多个子组
【发布时间】:2018-11-20 20:16:29
【问题描述】:

您好,我正在尝试学习如何遍历数据框中的多个组并应用某些算术运算。我没有编程背景,并且正在努力遍历多个条件。

我的数据如下所示:

Event = c(1,1,1,1,1,2,2,2,2,2)
Indiv1=c(4,5,6,11,45,66,8,9,32,45)
Indiv2=c(7,81,91,67,12,34,56,78,90,12)
Category=c(1,1,2,2,2,1,2,2,1,1) 
Play_together=c(1,0,1,1,1,1,1,1,0,1)
Money=c(23,11,78,-9,-12,345,09,43,21,90)
z = data.frame(Event,Indiv1,Indiv2,Category,Play_together,Money)

我想做的是查看每个事件和每个类别,并在 Play_together == 1 的情况下取 Money 的平均值。当 Play_together==0 时,我想申请 Money/100。

我知道循环看起来像下面这样:

 for i in 1:nrow(z){
     #loop for event{
         #loop for Category{
              #Define avg or division function
         }
     }
 }

但是,我似乎无法使用嵌套循环来实现这一点。我看到另一个使用 dplyr 包的帖子(链接:apply function for each subgroup)。我想知道是否有人可以帮助我在不使用任何包的情况下实现这一点(我知道与使用 R 包相比,这可能需要更长的时间)。我正在尝试学习 R,这是我第一次使用嵌套循环。

最终输出将如下所示:

对于事件 1,以下情况成立:

a) 对于类别 1:

Play_together ==1 在第 1 行;我们取货币价值的平均值,因此最终输出 = 23/1= 23

Play_together==0 在第 2 行;我们拿钱/100=0.11

b) 对于第 2 类: Play_together == 1 用于所有观察。我们对所有三个观察结果都取 avg Money。

这同样适用于事件 2。在我的实际数据集中,我的事件 = 600,类别数量在 1 到 10 之间。有些事件可能只有 1 个类别,最多有 10 个类别。所以任何功能都需要非常灵活。我的数据集中的观察总数约为 150 万,因此循环过程中的任何更改以减少执行操作所需的时间都将非常有帮助(尽管在这个阶段我的优先级是循环过程本身)。

如果你能告诉我如何使用嵌套循环并简要解释这些步骤,那将是一个很大的帮助。非常感谢。

【问题讨论】:

  • 您的示例输出与示例数据不同...(具有事件“3”)
  • 感谢@Wimpel 指出这一点。我不得不多次更改示例数据。我现在改了。
  • 你不应该为此使用循环,使用 dplyrdata.table 包,或在基础 R 中 aggregateby
  • 这个最终用途是在吉布斯抽样框架(贝叶斯统计)中,我需要遵循这个程序。我试图以一种非常简单的方式分解问题,以便我可以学习如何在 R 中使用嵌套循环。@Gregor
  • 除非您想强制 R 以蜗牛的速度移动,否则您需要尽可能使用矢量化。所以不要遍历每一行,至少在类别级别开始你的外部循环。你可以让你的外循环超过类别,你的内循环超过事件,然后显示一个尝试!当你展示的只是一个没有任何填充物的裸露骨架时,真的很难知道你需要什么帮助。

标签: r loops data-manipulation


【解决方案1】:

这样的事情会做吗? 我知道它正在使用 dplyr,但该软件包是为此类工作制作的 ;-)

Event = c(1,1,1,1,1,2,2,2,2,2)
Indiv1=c(4,5,6,11,45,66,8,9,32,45)
Indiv2=c(7,81,91,67,12,34,56,78,90,12)
Category=c(1,1,2,2,2,1,2,2,1,1) 
Play_together=c(1,0,1,1,1,1,1,1,0,1)
Money=c(23,11,78,-9,-12,345,09,43,21,90)
z = data.frame(Event,Indiv1,Indiv2,Category,Play_together,Money)

library(dplyr)

df_temp <- z %>%
  group_by( Event, Category, Play_together ) %>%
  summarise( money_mean = mean( Money ) ) %>%
  mutate( final_output = ifelse( Play_together == 0, money_mean / 100, money_mean )) %>%
  select( -money_mean )

df <- z %>%
  left_join(df_temp, by = c("Event", "Category", "Play_together" )) %>%
  arrange(Event, Category)

【讨论】:

  • 我喜欢这个解决方案,因为它很整洁,但我担心你会丢失很多关于 indiv1 和 indiv2 的信息
  • 是的,但这不是您当前的解决方案...我知道您可以重新加入。
  • 它给了我想要的结果。但是,如果您还可以告诉我如何通过循环来实现它,那就太棒了。我问这个问题的原因是我想学习如何使用循环来实现它(不借助 dplyr 等函数)。 @Wimpel
  • @Prometheus 我永远不会推荐为此使用循环.. 何必呢?不需要 for 循环是 R 的众多优势之一
  • @Wimpel 这部分的最终用途是将其用作贝叶斯回归模型中吉布斯采样框架的一部分,我需要为每个观察生成不同的潜在值。我试图将问题分解为一种非常简单的形式,这样我就不会在这里过度复杂化我的问题。我会尝试看看这个解决方案是否适用于我的最终模型。
【解决方案2】:

考虑基本 R 的 bytapply 的面向对象包装器旨在按因子对数据帧进行子集化,但与 split 不同的是,它可以将子集传递到定义的函数中。然后,使用 ifelseFinal_Output 字段运行条件逻辑。最后,为最终对象堆叠所有子集数据帧。

# LIST OF DATAFRAMES
by_list <- by(z, z[c("Event", "Category")], function(sub) {      
  tmp <- subset(sub, Play_together==1)
  sub$Final_Output <- ifelse(sub$Play_together == 1, mean(tmp$Money), sub$Money/100)
  return(sub)      
})

# APPEND ALL DATAFRAMES
final_df <- do.call(rbind, by_list)    
row.names(final_df) <- NULL

final_df 
#    Event Indiv1 Indiv2 Category Play_together Money Final_Output
# 1      1      4      7        1             1    23        23.00
# 2      1      5     81        1             0    11         0.11
# 3      2     66     34        1             1   345       217.50
# 4      2     32     90        1             0    21         0.21
# 5      2     45     12        1             1    90       217.50
# 6      1      6     91        2             1    78        19.00
# 7      1     11     67        2             1    -9        19.00
# 8      1     45     12        2             1   -12        19.00
# 9      2      8     56        2             1     9        26.00
# 10     2      9     78        2             1    43        26.00

【讨论】:

    猜你喜欢
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 2017-02-05
    • 2018-01-20
    • 2019-07-10
    相关资源
    最近更新 更多