【问题标题】:lapply? and recursive partial replacement, data frame应用?和递归部分替换,数据框
【发布时间】:2016-02-09 15:25:03
【问题描述】:

我想简化模式匹配以更新数据帧。例如,需要将零添加到所有单个字符,字段 2 和 3:

set.seed(5)
x<-data.frame(Site=c(rep("Site A",5),rep("Site B",5)),
  Upstream=rep(c("A5","B","B5","C","C5"),2),
  Downstream=rep(c("A","A5","B","B5","C"),2),
  Value=sample(100:200,10), stringsAsFactors=FALSE)

此解决方案效果很好,逐个字段:

r<-data.frame(V1=LETTERS[1:11],V2<-paste0(LETTERS[1:11],"0"), stringsAsFactors=FALSE)                 
replc<-r[,2][match(x[,3],r[,1])]
x[,3]<-ifelse(is.na(replc),x[,3],replc) 

对于多个字段,这些基于列表的尝试会产生一些有趣的结果,但不是我想要的:

s2<-LETTERS[seq(1:11)]
lapply(s2,function(z){replace(x[,3],x[,3]==z,paste0(z,"0"))})                  
lapply(s2,function(z){x[,3][x[,3]==z]<-paste0(z,"0")})                         
lapply(s2,function(z){x[x[,3]==z,]<-paste0(z,"0");x} )                        
lapply(s2,function(z){within(x,x[,3][x[,3]==z]<-paste0(z,"0"))} )               
lapply(s2,function(z){(with(x,{x[x[,3]==z,]<-paste0(z,"0")}))} )  

通过反复试验,上述变化已经奏效,但随后我得到了不匹配的 NA(所有值都以 5 结尾)。所以,我至少错过了一些东西,比如回收 df 和处理 NA。

如果上述方法有效,那么我只想循环遍历许多字段,并按照以下方式进行替换:

lapply(x[,2;3], function(y){
        lapply(s2,function(z){x[,y][a[,y]==z]<-paste0(z,"0")})      
        })

感谢您的帮助。

【问题讨论】:

  • 或者,类似于Jimbou的建议:x[] &lt;- lapply(x, function(y) ifelse(nchar(y) == 1, paste0(y, 0), y))
  • 我去掉了括号。对不起。是的,这些建议看起来应该可行。感谢您的帮助。
  • 我缺少括号,抱歉。是的,这些建议看起来应该可行。感谢您的帮助。这个问题更普遍,但并非所有字符串都以 5 结尾。

标签: r recursion multiple-columns lapply


【解决方案1】:

我愿意……

mycols = 2:3
x[, mycols] <- lapply(x[, mycols], function(z) sub("^(.)$", "\\10", z))

给了

     Site Upstream Downstream Value
1  Site A       A5         A0   120
2  Site A       B0         A5   168
3  Site A       B5         B0   190
4  Site A       C0         B5   127
5  Site A       C5         C0   110
6  Site B       A5         A0   167
7  Site B       B0         A5   150
8  Site B       B5         B0   175
9  Site B       C0         B5   188
10 Site B       C5         C0   196

这使用正则表达式来识别构成完整字符串的单个字符.——从开始^ 到结束$。括号标识在替换中由\\1 引用的“组”。

【讨论】:

  • 太棒了。试一试。
  • 正是我想要的。我可以将其包装在我的数据框列表中并过滤到要更新的字段。
  • 那个正则表达式注释很有用。我可以将它与过滤器结合使用。那么,这是否意味着两个字符 (..) 而这个 \\20 意味着添加零作为第三个字符?
  • @user2009447 对于两个字符,是的,应该可以。 "^(..)$" 作为模式,"\\10" 作为替换(因为 \\1 “反向引用”指的是“组”计数器,它仅取决于模式中的括号)。您也可以使用量词,例如"^(.{2})$",而不是写出每个点。有关更多详细信息,请尝试 R 中的 ?regex 或任何有关正则表达式的在线资源(因为它们在其他语言中相似)。
【解决方案2】:

没有正则表达式你可以使用这个:

mycols = 2:3
x[, mycols] <- apply(x[,mycols], 2, function(x) ifelse(nchar(x)<2, paste0(x,0), x))

如果字符串的长度小于 2,该函数将在字符串后面粘贴一个 0。正如 docendo discimus 所评论的,您还可以使用 nchar(x) == 1 搜索长度正好为 1 的字符串。

【讨论】:

  • 也试试这个。谢谢。
  • lapplyapply 更受欢迎,因为后者将列组合成一个矩阵并返回一个矩阵(然后必须在分配给 @987654326 时将其拆分回列@)。
  • 这也很好用,我可以修改它以获得更通用的解决方案和数据框列表。s
  • 实际上,我现在可以看到这种方法与我最近为一组不同的数据帧进行的一些统计和测试有一些相似之处。列
猜你喜欢
  • 2020-11-13
  • 1970-01-01
  • 2021-01-24
  • 1970-01-01
  • 2021-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
相关资源
最近更新 更多