在 R 中使用嵌套 if 优化 For 循环
Optimizing For loop with nested if in R
我正在尝试将多个 csv 文件合并到一个数据帧中,并尝试使用 for 循环操作生成的数据帧。生成的数据框可能有 1,500,000 到 2,000,000 行。
我正在使用下面的代码。
setwd("D:/Projects")
library(dplyr)
library(readr)
merge_data = function(path)
{
files = dir(path, pattern = '\.csv', full.names = TRUE)
tables = lapply(files, read_csv)
do.call(rbind, tables)
}
Data = merge_data("D:/Projects")
Data1 = cbind(Data[,c(8,9,17)],Category = "",stringsAsFactors=FALSE)
head(Data1)
for (i in 1:nrow(Data1))
{
Data1$Category[i] = ""
Data1$Category[i] = ifelse(Data1$Days[i] <= 30, "<30",
ifelse(Data1$Days[i] <= 60, "31-60",
ifelse(Data1$Days[i] <= 90, "61-90",">90")))
}
但是代码 运行 很长。有没有更好更快的方法来做同样的操作?
我们可以通过使用 fread
从 data.table
读取然后使用 cut/findInterval
来优化它。当 运行 在多个内核中时,这将变得更加明显,服务器上的节点 fread
利用所有节点并并行执行
library(data.table)
merge_data <- function(path) {
files = dir(path, pattern = '\.csv', full.names = TRUE)
rbindlist(lapply(files, fread, select = c(8, 9, 17)))
}
Data <- merge_data("D:/Projects")
Data[, Category := cut(Data1, breaks = c(-Inf, 30, 60, 90, Inf),
labels = c("<=30", "31-60", "61-90", ">90"))]
您已经在使用 dplyr
,为什么不直接:
Data = merge_data("D:/Projects") %>%
select(8, 9, 17) %>%
mutate(Category = cut(Days,
breaks = c(-Inf, 30, 60, 90, Inf),
labels = c("<=30", "31-60", "61-90", ">90"))
Ak运行 确实是正确的,fread 快得多 read.csv。
但是,除了他的post,我还要补充一点,你的for循环是完全没有必要的。他用我不熟悉的 cut/findInterval 代替了它。不过,就简单的 R 编程而言,当计算中的某些因素逐行变化时,for 循环是必要的。但是,在您的代码中,情况并非如此,也不需要 for 循环。
本质上,当您只需要 运行 对列进行一次计算时,您正在 运行 计算多达 200 万次。
您可以用这样的东西替换您的 for 循环:
Data1$category = ifelse(Data1$Days <= 30, "<=30",
ifelse(Data1$Days <= 60, "31-60",
ifelse(Data1$Days <= 90, "61-90",">90")))
您的代码 运行 会更快
我正在尝试将多个 csv 文件合并到一个数据帧中,并尝试使用 for 循环操作生成的数据帧。生成的数据框可能有 1,500,000 到 2,000,000 行。
我正在使用下面的代码。
setwd("D:/Projects")
library(dplyr)
library(readr)
merge_data = function(path)
{
files = dir(path, pattern = '\.csv', full.names = TRUE)
tables = lapply(files, read_csv)
do.call(rbind, tables)
}
Data = merge_data("D:/Projects")
Data1 = cbind(Data[,c(8,9,17)],Category = "",stringsAsFactors=FALSE)
head(Data1)
for (i in 1:nrow(Data1))
{
Data1$Category[i] = ""
Data1$Category[i] = ifelse(Data1$Days[i] <= 30, "<30",
ifelse(Data1$Days[i] <= 60, "31-60",
ifelse(Data1$Days[i] <= 90, "61-90",">90")))
}
但是代码 运行 很长。有没有更好更快的方法来做同样的操作?
我们可以通过使用 fread
从 data.table
读取然后使用 cut/findInterval
来优化它。当 运行 在多个内核中时,这将变得更加明显,服务器上的节点 fread
利用所有节点并并行执行
library(data.table)
merge_data <- function(path) {
files = dir(path, pattern = '\.csv', full.names = TRUE)
rbindlist(lapply(files, fread, select = c(8, 9, 17)))
}
Data <- merge_data("D:/Projects")
Data[, Category := cut(Data1, breaks = c(-Inf, 30, 60, 90, Inf),
labels = c("<=30", "31-60", "61-90", ">90"))]
您已经在使用 dplyr
,为什么不直接:
Data = merge_data("D:/Projects") %>%
select(8, 9, 17) %>%
mutate(Category = cut(Days,
breaks = c(-Inf, 30, 60, 90, Inf),
labels = c("<=30", "31-60", "61-90", ">90"))
Ak运行 确实是正确的,fread 快得多 read.csv。
但是,除了他的post,我还要补充一点,你的for循环是完全没有必要的。他用我不熟悉的 cut/findInterval 代替了它。不过,就简单的 R 编程而言,当计算中的某些因素逐行变化时,for 循环是必要的。但是,在您的代码中,情况并非如此,也不需要 for 循环。
本质上,当您只需要 运行 对列进行一次计算时,您正在 运行 计算多达 200 万次。
您可以用这样的东西替换您的 for 循环:
Data1$category = ifelse(Data1$Days <= 30, "<=30",
ifelse(Data1$Days <= 60, "31-60",
ifelse(Data1$Days <= 90, "61-90",">90")))
您的代码 运行 会更快