【问题标题】:R loop to create multiple new columns based on dataframe nameR循环根据数据框名称创建多个新列
【发布时间】:2019-03-04 12:18:19
【问题描述】:

我正在创建一个 R 脚本以从我的收件箱中提取某些电子邮件附件,将附件放入数据框(与文件名同名),然后将数据框名称解析为单个元素,然后可以使用在数据框中创建新列。然后这将被 rbind-ed 并最终放入 SQL 表中。

我正处于需要一个循环来遍历数据框名称、解析它们并将它们添加为新列的阶段,但我无法让我的循环工作。

我在下面提供了我的代码示例:

df_list <- Filter(function(x) is.data.frame(get(x)), ls())

for(i in df_list){
  i["Filename"]           <- df_list[i]
  i["Campaign_ID"]        <- sapply(strsplit(df_list[i], " "), "[", 1)
  i["Campaign_Name"]      <- str_sub(regmatches(df_list[i], regexpr("(?<=\\ )[^_]+", df_list[i], perl=TRUE)), start = 1, end = str_length(regmatches(df_list[i], regexpr("(?<=\\ )[^_]+", df_list[i], perl=TRUE))) - str_length(regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^_]+", df_list[i], perl=TRUE)))-1)
  i["Campaign_Code"]      <- regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^ -]+", df_list[i], perl=TRUE))
  i["Brand"]              <- substr(regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^ -]+", df_list[i], perl=TRUE)), start = 1, stop = 4)
  i["Campaign_Type"]      <- substr(regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^ -]+", df_list[i], perl=TRUE)), start = 5, stop = 7)
  i["Campaign_Category"]  <- substr(regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^ -]+", df_list[i], perl=TRUE)), start = 8, stop = 10)
  i["Campaign_Churn"]     <- substr(regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^ -]+", df_list[i], perl=TRUE)), start = 11, stop = 13)
  i["Product"]            <- substr(regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^ -]+", df_list[i], perl=TRUE)), start = 14, stop = 16)
  i["Version"]            <- substr(regmatches(df_list[i], regexpr("([A-Z]+[A-Z])[^ -]+", df_list[i], perl=TRUE)), start = 17, stop = 17)
  i["Segment"]            <- regmatches(df_list[i], regexpr("(?<=\\_)[^ -]+", df_list[i], perl=TRUE))
  i["Churn"]              <- regmatches(df_list[i], regexpr("(?<=\\- )[^ -]+", df_list[i], perl=TRUE))
  i["Stage"]              <- regmatches(df_list[i], regexpr("([S-S]+[a-z]+[a-z]+[a-z]+[a-z] )[^\\s]+", df_list[i], perl=TRUE))
  i["Other"]              <- str_sub(regmatches(df_list[i], regexpr("([S-S]+[a-z]+[a-z]+[a-z]+[a-z] )[^.]+", df_list[i], perl=TRUE)), start = str_length(regmatches(df_list[i], regexpr("([S-S]+[a-z]+[a-z]+[a-z]+[a-z] )[^\\s]+", df_list[i], perl=TRUE)))+2, end = str_length(regmatches(df_list[i], regexpr("([S-S]+[a-z]+[a-z]+[a-z]+[a-z] )[^.]+", df_list[i], perl=TRUE))) - str_length(regmatches(df_list[i], regexpr("\\S+(?=\\.[^.]*$)", df_list[i], perl=TRUE)))-1)
  i["Date"]               <- dmy(regmatches(df_list[i], regexpr("\\S+(?=\\.[^.]*$)", df_list[i], perl=TRUE)))
  print(i)
}

我想这是我的循环中缺少的一些简单的东西,但我似乎无法弄清楚是什么。 我试过这个没有解析,只是添加随机数据,但它仍然不起作用

为清楚起见,我还提供了“df_list”的内容(这些确实是数据帧 - 它们的名称与它们所派生的文件的名称相同):

[1] "20579 Buzz Testing Nathan 1 BUZZRETJOUCHUALLA_D1A - Churned - Stage 1 Other 28-February-2019.csv"
[2] "20580 Buzz Testing Nathan 2 BUZZRETJOUCHUALLA_D1B - Churned - Stage 1 Other 28-February-2019.csv"
[3] "20581 Buzz Testing Nathan 3 BUZZRETJOUCHUALLA_D1C - Churned - Stage 1 Other 28-February-2019.csv"

