【问题标题】:How to vectorize a for loop in R for a large dataset如何为大型数据集矢量化 R 中的 for 循环
【发布时间】:2020-11-04 01:45:12
【问题描述】:

我对 R 比较陌生,我有一个关于数据处理的问题。主要问题是数据集太大,我想写一个比for循环更快的向量化函数,但我不知道怎么做。数据是关于电影和用户评分的,格式如下(如下)。

1:
5,3,2005-09-06
1,5,2005-05-13
3,4,2005-10-19

2:
2,4,2005-12-26
3,3,2004-05-03
5,3,2005-11-17

1: 和 2: 代表电影,而其他行代表该电影的用户 ID、用户评分和评分日期(按从左到右的顺序,以逗号分隔)。我想将数据格式化为边缘列表,如下所示:

Movie | User
1:    | 5
1:    | 1
1:    | 3
2:    | 2
2:    | 3
2:    | 5

我写了下面的代码来执行这个功能。基本上,对于每一行,它都会检查其是否为电影 ID(包含“:”)或是否为用户数据。然后,它将电影 ID 和用户 ID 组合为每个电影和用户的两列,然后将其行绑定到一个新的数据帧。同时,它也只绑定那些对一部电影评分为 5 分(满分 5 分)的用户。

el <- data.frame(matrix(ncol = 2, nrow = 0))

for (i in 1:nrow(data))
{
  if (grepl(':', data[i,]))
  {
    mid <- data[i,]
  } else(grepl(',', data[i,]))
  {
    if(grepl(',5,', data[i,]))
    {
      uid <- unlist(strsplit(data[i,], ','))[1]
      add <- c(mid, uid)
      el <- rbind(el, add)
    }
  }
}

但是,我有大约 1 亿个条目,并且 for 循环在整个晚上运行而无法完成。有没有办法加快这个速度?我读到了矢量化,但我不知道如何矢量化这个函数。有什么帮助吗?

【问题讨论】:

  • 第一个代码块是否显示了您的数据在读入 R 之前的样子?这看起来不像 R 控制台打印的任何内容。

标签: r


【解决方案1】:

您可以使用一些正则表达式来执行此操作,我将使用 stringr package 以及 zoo 包中的 na.locf。 (你必须先安装 stringr 和 zoo)。

首先,我们将设置您的数据,听起来像是在单列数据框中:

data <- read.table(textConnection("1:
5,3,2005-09-06
1,5,2005-05-13
3,4,2005-10-19

2:
2,4,2005-12-26
3,3,2004-05-03
5,3,2005-11-17
"))

然后您可以按照以下步骤操作(在 cmets 中解释)。

# Pull out the column as a character vector for simplicity
lines <- data[[1]]

library(stringr)
# Figure out which lines represent movie IDs, and extract IDs
movie_ids <- str_match(lines, "(\\d+):")[, 2]

# Fill the last observation carried forward (locf), to find out
# the most recent non-NA value
library(zoo)
movie_ids_filled <- na.locf(movie_ids)

# Extract the user IDs
user_ids <- str_match(lines, "(\\d+),")[, 2]

# For each line that has a user ID, match it to the movie ID
result <- cbind(movie_ids_filled[!is.na(user_ids)],
                user_ids[!is.na(user_ids)])

这样就得到了结果

     [,1] [,2]
[1,] "1"  "5" 
[2,] "1"  "1" 
[3,] "1"  "3" 
[4,] "2"  "2" 
[5,] "2"  "3" 
[6,] "2"  "5" 

这段代码最重要的部分是正则表达式的使用,尤其是"(\\d+):"(\\d+), 括号中的捕获组。有关将str_match 与正则表达式结合使用的更多信息,请查看this guide

【讨论】:

  • 顺便说一句,我想指出stringr及其函数比grep及其函数快一个数量级,所以你应该改掉使用的习惯grep 反正。
  • @SirTain 我以前没见过这个断言。你能指出一些好的测试结果吗? (顺便说一句,“stringr”的任何速度声明都应该归功于“stringi”包的作者的性能,因为我知道“stringr”现在只是“stringi”的轻包装。)
  • 感谢您的所有帮助和 cmets!使用字符捕获一组元素,并使用 stringr 函数比我的 for 循环快得多。谢谢
  • @IRTFM 关于“stringi”的好点子。我总是忘记这一点。我看了看,找不到任何好的基准测试。我只是从我自己对更大数据库的经验中说出来。也许有一天,我将不得不生成自己的基准测试示例。
  • 编辑:显然我是个疯子,grep 很好。我就让自己出去吧……
猜你喜欢
  • 2012-12-10
  • 2020-05-03
  • 1970-01-01
  • 2019-02-28
  • 2018-12-08
  • 2014-10-03
  • 1970-01-01
  • 2016-02-11
相关资源
最近更新 更多