我正在尝试将所有Normal1, Normal2, Normal3
替换为Normal
。
df=data.frame(col1=1:4, col2=c("Normal", "Normal2", "Normal3", "Normal"))
当我尝试这个df %>% filter(grepl("^Nor", col2)) %>% gsub("Normal.*","Normal", df$col2)
Warning message:
In gsub(., "Normal.*", "Normal", df$col2) :
argument 'pattern' has length > 1 and only the first element will be used
如何解决这个问题? 感谢。
答案 0 :(得分:0)
这里涉及两个概念:
%>%
告诉下一个函数使用filter(grepl("^Nor", col2))
生成的数据作为下一个函数的第一个参数。 gsub
的参数列表的排序方式与tidyverse
函数不同:grep,grepl,regexpr,gregexpr和regexec在字符向量的每个元素中搜索与参数模式的匹配:它们在结果的格式和细节数方面不同。 sub和gsub分别执行第一个和所有匹配的替换。
gsub(模式,替换, x ,ignore.case = FALSE,perl = FALSE, fixed = FALSE,useBytes = FALSE)
因此, x 参数是您尝试替换的矢量"正常"值属于函数。 gsub
并未意识到您正试图将数据放在除第一个参数之外的其他位置。
gsub适用于一列数据,您传递的内容是数据帧。原样,你的管道有:
你可以对数据结构感兴趣,以便将gsub公开为管道的直接参与者(因为你现在已经得到它)。 m-dz对this question的回答是如何做到的。从本质上讲,您需要告诉您的代码它应该传递上一步中的数据参数而不是下一个函数的第一个参数。
那就是说,我强烈推荐G. Grothendieck建议的方法。具体而言,将您使用gsub
mutate
功能的数据清理干净。
我认为这是一种更好的方法有几个原因:
dplyr
,并了解mutate
的作用。通过将数据清理步骤放入mutate
,您可以对其他人(包括future you)说:"在此步骤中,我正在修改col2
,此处&# 39;我是如何修改它的。" gsub
中的任意位置。在mutate
中,data参数是第一个参数,和它将该参数公开给定义/修改数据帧的函数。这使得在第一个参数以外的函数中的位置引用数据变得容易。我从iris
数据集构建了一个可重现的示例:
iris %>%
# create a fake "col2" to demonstrate Normal1, Normal2, Normal3
mutate(
options = runif(nrow(iris)),
col2 = ifelse(options > 0.333, "Normal2", "Normal1"),
col2 = ifelse(options > 0.666, "Normal3", col2),
options = NULL) %>%
filter(grepl("virginica", .$Species)) %>%
# example of how wrapping gsub in mutate can accomplish the goal
mutate(col2 = gsub("Normal.*", "Normal", .$col2))
替代mutate()
如果您真的致力于不使用mutate
,您还可以编写自己的函数,包含对gsub的调用并将数据帧作为其第一个参数。一个例子可能如下所示:
gsub_dataframe <- function(data, pattern, replacement, column) {
data[column] <- gsub(pattern, replacement, data[[column]])
return(data)
}
我不建议这样做,因为它会向分析管道添加更多自定义代码,基于mutate
的解决方案会做同样的事情而其他用户已经熟悉它。