编辑: 我想我会添加一些更多可重现的数据,这应该有助于澄清一些事情。

`20579 Buzz Testing Nathan 1 BUZZRETJOUCHUALLA_D1A - Churned - Stage 1 Other 28-February-2019.csv` <- data.frame(ID = 000000, Code = 'ABCDE')

`20580 Buzz Testing Nathan 2 BUZZRETJOUCHUALLA_D1B - Churned - Stage 1 Other 28-February-2019.csv` <- data.frame(ID = 111111, Code = 'FGHIJ')

`20581 Buzz Testing Nathan 3 BUZZRETJOUCHUALLA_D1C - Churned - Stage 1 Other 28-February-2019.csv` <- data.frame(ID = 222222, Code = 'KLMNO')

然后在每个数据框中,创建一个新列,使用数据框名称的元素来填充它们。 因此,例如,对于第一个数据框,数据框名称的前 5 位数字将是活动 ID。正如我的问题前面提到的,我已经对这些元素进行了字符串拆分。

【问题讨论】:

    标签: r loops


    【解决方案1】:

    由于我无权访问您的数据,因此我将尝试使用示例数据框和表示您可能在 for 循环中指定的列修改过程的任意操作非常笼统地回答您的问题在原帖中。我的解决方案中的结构有点不同。我没有使用 for 循环,而是将数据框组合成一个列表,并使用 lapply 修改命名列。

    df1 <- data.frame(foo = 1:5,
                      bar = c(7, NA, 22, 3, 14),
                      baz = c(T, F, F, NA, T))
    
    df2 <- data.frame(foo = 1:5,
                      bar = c(4, NA, 9, 29, 11),
                      baz = c(T, T, F, NA, T))
    
    df3 <- data.frame(foo = 1:5,
                      bar = c(1, 9, NA, 7, 12),
                      baz = c(F, F, F, NA, F))
    
    dfs <- Filter(function(x) is.data.frame(get(x)), ls())
    

    下一行将创建一个列表,其条目是数据框。 可以使用 names(df_list) your names here)

    更改名称
    df_list <- lapply(dfs, function(x) eval(as.name(x)))
    

    再一次,由于我没有您的原始数据,我正在对每个数据框的“条形”列应用任意转换,以说明如何将转换集成到这个通用解决方案中。在这里,我只是将“bar”列中的每个非 NA 值加 1。希望我不会误解您的目标。如果它不是您需要的或者它不适用于您的特定数据,请发布更新/评论。

    df_list <- lapply(1:length(df_list), function(i) {
                 reps = dim(df_list[[i]])[[1]]
                 df_list[[i]][ ,"bar"] <- df_list[[i]][ ,"bar"] +
                   rep(1, times = reps)
                 df_list[[i]]
               })
    

    输出应该是一个数据帧列表,在“bar”的每个非 NA 元素中添加了 1。您可以在使用 lapply 应用的函数中的其他列上添加转换。如果将您的数据框放在列表中不适合您作为列表,这里有一些代码会将列表中的转换后的数据框分配给全局环境中的原始数据框:

    assignment_fun <- function(x, y) {
      assign(x, y, envir = .GlobalEnv)
    }
    
    mapply(assignment_fun, dfs, df_list)
    df1
    df2
    df3
    

    您将从控制台中的 mapply 行获得一个看起来很有趣的输出,总结了分配的数据类型,如果您在全局环境中调用这些数据框,它们现在应该与转换后的数据框列表中的条目相匹配.

    【讨论】:

    • 不错的答案!我推荐df_list &lt;- mget(dfs) 而不是lapply(dfs, function(x) eval(as.name(x)))。而list2env(df_list) 是您的assignment_fun 的内置替代品(它将使用df_list 的名称作为变量名称,因此根据需要先更新这些名称)。
    • 哦,太好了,谢谢。我不知道这两个功能。实际上,我从最初的问题中也不知道 Filter(),所以我很高兴能找到它。
    • 对不起,我应该更清楚。我将在我的问题中添加更多可重现的信息。
    猜你喜欢
    • 2023-01-10
    • 1970-01-01
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-18
    相关资源
    最近更新 更多