【问题标题】:Loop through columns and split fields automatically to new column循环遍历列并将字段自动拆分到新列
【发布时间】:2019-08-21 13:08:12
【问题描述】:

我一直在使用名为 daff 的包比较 R 中的两个数据帧,这是我得到的最终表格:

dput(df)
structure(list(v1 = c("Silva->Silva/Mark", "Brandon->Brandon/Livo", "Mango->Mango or Apple"),
               v2 = c("James->James=Jacy","NA->Na/Jane", "Egg->Egg and Orange")),
          class = "data.frame", row.names = c(NA,  -3L))

行字段具有 ->(箭头) 表示该单元格中的数据已从先前的数据帧列修改为当前数据帧值。现在从这里我不得不用 ->(arrow) 分隔符分隔列,这样我就可以拥有一个旧列和新的更改列。这意味着我在新列中添加了后缀_old_New。我使用了这段代码并查看了输出:

setDT(df)
df1<- lapply(names(df), function(x) {
  mDT <- df[, tstrsplit(get(x), " *-> *")]
  if (ncol(mDT) == 2L) setnames(mDT, paste0(x, c("_Old", "_New")))
}) %>% as.data.table()

输出

dput(df)
structure(list(v1_Old = c("Silva", "Brandon", "Mango"),
               v1_New = c("Silva/Mark", "Brandon/Livo", "Mango or Apple"),
               v2_Old = c("James","NA", "Egg"),
               v2_New = c("James=Jacy","Na/Jane", "Egg and Orange")),
          class = "data.frame", row.names = c(NA,  -3L))

现在我的下一步是比较具有 _old_new 后缀的每两列,以确定修改的内容,然后拆分并存储在名为 diff_v1 的新列中diff_v2。这是我使用这段代码完成的(意识到我必须通过创建不同的拆分代码行手动执行此操作,这对于 20 多个单独的列来说很乏味):

df$diff_v1<- mapply(function(x, y) paste(setdiff(y, x), collapse = '| '), strsplit(df$v1_old, '\\||, | | -| \\+'), strsplit(df$v1_Name_new, '\\||, | | -| \\+'))
df$diff_v2<- mapply(function(x, y) paste(setdiff(y, x), collapse = '| '), strsplit(df$v2_old, '\\||, | | -| \\+'), strsplit(df$v2_new, '\\||, | | -| \\+'))

输出

dput(df)
structure(list(v1_Old = c("Silva", "Brandon", "Mango"),
               v1_New = c("Silva/Mark", "Brandon/Livo", "Mango or Apple"),
               diff_v1 = c("/Mark", "/Livo", "or Apple"),
               v2_Old = c("James","NA", "Egg"),
               v2_New = c("James=Jacy","Na/Jane", "Egg and Orange"),
               diff_v2 = c("=Jacy","/Jane", "and Orange")),
          class = "data.frame", row.names = c(NA,  -3L))

我的问题是我能否遍历具有 _old_new 的列并创建名为 diff_v1diff_v2 的新列 之后分别没有逐行运行代码。我有多个列,它们根据我正在比较的数据框不断变化。想知道如何使用代码自动识别具有 _Old_New 后缀的列并拆分,然后在两者之后创建新列,但应该在每对列上发生。

目前我必须转到数据框,检查新旧列,然后手动更改正在拆分和创建 diff 列

的代码

【问题讨论】:

    标签: r split


    【解决方案1】:

    我们可以使用grep 根据名称识别"Old""New" 列。我们可以使用在stringpattern 上矢量化的str_remove 来删除"New" col 中存在的"Old" col 的一部分以创建新列。

    old_cols <- grep("Old$", names(df), value = TRUE)
    new_cols <- grep("New$", names(df), value = TRUE)
    
    
    df[sub("New$", "diff", new_cols)] <- Map(stringr::str_remove, 
                                             df[new_cols], df[old_cols])
    

    要按顺序获取名称,我们可以这样做

    df <- df[order(sub("_.*", "", names(df)))]
    df
    #   v1_Old         v1_New   v1_diff v2_Old         v2_New     v2_diff
    #1   Silva     Silva/Mark     /Mark  James     James=Jacy       =Jacy
    #2 Brandon   Brandon/Livo     /Livo     NA        Na/Jane     Na/Jane
    #3   Mango Mango or Apple  or Apple    Egg Egg and Orange  and Orange
    

    使用tidyverse,我们可以做到

    library(tidyverse)
    
    df %>%
       bind_cols(map2(df %>% select(ends_with("New")), 
                      df %>% select(ends_with("Old")), stringr::str_remove))
    

    【讨论】:

    • 谢谢您,但是当我使用我的数据集运行时出现此错误 [.data.table(df1, new_cols) 中的错误:当 i 是 data.table(或字符向量)时,列必须使用“on=”参数(参见 ?data.table)或键入 x(即已排序,并且标记为已排序,参见 ?setkey)来指定加入依据。由于 x 在 RAM 中排序,键控连接可能对非常大的数据有进一步的速度优势。
    • @LivingstoneM 我想你有data.table。您可以将其更改为 data.frame 然后尝试吗? df &lt;- data.frame(df)
    • 确定我已经这样做了,并且它可以工作,现在我正在创建新列,是否可以让 diff 从列名开始,例如 diff_v1 diff_v2 那么是否可以将这些新列排列在已检查的列对之后,例如列是这样的 v1_Oldv1_NewDiff_v1 然后 v2_OldV2_Newdiff_v2
    • @LivingstoneM 你可以通过df[order(sub("_.*", "", names(df)))] 来按顺序排列它们。
    • 它只是给我同样的安排,你能把它添加到你上面的代码我再试一次
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多