【问题标题】:R: gsub, pattern = vector and replacement = vectorR:gsub,模式=向量和替换=向量
【发布时间】:2013-10-17 10:52:08
【问题描述】:

正如标题所述,我正在尝试使用 gsub,我将向量用于“模式”和“替换”。目前,我的代码如下所示:

  names(x1) <- gsub("2110027599", "Inv1", names(x1)) #x1 is a data frame
  names(x1) <- gsub("2110025622", "Inv2", names(x1))
  names(x1) <- gsub("2110028045", "Inv3", names(x1))
  names(x1) <- gsub("2110034716", "Inv4", names(x1))
  names(x1) <- gsub("2110069349", "Inv5", names(x1))
  names(x1) <- gsub("2110023264", "Inv6", names(x1))

我希望做的是这样的:

  a <- c("2110027599","2110025622","2110028045","2110034716", "2110069349", "2110023264")
  b <- c("Inv1","Inv2","Inv3","Inv4","Inv5","Inv6")
  names(x1) <- gsub(a,b,names(x1))

我猜在某个地方有一个 apply 函数可以做到这一点,但我不太确定该使用哪一个!

编辑:names(x1) 看起来像这样(还有更多列,但我将它们排除在外):

> names(x1)
  [1] "2110023264A.Ms.Amp"        "2110023264A.Ms.Vol"        "2110023264A.Ms.Watt"       "2110023264A1.Ms.Amp"      
  [5] "2110023264A2.Ms.Amp"       "2110023264A3.Ms.Amp"       "2110023264A4.Ms.Amp"       "2110023264A5.Ms.Amp"      
  [9] "2110023264B.Ms.Amp"        "2110023264B.Ms.Vol"        "2110023264B.Ms.Watt"       "2110023264B1.Ms.Amp"      
 [13] "2110023264Error"           "2110023264E-Total"         "2110023264GridMs.Hz"       "2110023264GridMs.PhV.phsA"
 [17] "2110023264GridMs.PhV.phsB" "2110023264GridMs.PhV.phsC" "2110023264GridMs.TotPFPrc" "2110023264Inv.TmpLimStt"  
 [21] "2110023264InvCtl.Stt"      "2110023264Mode"            "2110023264Mt.TotOpTmh"     "2110023264Mt.TotTmh"      
 [25] "2110023264Op.EvtCntUsr"    "2110023264Op.EvtNo"        "2110023264Op.GriSwStt"     "2110023264Op.TmsRmg"      
 [29] "2110023264Pac"             "2110023264PlntCtl.Stt"     "2110023264Serial Number"   "2110025622A.Ms.Amp"       
 [33] "2110025622A.Ms.Vol"        "2110025622A.Ms.Watt"       "2110025622A1.Ms.Amp"       "2110025622A2.Ms.Amp"      
 [37] "2110025622A3.Ms.Amp"       "2110025622A4.Ms.Amp"       "2110025622A5.Ms.Amp"       "2110025622B.Ms.Amp"       
 [41] "2110025622B.Ms.Vol"        "2110025622B.Ms.Watt"       "2110025622B1.Ms.Amp"       "2110025622Error"          
 [45] "2110025622E-Total"         "2110025622GridMs.Hz"       "2110025622GridMs.PhV.phsA" "2110025622GridMs.PhV.phsB"

我希望得到的是:

> names(x1)
  [1] "Inv6A.Ms.Amp"        "Inv6A.Ms.Vol"        "Inv6A.Ms.Watt"       "Inv6A1.Ms.Amp"       "Inv6A2.Ms.Amp"      
  [6] "Inv6A3.Ms.Amp"       "Inv6A4.Ms.Amp"       "Inv6A5.Ms.Amp"       "Inv6B.Ms.Amp"        "Inv6B.Ms.Vol"       
 [11] "Inv6B.Ms.Watt"       "Inv6B1.Ms.Amp"       "Inv6Error"           "Inv6E-Total"         "Inv6GridMs.Hz"      
 [16] "Inv6GridMs.PhV.phsA" "Inv6GridMs.PhV.phsB" "Inv6GridMs.PhV.phsC" "Inv6GridMs.TotPFPrc" "Inv6Inv.TmpLimStt"  
 [21] "Inv6InvCtl.Stt"      "Inv6Mode"            "Inv6Mt.TotOpTmh"     "Inv6Mt.TotTmh"       "Inv6Op.EvtCntUsr"   
 [26] "Inv6Op.EvtNo"        "Inv6Op.GriSwStt"     "Inv6Op.TmsRmg"       "Inv6Pac"             "Inv6PlntCtl.Stt"    
 [31] "Inv6Serial Number"   "Inv2A.Ms.Amp"        "Inv2A.Ms.Vol"        "Inv2A.Ms.Watt"       "Inv2A1.Ms.Amp"      
 [36] "Inv2A2.Ms.Amp"       "Inv2A3.Ms.Amp"       "Inv2A4.Ms.Amp"       "Inv2A5.Ms.Amp"       "Inv2B.Ms.Amp"       
 [41] "Inv2B.Ms.Vol"        "Inv2B.Ms.Watt"       "Inv2B1.Ms.Amp"       "Inv2Error"           "Inv2E-Total"        
 [46] "Inv2GridMs.Hz"       "Inv2GridMs.PhV.phsA" "Inv2GridMs.PhV.phsB" 

