首页 > 解决方案 > 如何为大型数据集矢量化 R 中的 for 循环

问题描述

我对 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

解决方案


您可以使用一些正则表达式来完成此操作,为此我将使用stringr 包以及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
"))

然后,您可以按照以下步骤操作(注释中的说明)。

# 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


推荐阅读