【问题标题】:How can I simplify this code (r) in which I am using information from an original data set to create a new dataset?在我使用来自原始数据集的信息来创建新数据集时,如何简化此代码 (r)?
【发布时间】:2022-01-26 01:03:42
【问题描述】:

我有一个数据集,我试图用它在 R 中生成不同的数据集。数据集有很多列;但生成新数据集的三个相关列是“Reach”、“Results”和“DV”。范围和结果是数字。 DV 是二进制的 0 和 1。在原始数据集中,所有行的 DV = 0。

对于原始数据集的每一行,我尝试使用一个变量“Reach”并复制该行“reach”次数。 然后对于这组新行,我想将新行的“结果”数(来自原始行)的 DV 从 0 更改为 1。

例如,在原始数据集的第 33 行中:Reach = 1004,Results = 45,DV = 0。新数据集的第 33 行应复制 1004 次,其中 45 行 DV 应从0 到 1。

我为该任务编写的代码可以运行……但由于文件太大,需要 10 多个小时才能运行。关于如何简化此代码以便更快处理的任何想法

empty_new.video <- new.video[FALSE,]
for(i in 1:nrow(new.video)){
  n.times <- new.video[i,'Reach'] #determine number of times to repeat rows
  if (n.times > 0){
    for (j in 1:n.times){
      empty_new.video[nrow(empty_new.video) + 1 , ] <- new.video[i,]
    }
  }
  dv.times <- new.video[i,'Results'] #creating dependent variable 
  if (dv.times>0){
    for (k in 1:dv.times){
      empty_new.video[nrow(empty_new.video) - n.times + k,'DV'] <- 1
    }
  }
}

【问题讨论】:

标签: r performance for-loop


【解决方案1】:

您可以定义一个简单的函数,对一行执行此操作并检查结果,而不是一次执行所有操作的循环

dd <- data.frame(Reach = c(5, 3), Results = c(4, 1), DV = c(0, 0))
#   Reach Results DV
# 1     5       4  0
# 2     3       1  0

f <- function(data) {
  nr <- data$Reach
  nd <- data$Results
  data <- data[rep_len(1L, nr), ]
  data$DV <- rep(0:1, c(nr - nd, nd))
  rownames(data) <- NULL
  data
}
f(dd[1, ])

然后循环每一行

res <- lapply(split(dd, rownames(dd)), f)
do.call('rbind', res)
#     Reach Results DV
# 1.1     5       4  0
# 1.2     5       4  1
# 1.3     5       4  1
# 1.4     5       4  1
# 1.5     5       4  1
# 2.1     3       1  0
# 2.2     3       1  0
# 2.3     3       1  1

但实际上,您所做的只是为 DV 创建一个行索引和 0/1 值向量,您可以使用 rep 来做到这一点

ii <- rep(1:nrow(dd), dd$Reach)

jj <- c(t(cbind(dd$Reach - dd$Results, dd$Results)))
dv <- rep(rep(0:1, nrow(dd)), jj)

within(dd[ii, ], {
  DV <- dv
})
#     Reach Results DV
# 1       5       4  0
# 1.1     5       4  1
# 1.2     5       4  1
# 1.3     5       4  1
# 1.4     5       4  1
# 2       3       1  0
# 2.1     3       1  0
# 2.2     3       1  1

【讨论】:

  • 谢谢!我收到一条消息,在 rep_len(1L, nr) 中使用 nr 是无效的“length.out”值。知道那里发生了什么吗?我已经确认 nr 是一个整数
  • 达到是否为负数?覆盖面总是大于结果吗?
  • reach 总是大于零,并且总是大于 results
  • 开始工作了!!非常感谢
【解决方案2】:

避免在循环中增长对象。考虑Map(包装到mapply)逐元素遍历所有原始数据集的列,以构建数据框列表,最终在末尾连接一次

build_rows <- function(reach, results) {
    # DATA FRAME TO REPLICATE REACH BY ITS LENGTH
    df <- data.frame(id = reach, reach = 1:reach, dv = 0)

    # RANDOMLY ASSIGN N ROWS TO 1 (N=RESULTS)  
    df$dv[sample(1:nrow(df), results),] = 1 

    # ASSIGN FIRST N ROWS TO 1 (N=RESULTS)
    df$dv[1:results,] = 1 

    return(df)
}

df_list <- Map(build_rows, original_data$Reach, original_data$Results)

final_df <- do.call(rbind, df_list)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 2021-10-14
    • 2013-01-16
    • 1970-01-01
    • 2017-05-15
    • 2021-04-30
    • 1970-01-01
    相关资源
    最近更新 更多