我可以创建一个循环来在多个数据帧上运行一系列函数,但每次都需要稍微调整名称吗?

问题描述 投票:0回答:2

我正在开展一个项目,将数百个电子邮件活动的信息编译成一个数据集。我们使用的平台使我们将每个操作的数据导出到单独的 CSV 中,并且我们对三个操作感兴趣,这意味着每个活动都有三个 CSV。这是命名约定的示例:

Campaign_1_Delivered
Campaign_1_Opened
Campaign_1_Clicked

(如果使用不同的命名约定有助于解决问题,我绝对可以重命名)

最终将有数百个活动,我保持了命名约定,只是将下一个活动的数量加一(例如,

Campaign_2_Delivered
Campaign_3_Delivered
,依此类推,目前为
Campaign_112_Delivered
) )。所有 CSV 文件都具有相同的六列,无论它们是什么数据类型: 会员 ID、电子邮件地址、名字、姓氏、活动、日期

对于每个活动,我想加载 CSV,运行一些重新编码,然后将它们合并到整个活动的一个数据集中。我不是复制代码数百次然后查找并替换数字,而是希望有一个可以运行的循环,该循环将只运行代码然后再次执行,但所有数字都会增加一。

这是活动 23 的脚本的第一部分:


Campaign_23_Delivered <- read.csv("Campaign 23 - Delivered.csv")
Campaign_23_Opened <- read.csv("Campaign 23 - Opened.csv")
Campaign_23_Clicked <- read.csv("Campaign 23 - Clicked.csv")

Campaign_23_Delivered$Campaign_23_DateTime_Delivered <- mdy_hm(Campaign_23_Delivered$Date)
Campaign_23_Delivered$Campaign_23_Delivered <- 1
Campaign_23_Delivered <- Campaign_23_Delivered[c("Member.ID", "Campaign_23_Delivered", "Campaign_23_DateTime_Delivered")]

Campaign_23_Opened$Campaign_23_DateTime_Opened <- mdy_hm(Campaign_23_Opened$Date)
Campaign_23_Opened$Campaign_23_Opened <- 1
Campaign_23_Opened <- Campaign_23_Opened[c("Member.ID", "Campaign_23_Opened", "Campaign_23_DateTime_Opened")]

Campaign_23_Clicked$Campaign_23_DateTime_Clicked <- mdy_hm(Campaign_23_Clicked$Date)
Campaign_23_Clicked$Campaign_23_Clicked <- 1
Campaign_23_Clicked <- Campaign_23_Clicked[c("Member.ID", "Campaign_23_Clicked", "Campaign_23_DateTime_Clicked")]

Campaign_23 <- merge(Campaign_23_Delivered, Campaign_23_Opened, by = "Member.ID", all.x = TRUE)
Campaign_23 <- merge(Campaign_23, Campaign_23_Clicked, by = "Member.ID", all.x = TRUE)

我找到了几个循环的问题和答案,但没有一个允许我像这样调整数据集中和列名称中的数字。换句话说,我想再次运行这整套代码,但将 23 的每个实例替换为 24,然后是 25,然后是 26,依此类推。

任何帮助将不胜感激!

r loops
2个回答
0
投票

通常对于批处理,请考虑将数据包含在列表中。列表允许您使用

for
循环或
apply
系列函数迭代它们,并轻松应用您需要的任何操作。

此方法假定顶级目录的结构,每个活动都位于单独的子目录中:

dir <- "/your/top/level/dir/here"
setwd(dir)
dirs <- list.dirs(full.names = FALSE, recursive = FALSE)

out <- lapply(dirs, function(x){
  setwd(paste0(dir,"/",x))
  files <- list.files()
  fin <- lapply(files, function(y){
    temp <- read.csv(y)
    ###DO WHATEVER MANIPULATION YOU WANT TO DO ON THIS FILE HERE###
    })
  names(fin) <- files
  fin
})

在我的例子中,顶级目录使用名为 1、2 和 3 的三个子目录进行测试,第一个文件中有 2 个文件(bla.csv 和 hey.csv),第一个文件中有 3 个文件(hi.csv、hey.csv 和 bla,其他两个中的 csv)。

