【问题标题】:Looping with multiple subset() functions in R: Is there a more elegant / quicker way?在 R 中循环使用多个子集()函数:有没有更优雅/更快的方法?
【发布时间】:2020-06-25 19:40:33
【问题描述】:

我正在尝试在一个相当大的数据帧(大小 50,000rx 150c)上计算一些历史平均值,为此,我首先需要根据两个标准对数据进行子集化,然后对其中一个子集应用一些算术函数列。然后,我将结果写入另一个数据帧,作为特定时期内的新计数/平均值/加权平均值列。由于数据集的大小(以及我编码技能的限制),这需要很长时间,我的问题是,在 R 中是否有更好的方法来解决此类问题?

这是一个简单的例子来说明我想要做什么:

library(lubridate)

###  Create dataframe Df

date <- c("01/01/2020", "02/01/2020", "02/01/2020","02/01/2020", "03/01/2020", 
          "03/01/2020", "03/01/2020", "03/01/2020", "04/01/2020", "04/01/2020")
date <- dmy(date)
name <- c("john", "paul", "john", "peter", "peter", 
          "john", "andrew", "john", "peter", "peter")
visits <- c(1, 3, 2, 1, 3, 
            4, 6, 1 ,1, 9)
Df <- data.frame(date, name, visits)
Df


###  Create dataframe Df1

date1 <- c("01/01/2020", "02/01/2020", "03/01/2020", "04/01/2020")
date1 <- dmy(date1)
name1 <- c("john", "paul", "andrew", "peter")
totvisits <- c(0, 0, 0, 0)
Df1 <- data.frame(date1, name1, totvisits)
Df1

Df$name <- as.character(Df$name)
Df1$name1 <- as.character(Df1$name1)

在这个例子中,我想(对于 Df1 中的每一行 name1/date1 对)根据日期/名称子集 Df 并返回每个 'name1' 在每个 'date1' 值之前进行的访问次数,即通过求和日期

### loop 
for (i in 1:dim(Df1)[1]) {
  Df1[i, 3] <- sum(subset(Df, Df$name == Df1$name1[i] & Df$date <= Df1$date1[i])[,3])
}
Df1

### apply()
f <- function(x, y) {
  sum(subset(Df, (Df$name == x) & (Df$date <= y))[,3])
  }
Df1[, 3] <- mapply(f, x = Df1$name1, y = Df1$date1)
Df1

任何关于替代方法的想法或指示将不胜感激。

编辑:

为了使上述内容更清楚,我要做的是向 Df1 ('Df1$totvisits') 添加一个新列,其中每个条目都是在另一个数据框中查找 date1/name1 的结果 (' Df),并返回每个“name1”在“date1”之前发生的访问总和。例如,在 Df1 中的“2020-01-02 paul”行中,我需要从 Df 中获取 'name == paul' 和 'date

我希望能够将此扩展到从一系列日期中查找值,例如x 和 y 之间的日期,其中人 z 进行了访问。我想这样做,以便计算 n 天窗口内的访问次数。

在 dplyr 上下文中,我认为我正在尝试使用一个新列“变异”Df1,该列包含返回 Df总和值的表达式>$visits 在每个日期之前(/之间)。只是我似乎无法让它工作,这让我发疯了。

在此先感谢您提供更多帮助。

【问题讨论】:

    标签: r loops subset mapply


    【解决方案1】:

    仍然不能 100% 确定我是否了解您想要做什么,但这里有一个dplyr 的获取方式:

    在这个例子中,我想要(对于 Df1 中的每一行 name1/date1 对)子集 df 根据日期/名称返回每个访问次数 'name1' 在每个 'date1' 值之前,即通过对 日期

    library(dplyr)
    Df %>% 
      group_by(name) %>% 
      arrange(date) %>% 
      mutate(total = cumsum(visits)) %>% 
      ungroup() %>% 
      arrange(name, date)
    

    上面的代码返回:

    # A tibble: 10 x 4
       date       name   visits total
       <date>     <fct>   <dbl> <dbl>
     1 2020-01-03 andrew      6     6
     2 2020-01-01 john        1     1
     3 2020-01-02 john        2     3
     4 2020-01-03 john        4     7
     5 2020-01-03 john        1     8
     6 2020-01-02 paul        3     3
     7 2020-01-02 peter       1     1
     8 2020-01-03 peter       3     4
     9 2020-01-04 peter       1     5
    10 2020-01-04 peter       9    14
    

    这就是使用data.table 的相同任务的样子:

    library(data.table)
    Df <- data.table(Df)
    Df[order(date), total:=cumsum(visits), name]
    

    我们对其进行排序,得到与上述解决方案相同的结构:

    Df[order(name, date),]
    
              date   name visits total
     1: 2020-01-03 andrew      6     6
     2: 2020-01-01   john      1     1
     3: 2020-01-02   john      2     3
     4: 2020-01-03   john      4     7
     5: 2020-01-03   john      1     8
     6: 2020-01-02   paul      3     3
     7: 2020-01-02  peter      1     1
     8: 2020-01-03  peter      3     4
     9: 2020-01-04  peter      1     5
    10: 2020-01-04  peter      9    14
    

    【讨论】:

    • 还有base R: Df &lt;- within(Df[order(Df$name, Df$date),], { total &lt;- ave(visits, name, FUN=cumsum)})
    • @Parfait 完美!感谢您对base R 表达爱意;)
    • 非常感谢您的回复 - 我在这里的第一个问题,所以很抱歉不清楚。我想用相关计数更新 Df1 的每一行,所以“2020-01-01 john”用 1,“2020-01-02 paul”用 3,“2020-01-03 andrew”等等。所以总共有四行。
    猜你喜欢
    • 2021-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-22
    • 1970-01-01
    相关资源
    最近更新 更多