【问题标题】:Speeding up code inside for loop加速 for 循环内的代码
【发布时间】:2017-01-19 06:11:12
【问题描述】:

我有一个包含超过 200 万条记录的数据框。由于数据安全原因,我只分享少数记录。希望你们能理解我的原因。

data <- data[order(data$email_address_hash),]
skip_row <- c()
data$hash_time <- rep('NA',NROW(data)) #adding new column to our data
rownames(data) <- as.character(1:NROW(data))
dput(droplevels(data))
structure(list(email_address_hash = structure(c(2L, 1L, 1L, 2L
), .Label = c("0004eca7b8bed22aaf4b320ad602505fe9fa9d26", "35c0ef2c2a804b44564fd4278a01ed25afd887f8"
), class = "factor"), open_time = structure(c(2L, 1L, 3L, 4L), .Label = c(" 04:39:24", 
" 09:57:20", " 10:39:43", " 19:00:09"), class = "factor")), .Names = c("email_address_hash", 
"open_time"), row.names = c(41107L, 47808L, 3973L, 8307L), class = "data.frame")

str(data)
'data.frame':   4 obs. of  2 variables:
 $ email_address_hash: Factor w/ 36231 levels "00012aec4ca3fa6f2f96cf97fc2a3440eacad30e",..: 7632 2 2 7632
 $ open_time         : Factor w/ 34495 levels " 00:00:03"," 00:00:07",..: 15918 5096 16971 24707
.

skip_row <- c()


data$hash_time <- rep('NA',NROW(data)) #adding new column to our data

rownames(data) <- as.character(1:NROW(data))

for(i in 1:NROW(data)){
#Skipping the email_address_hash that was already used for grouping 
  if(i %in% skip_row) next   
  hash_row_no <- c()
#trimming data so that we don't need to look into whole dataframe 


trimmed_data <- data[i:NROW(data),] 
  # Whenever we search for email_address_hash the previous one was ignored or removed from the check 

  #extracting rownames so that we can used that as rownumber inside the skip_row
  hash_row_no <-  rownames(trimmed_data[trimmed_data$email_address_hash==trimmed_data$email_address_hash[1],])

#note :- 我们知道黑白行名和行号的区别

#converting rownames into numeric so that we can use them as rowno      
hash_row_no <- as.numeric(hash_row_no) 


  first_no <- hash_row_no[1]
  last_no <- hash_row_no[NROW(hash_row_no)]
  skip_row <- append(skip_row,hash_row_no)

  data$hash_time[first_no] <- paste(data$open_time[first_no:last_no], collapse = "")
}

请注意,我也尝试了以下方法来加快进程,但这似乎无效

hash_row_no <-  rownames(trimmed_data[trimmed_data$email_address_hash==trimmed_data$email_address_hash[1],])

将数据帧转换为 data.table

setDT(data)

执行任一操作都会给出相似的时间

system.time(rownames(trimmed_data[trimmed_data$email_address_hash==trimmed_data$email_address_hash[1],]))

system.time(rownames(trimmed_data)[trimmed_data[["email_address_hash"]] == trimmed_data$email_address_hash[1]])

由于我的数据包含超过 200 万条记录,并且需要 30 多分钟甚至更多时间,你们能帮我加快代码速度吗?

【问题讨论】:

  • “希望你们能理解我的理由。”然后你应该解释你的实际目标。更好的算法通常可以实现更好的性能。
  • 我是在数据安全的背景下说的。 .目标是提取一个人的所有开放时间,并将其写在该客户面前,并在一行而不是多行中,并删除该客户的其他条目
  • 这仍然不足以描述需要做什么。到目前为止,我了解到您希望将每个唯一 email_address_hash 的所有 open_time 值一起 paste。这是一个正确的问题描述吗?
  • 是的,你是绝对正确的

标签: r performance optimization


【解决方案1】:

显然你想这样做:

library(data.table)
setDT(data)
data[, .(open_times = paste(open_time, collapse = "")), by = email_address_hash]
#                         email_address_hash         open_times
#1: 35c0ef2c2a804b44564fd4278a01ed25afd887f8  09:57:20 19:00:09
#2: 0004eca7b8bed22aaf4b320ad602505fe9fa9d26  04:39:24 10:39:43

或者可能是这样的:

data[email_address_hash == "0004eca7b8bed22aaf4b320ad602505fe9fa9d26", 
     paste(open_time, collapse = "")]
#[1] " 04:39:24 10:39:43"

【讨论】:

  • 有一个问题。当我使用 View(data) 打开它时,它只显示第一次打开时间。即 09:57:20 在第 1 行的情况下和第二行的同一客户的第二次。在我们的例子中,视图显示为 4 行
  • 请尽量沟通清楚。我完全不知道你用View 打开了什么,因为我的答案中的代码没有分配结果(你显然可以这样做)。
猜你喜欢
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
  • 2012-01-28
  • 1970-01-01
  • 2021-09-03
  • 2016-04-14
  • 1970-01-01
  • 2021-01-30
相关资源
最近更新 更多