【问题讨论】:

  • 你能举一些names(x1)的例子吗?
  • 请将names( x1 )的输出添加到问题中...
  • 我添加了名字(x1),谢谢。

标签: r


【解决方案1】:

已经有很多解决方案了,这里还有一个:

qdap 包:

library(qdap)
names(x1) <- mgsub(a,b,names(x1))

【讨论】:

  • mapply 并不能真正工作,因为 gsub 仍然不能在向量上工作,但是 qdap 包可以完美地工作。因此,我选择这个作为接受的答案。
  • 注意:qdap 有大量依赖项。
  • 自从我写了它我就很清楚了。其次,不需要你的警告。它是开源的,此信息在文档的第一页中清楚地说明。
  • 这就像在说“没有必要说明这个答案中使用的库,因为你总是可以用谷歌搜索这个函数”。当然,警告可能没有必要,但不做进一步研究就知道了。
【解决方案2】:

来自str_replace_allstringr 文档,“如果您想对同一个字符串应用多个模式和替换,请将一个命名的 版本传递给模式。”

因此使用上面的 a、b 和 names(x1)

stringr::str_replace_all(names(x1), setNames(b, a))

编辑

stringr::str_replace_all调用stringi::stri_replace_all_regex,可以直接使用,速度也快一些。

x <- names(x1)
pattern <- a
replace <- b

microbenchmark::microbenchmark(
  str  = stringr::str_replace_all(x, setNames(replace, pattern)),
  stri = stringi::stri_replace_all_regex(x, pattern, replace, vectorize_all = FALSE)
  )

Unit: microseconds
 expr    min      lq     mean  median   uq    max neval cld
  str 1022.1 1070.45 1286.547 1175.55 1309 2526.8   100   b
 stri  145.2  150.45  190.124  160.55  178  457.9   100  a 

【讨论】:

  • str_replace_all 与原始发帖人的gsub 相当。但是str_replace 在某些情况下可能是首选。
【解决方案3】:

新答案

如果我们可以做出另一个假设,那么以下应该可行。这次的假设是您真的有兴趣替换 names(x1) 中每个值的前 10 个字符。

在这里,我将names(x1) 存储为一个名为“X1”的字符向量。该解决方案本质上使用substr 将X1 中的值分成两部分,match 找出正确的替换选项,paste 将所有内容重新组合在一起。

a <- c("2110027599", "2110025622", "2110028045",
       "2110034716", "2110069349", "2110023264")
b <- c("Inv1","Inv2","Inv3","Inv4","Inv5","Inv6")

X1pre <- substr(X1, 1, 10)
X1post <- substr(X1, 11, max(nchar(X1)))

