遍历列并自动将字段拆分为新列

时间:2019-08-21 13:08:12

标签: r split

我一直在使用名为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_v1 diff_v2的新列之后,不再逐行运行代码。我有多列,它们根据我正在比较的数据帧不断变化。想知道如何使用代码自动标识后缀为 _Old _New 的列并拆分,然后在两个之后创建该新列,但应该在每对列上进行。

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

的代码

1 个答案:

答案 0 :(得分:0)

我们可以使用"Old"根据它们的名称来标识"New"grep列。我们可以使用在str_removestring上矢量化的pattern来删除"Old" col中存在的"New" 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))