list.dirs
list.files
函数仅返回一个包含工作目录中目录/文件名称的向量。然后,我们使用 lapply 函数迭代这些向量以进入每个目录并将所有 csv 文件作为数据帧读取。

这是输出:

str(out)
List of 3
 $ :List of 2
  ..$ bla.csv:'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ heu.csv:'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
 $ :List of 3
  ..$ bla.csv:'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hey.csv:'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hi.csv :'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
 $ :List of 3
  ..$ bla.csv:'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hey.csv:'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hi.csv :'data.frame': 3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4

out 是一个列表,其中包含每个活动/子目录的列表,其中包含每个数据帧。通过迭代此列表,您可以轻松地批量进行所需的任何编辑,并根据需要进行拆分/组合。

如果你的所有内容都在同一个目录中,请考虑这样的事情:

dir <- "/your/top/level/dir/here"
setwd(dir)
allfiles <- list.files()
out <- list()
for(i in 1:3){
  files <- allfiles[grep(as.character(i), allfiles)]
  fin <- lapply(files, function(x){
    temp <- read.csv(x)
    ###DO WHATEVER MANIPULATION YOU WANT TO DO ON THIS FILE HERE###
  })
  names(fin) <- files
  out <- append(out, list(fin), after = length(out))
}

这本质上是相同的想法,只是你必须手动提供迭代次数(在本例中我有 3 次)。然后我们使用 grep 找出共享相同编号的文件名。这是输出:

str(out)
List of 3
 $ :List of 2
  ..$ bla1.csv:'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hey1.csv:'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
 $ :List of 3
  ..$ bla2.csv:'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hey2.csv:'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hi2.csv :'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
 $ :List of 3
  ..$ bla3.csv:'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hey3.csv:'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4
  ..$ hi3.csv :'data.frame':    3 obs. of  3 variables:
  .. ..$ X  : int [1:3] 1 2 3
  .. ..$ foo: int [1:3] 1 2 3
  .. ..$ bar: int [1:3] 2 3 4

0
投票

将 CSV 文件读入数据框列表并使用

lapply()
等函数来处理它们是一种方法。

此代码假设您对所有营销活动都有相同格式的 3 个文件,并且所有文件都保存在您当前的工作目录中。

这里定义了2个函数:

  • 对每个数据帧进行处理,即格式化日期并设置相关标志。这会在列表中的每个数据帧上运行。
  • 另一个组合每个数字对应的3个数据框
filenames <- list.files(pattern = "^Campaign")

all_data <- lapply(filenames, read.csv)
names(all_data) <- filenames

modify_data <- function(name) {
    dt_varname <- gsub("Campaign_(\\d+)_(\\w+)", "Campaign_\\1_Datetime_\\2", name)
    result <- all_data[[name]]
    result[[dt_varname]] <- lubridate::mdy_hm(result[["Date"]])
    result[[name]] <- 1
    result <- result[c("Member.ID", name, dt_varname)]
    return(result)
}

all_data <- lapply(names(all_data), modify_data)
names(all_data) <- filenames

combine_data <- function(number) {

    delivered_name <- sprintf("Campaign_%s_Delivered", number)
    opened_name <- sprintf("Campaign_%s_Opened", number)
    clicked_name <- sprintf("Campaign_%s_Clicked", number)

    result <- merge(
                    all_data[[delivered_name]],
                    all_data[[opened_name]],
                    by = "Member.ID", all.x = TRUE
    )
    result <- merge(
                    result,
                    all_data[[sprintf("Campaign_%s_Clicked", number)]],
                    by = "Member.ID", all.x = TRUE
    )
    return(result)
}

numbers <- unique(gsub("^\\w+_(\\d+)_.*$", "\\1", filenames))
final_data <- lapply(numbers, combine_data)
names(final_data) <- paste0("Campaign_", numbers)

© www.soinside.com 2019 - 2024. All rights reserved.