paste0(b[match(X1pre, a)], X1post)
#  [1] "Inv6A.Ms.Amp"        "Inv6A.Ms.Vol"        "Inv6A.Ms.Watt"      
#  [4] "Inv6A1.Ms.Amp"       "Inv6A2.Ms.Amp"       "Inv6A3.Ms.Amp"      
#  [7] "Inv6A4.Ms.Amp"       "Inv6A5.Ms.Amp"       "Inv6B.Ms.Amp"       
# [10] "Inv6B.Ms.Vol"        "Inv6B.Ms.Watt"       "Inv6B1.Ms.Amp"      
# [13] "Inv6Error"           "Inv6E-Total"         "Inv6GridMs.Hz"      
# [16] "Inv6GridMs.PhV.phsA" "Inv6GridMs.PhV.phsB" "Inv6GridMs.PhV.phsC"
# [19] "Inv6GridMs.TotPFPrc" "Inv6Inv.TmpLimStt"   "Inv6InvCtl.Stt"     
# [22] "Inv6Mode"            "Inv6Mt.TotOpTmh"     "Inv6Mt.TotTmh"      
# [25] "Inv6Op.EvtCntUsr"    "Inv6Op.EvtNo"        "Inv6Op.GriSwStt"    
# [28] "Inv6Op.TmsRmg"       "Inv6Pac"             "Inv6PlntCtl.Stt"    
# [31] "Inv6Serial Number"   "Inv2A.Ms.Amp"        "Inv2A.Ms.Vol"       
# [34] "Inv2A.Ms.Watt"       "Inv2A1.Ms.Amp"       "Inv2A2.Ms.Amp"      
# [37] "Inv2A3.Ms.Amp"       "Inv2A4.Ms.Amp"       "Inv2A5.Ms.Amp"      
# [40] "Inv2B.Ms.Amp"        "Inv2B.Ms.Vol"        "Inv2B.Ms.Watt"      
# [43] "Inv2B1.Ms.Amp"       "Inv2Error"           "Inv2E-Total"        
# [46] "Inv2GridMs.Hz"       "Inv2GridMs.PhV.phsA" "Inv2GridMs.PhV.phsB"

旧答案

如果我们可以假设 names(x1) 与模式和替换的顺序相同,并且基本上是一对一的替换,那么您也许可以只使用 sapply

以下是该特定情况的示例:

想象一下“names(x)”看起来像这样:

X1 <- paste0("A2", a, sequence(length(a)))
X1
# [1] "A221100275991" "A221100256222" "A221100280453" 
# [4] "A221100347164" "A221100693495" "A221100232646"

这是我们的 patternreplacement 向量:

a <- c("2110027599", "2110025622", "2110028045", 
       "2110034716", "2110069349", "2110023264")
b <- c("Inv1","Inv2","Inv3","Inv4","Inv5","Inv6")

如果这些假设成立,这就是我们可以使用sapply 的方式。

sapply(seq_along(a), function(x) gsub(a[x], b[x], X1[x]))
# [1] "A2Inv11" "A2Inv22" "A2Inv33" "A2Inv44" "A2Inv55" "A2Inv66"

【讨论】:

    【解决方案4】:

    试试mapply

    names(x1) <- mapply(gsub, a, b, names(x1), USE.NAMES = FALSE)
    

    或者,更简单的是,str_replace 来自 stringr

    library(stringr)
    names(x1) <- str_replace(names(x1), a, b)
    

    【讨论】:

    • 我已经在上面发布了这个答案,但这里不需要USE.NAMES = FALSE
    • @TylerRinker 是的,你打败了我。 USE.NAMES = FALSE 提供了一个较小的性能优势,对于大型数据集,它可以为您节省几乎与您键入额外字符所花费的时间一样多的时间。
    • 我尝试了 stringr 包中的 str_replace_all ,它应该按照描述的那样做。但是,它给了我一个错误: check_pattern(pattern, string, replacement) 中的错误:字符串和模式的长度不兼容编辑:我意识到 str_replace_all 需要 names(x1) 与 a 和 b 的长度相同,这是它不起作用的原因。
    • @WetFeet 这不是说str_replace 解决方案是错误的吗?我想是的,但不确定,因为还没有人提出这个问题。
    • 我认为mapply 也不起作用,因为它不会递归地将 gsub 应用于名称(x1)
    【解决方案5】:

    不知何故,names&lt;-match 在这里似乎更合适...

    names( x1 ) <- b[ match( names( x1 ) , a ) ]
    

    但我假设向量a 的元素是您的data.frame 的实际names

    如果a 确实是在x1names 的每个names 中发现的模式,那么这种grepl 方法与names&lt;- 可能会很有用...

    new <- sapply( a , grepl , x = names( x1 ) )
    names( x1 ) <- b[ apply( new , 1 , which.max ) ]
    

    【讨论】:

    • 由于模式是在 x1 的名称中找到的,因此 match 返回 NA 值。 grep1 并没有真正起作用,因为它用数字替换了名称的整个部分而不是部分(如在编辑中)
    【解决方案6】:

    我需要做类似的事情,但必须使用基数 R。只要你的向量长度相同,我认为这会起作用

    for (i in seq_along(a)){
      names(x1) <- gsub(a[i], b[i], names(x1))
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-16
      • 2015-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多