【问题标题】:Creating a new column using substring and gregexpr in R [closed]在R中使用子字符串和gregexpr创建一个新列[关闭]
【发布时间】:2016-01-31 00:46:02
【问题描述】:

我有一个表格,其中一列是这样的字符串:aaaaaaa_bbbbbb_ccccc_1111111

大约有 20000 行,我需要为每一行创建一个包含此子字符串的新列:aaaaaaa_bbbbbb_ccccc

经过一些研究,我发现使用"substring""gregexpr" 对我有用,而且当我对每一行(或者如果我选择某行)使用这样的命令时,它确实可以正常工作:

for (i in 1:nrow(table)){
    table$column[i] <- 
         substring(table$column[i], 1, (gregexpr("_", table$column[i])[[1]][3])-1)
}

但是我想在没有循环的情况下使用它:

table$column &lt;- substring(table$column, 1, (gregexpr("_", table$column)[[1]][3])-1)

但在这种情况下,新列的子字符串与我想要的模式不匹配,有时它们是正确的,有时它们的长度是随机的。

有人知道导致这些奇怪结果的原因吗?

【问题讨论】:

  • 你可以试试table$column &lt;- sub("(.*)_\\d+", "\\1", table$column)
  • 没有可重现的例子,不清楚那里发生了什么。你能提供一个小的可重现的例子来展示这种行为吗?否则,您可能会考虑另一种方法,例如 docendo discimus 建议的方法。
  • 您应该将列表分配给 data.frame 列。
  • @42 如果我是对的,我不会将列表分配给 data.frame...gregexpr 返回一个包含所有模式位置的列表。所以我使用列表中的特定项目来删除我不感兴趣的字符串部分。

标签: r substring


【解决方案1】:

假设您的数据如下所示:

df <- as.data.frame(t(sapply(seq(10), function(x) c(x,paste(paste(sapply(seq(3),function(i) paste(rep(letters[sample(seq(26),1)],7),collapse="")),collapse="_"),paste(rep(as.character(sample(seq(9),1)),7),collapse=""),sep="_")))))
colnames(df) <- c("id","column")
df
#    id                          column
# 1   1 wwwwwww_kkkkkkk_bbbbbbb_7777777
# 2   2 iiiiiii_wwwwwww_qqqqqqq_5555555
# 3   3 iiiiiii_vvvvvvv_bbbbbbb_1111111
# 4   4 hhhhhhh_xxxxxxx_rrrrrrr_4444444
# 5   5 sssssss_eeeeeee_eeeeeee_8888888
# 6   6 ooooooo_ddddddd_rrrrrrr_9999999
# 7   7 yyyyyyy_rrrrrrr_hhhhhhh_1111111
# 8   8 yyyyyyy_rrrrrrr_lllllll_4444444
# 9   9 ggggggg_ggggggg_iiiiiii_6666666
# 10 10 ccccccc_lllllll_jjjjjjj_2222222

你想要这样的东西:

df
#    id                  column
# 1   1 wwwwwww_kkkkkkk_bbbbbbb
# 2   2 iiiiiii_wwwwwww_qqqqqqq
# 3   3 iiiiiii_vvvvvvv_bbbbbbb
# 4   4 hhhhhhh_xxxxxxx_rrrrrrr
# 5   5 sssssss_eeeeeee_eeeeeee
# 6   6 ooooooo_ddddddd_rrrrrrr
# 7   7 yyyyyyy_rrrrrrr_hhhhhhh
# 8   8 yyyyyyy_rrrrrrr_lllllll
# 9   9 ggggggg_ggggggg_iiiiiii
# 10 10 ccccccc_lllllll_jjjjjjj

你可以简单地使用sub:

df$column <- sub("_[0-9]+","",df$column)

sub 允许您替换character 向量中模式的第一个匹配项。此外,它是矢量化的,这使我们能够避免显式循环。在这里,我们使用您要删除«numeric»部分的事实,但如果您只想排除最后一个_之后的部分,您可以考虑这样做:

df$column <- sub("_[0-9a-z]+$","",df$column)

编辑(针对 cme​​ts):

我看不出有任何方法可以避免使用 gregexpr 进行循环。

如果我无论如何都想要一个单线,我可能会这样实现它:

df$column <- substring(df$column, sapply(gregexpr("_", df$column), function(i) i[1]+1), sapply(gregexpr("_", df$column), function(i) i[3]-1))

或者,我们可以继续使用sub。如果您还想删除字符串的第一部分,请处理两次:

df$column <- sub("^[0-9a-z]+_","",df$column)
df$column <- sub("_[0-9a-z]+$","",df$column)

任务完成了。

最后,你也可以考虑使用strsplit

df$column <- sapply(df$column, function(x) paste(strsplit(x,"_")[[1]][2:3],collapse="_"))

(对于后者,请确保您的专栏是 character 而不是 factor

【讨论】:

  • 这很好,但我还需要删除第一部分。在您的示例中,对于第一行,我将拥有:kkkkkkk_bbbbbbb 如果我有一个包含所有模式位置的列表,就像在gregexpr 中一样,这将有所帮助。我会尝试调整你的代码。谢谢!
  • 最后一部分可以是任何东西...不一定是numeric
  • EDIT 的第一个代码完美运行!我不知道我可以这样使用function(i)。非常感谢!
  • 耶!! :-D 那么如果它解决了你的问题,也许你可以接受答案? ;-)
猜你喜欢
  • 2020-05-06
  • 1970-01-01
  • 1970-01-01
  • 2021-11-17
  • 1970-01-01
  • 2020-05-26
  • 2023-02-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多