【问题标题】:operating on sub group inside data frame very slow在数据帧内的子组上操作非常慢
【发布时间】:2015-02-03 04:59:20
【问题描述】:

我有一个数据框,其中包含有关一周中四天由不同人(由 id 列表示)完成的俯卧撑数量的数据。我必须执行以下操作

  • 查找每个 id 的俯卧撑的运行总和(累积成本)
  • 我想在每一天添加一列,显示第二天完成的俯卧撑数量。 (注意:由于在最后一天,我们不知道第二天做了多少俯卧撑,我们只考虑到第 n-1 行))

我首先按 (id,dayofweek) 对列进行“排列”,然后创建一个临时数据框,在该数据框上迭代地执行所有这些操作。这样做的问题是,在一个巨大的数据帧上,它非常非常慢。有没有更优雅的方式来做这两件事。请我的代码和下面的输入输出数据框

输入(排列后)

> df
   id dayofweek pushupcount cumulativepushups nextdaypushupcount
1   1      day1         100                 0                  0
2   1      day2         240                 0                  0
3   1      day3         200                 0                  0
4   1      day4         170                 0                  0
5   2      day1         220                 0                  0
6   2      day2         190                 0                  0
7   2      day3         300                 0                  0
8   2      day4         150                 0                  0
9   3      day1         260                 0                  0
10  3      day2         160                 0                  0
11  3      day3         200                 0                  0
12  3      day4         210                 0                  0

输出

> df
   id dayofweek pushupcount cumulativepushups nextdaypushupcount
1   1      day1         100               100                240
2   1      day2         240               340                200
3   1      day3         200               540                170
5   2      day1         220               220                190
6   2      day2         190               410                300
7   2      day3         300               710                150
9   3      day1         260               260                160
10  3      day2         160               420                200
11  3      day3         200               620                210

创建数据

#creating data
id = c(1,2,3,2,1,2,3,1,3,2,1,3)
dayofweek = c('day1','day2','day3','day1','day2','day3','day4','day4','day1','day4','day3','day2')
pushupcount = c(100,190,200,220,240,300,210,170,260,150,200,160)
df =  data.frame(id,dayofweek,pushupcount,stringsAsFactors = FALSE)

代码

#arranding data in increasing order of day of week for each id
library('plyr')
df = arrange(df,id,dayofweek)

#adding the new columns
df$cumulativepushups = 0;
df$nextdaypushupcount = 0;

finaldf = NULL;

#the 'cumulativepushups' column is basically a running sum for each id
#the 'nextdaypushupcount' column is number of pushups for that id for the next day
 (NOTE that since on the last day, we do not know how many pushups were done the next day, we consider only till rows n-1)
uniqueid = unique(df$id)
for(i in 1:length(uniqueid))
{
  tempdf = df[which(df$id == uniqueid[i]),]

  for(j in 1:(nrow(tempdf)-1))
  {
    if(j == 1)
    {
      tempdf[j,]$cumulativepushups = tempdf[j,]$pushupcount
    }
    else
    {
      tempdf[j,]$cumulativepushups = tempdf[j-1,]$cumulativepushups + tempdf[j,]$pushupcount
    }

    tempdf[j,]$nextdaypushupcount = tempdf[j+1,]$pushupcount

    finaldf = rbind(finaldf,tempdf[j,])
  }
}
df = finaldf

谢谢。

【问题讨论】:

    标签: r rstudio


    【解决方案1】:

    你可以试试dplyr。按“id”、“dayofweek”(arrange(..))对数据集进行排序。在按“id”分组后,使用lead 创建“nextdaypushupcount”。删除最后一个 观察每组 (slice(..))。获取“pushupcount”的cumsum 来创建“cumulativepushups”。

    library(dplyr)
    df1 <- arrange(df, id, dayofweek)%>%
               group_by(id) %>% 
               mutate(nextdaypushupcount=lead(pushupcount)) %>%
               slice(-n())%>% 
               mutate(cumulativepushups=cumsum(pushupcount))
    df1 
     #    id dayofweek pushupcount nextdaypushupcount cumulativepushups
     #1  1      day1           100                240               100
     #2  1      day2           240                200               340
     #3  1      day3           200                170               540
     #4  2      day1           220                190               220
     #5  2      day2           190                300               410
     #6  2      day3           300                150               710
     #7  3      day1           260                160               260
     #8  3      day2           160                200               420
     #9  3      day3           200                210               620
    

    数据

    id <- c(1,2,3,2,1,2,3,1,3,2,1,3)
    dayofweek <- c('day1','day2','day3','day1','day2','day3','day4','day4',
     'day1','day4','day3','day2')
    pushupcount <- c(100,190,200,220,240,300,210,170,260,150,200,160)
    df <-  data.frame(id,dayofweek,pushupcount,stringsAsFactors = FALSE)
    

    【讨论】:

    • 非常感谢您的回答和解释。我仍然在某些地方感到困惑,所以我能够从 dplyr 文档中理解一些事情。不过我有几个问题。 1.我们需要做内连接吗?我们可以只做 df1 = attach(df,id,dayofweek) 吗(我得到相同的 o/p)? 2.是 %>% dplyr 语法吗?它有什么作用?由于字符的原因,无法用谷歌搜索这个:)
    • @IAMTubby 我认为你说得很好。我没有仔细查看数据集。是的,您不需要 inner_join。您可以跳过第一步,从排列开始。 %&gt;% 是连接 LHS 和 RHS 的链运算符。您可以通过?'%&gt;%'查看文档
    • 我已经能够有效地使用 dplyr 包,并且能够使用选项(dplyr.width = Inf)打印出所有列。但是,我有一个问题。为什么 class(df1) 说“grouped_df”、“tbl_df”、“tbl”、“data.frame”。我怎样才能让它只是一个数据框,所以我感觉更舒服。 (我可以像使用数据框一样使用这个对象,除了类(df1)的输出之外看不出任何区别)
    • @IAMTubby Just do df2 &lt;- as.data.frame(df1) dplyr 添加了一些类属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 2020-12-31
    • 2021-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多