【问题标题】:Replace given value in vector替换向量中的给定值
【发布时间】:2012-07-29 01:08:12
【问题描述】:

我正在寻找一个函数,它将用另一个值替换所有出现的一个值。 例如,我想用一替换所有零。 我不想将结果存储在变量中,但希望能够匿名使用向量作为更大表达式的一部分。

我自己会写一个合适的函数:

> vrepl <- function(haystack, needle, replacement) {
+   haystack[haystack == needle] <- replacement
+   return(haystack)
+ }
> 
> vrepl(c(3, 2, 1, 0, 4, 0), 0, 1)
[1] 3 2 1 1 4 1

但我想知道是否有一些标准功能可以完成这项工作,最好来自base 包,作为其他常用包的替代品。我相信使用这样的标准可能会使我的代码更具可读性,并且我不必在需要的地方重新定义该函数。

【问题讨论】:

  • as.numeric(gsub(0, 1, c(3, 2, 1, 0, 4, 0))) 这样的东西有用吗?
  • vec[vec==vec]&lt;-replacement

标签: r replace


【解决方案1】:

也许replace 就是你要找的东西:

> x = c(3, 2, 1, 0, 4, 0)
> replace(x, x==0, 1)
[1] 3 2 1 1 4 1

或者,如果您没有x(有什么具体原因吗?):

replace(c(3, 2, 1, 0, 4, 0), c(3, 2, 1, 0, 4, 0)==0, 1)

很多人都熟悉gsub,所以您也可以尝试以下任一方法:

as.numeric(gsub(0, 1, x))
as.numeric(gsub(0, 1, c(3, 2, 1, 0, 4, 0)))

更新

看完cmets,或许with是个选项:

with(data.frame(x = c(3, 2, 1, 0, 4, 0)), replace(x, x == 0, 1))

【讨论】:

  • 请记住,除非重新分配,否则 x 不会更改。
  • 不命名x的具体原因是计算x的表达式本身可能比较长。而且我想避免用太多变量破坏我的命名空间。所以我希望有一种方法可以避免必须命名向量,或者不必复制它的表达式。 gsub 和它的中间字符在性能和精度方面也感觉不对,尤其是在处理浮点数时。
  • 我绝对可以而且应该在我自己的vrepl 实现中使用replace,除非有人会提出一个完全废弃我自己功能的答案。所以感谢您指出这一点!
  • @MvG,怎么样:with(data.frame(x = c(3, 2, 1, 0, 4, 0)), replace(x, x == 0, 1))?
【解决方案2】:

另一个更简单的选择是:

 > x = c(1, 1, 2, 4, 5, 2, 1, 3, 2)
 > x[x==1] <- 0
 > x
 [1] 0 0 2 4 5 2 0 3 2

【讨论】:

  • 这需要将中间结果保存到一个命名变量中,正如我在问题中所说的那样,我想避免这种情况。
  • @MvG:抱歉,错过了那部分。无论如何,将它保存在变量中更易于维护
【解决方案3】:

一个简单的方法是使用矢量化的ifelse。如果满足条件,我们使用替换值,否则使用原始值。

v <- c(3, 2, 1, 0, 4, 0)
ifelse(v == 0, 1, v)

我们可以通过使用管道来避免命名变量。

c(3, 2, 1, 0, 4, 0) %>% ifelse(. == 0, 1, .)

一个常见的任务是进行多次替换。我们可以使用 dplyr 中的 case_when 代替嵌套的 ifelse 语句:

case_when(v == 0 ~ 1,
          v == 1 ~ 2,
          TRUE ~ v)

旧答案:

对于因子或字符向量,我们可以使用revalue from plyr

> revalue(c("a", "b", "c"), c("b" = "B"))
[1] "a" "B" "c"

这样的好处是只指定输入向量一次,所以我们可以使用像管道这样的管道

x %>% revalue(c("b" = "B"))

【讨论】:

  • 我会投票支持你在 2018 年使用 plyr - 一定很难在石头下生活:p
  • @MSBerends 因为 dplyr (主要)使用数据帧我不知道 dplyr 解决方案
【解决方案4】:

要替换多个数字:

vec <- 1:10
replace(vec, vec== c(2,6), c(0,9)) #2 and 6 will be replaced by 0 and 9.

编辑:

对于连续系列,您可以这样做vec &lt;- c(1:10); replace(vec, vec %in% c(2,6), c(0,9)) 但是对于vec &lt;- c(1:10,2,2,2); replace(vec, vec %in% c(2,6), 0),我们可以用一个值替换多个值。

【讨论】:

  • >警告消息:在 replace(vec, vec == c(2, 6), c(0, 9)) 中:要替换的项目数不是替换长度的倍数
【解决方案5】:

为什么大惊小怪?

replace(haystack, haystack %in% needles, replacements)

演示:

haystack <- c("q", "w", "e", "r", "t", "y")
needles <- c("q", "w")
replacements <- c("a", "z")

replace(haystack, haystack %in% needles, replacements)
#> [1] "a" "z" "e" "r" "t" "y"

【讨论】:

  • 请注意,此答案假定针头和替换是一对一的(必要时回收向量)。
  • 这也取决于haystackneedlesreplacements 的排序。将后者切换为c("w", "q")c("z", "a")replace()会产生废话。
【解决方案6】:

ifelse 函数将是一种快速简便的方法。

【讨论】:

  • 我必须给出相同的向量两次,一次用于test 参数,一次作为结果参数,对吧?似乎没有比建议的 replace 呼叫 mrdwab 更容易。
  • 正确,但您可以将其保存在临时变量中,然后引用两次。 ifelsereplace 都可以完成这项工作。
  • +1 这实际上比正确的解决方案好很多,因为它提供了将函数应用于值的额外选项。谢谢@Greg Snow!
  • 提供一个使用示例会很有帮助。
【解决方案7】:

如果你想一次性替换很多值,你可以使用 'library(car)'。

示例

library(car)

x <- rep(1:5,3)

xr <- recode(x, '3=1; 4=2')

x
## [1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
xr
## [1] 1 2 1 2 5 1 2 1 2 5 1 2 1 2 5

【讨论】:

    猜你喜欢
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多