使用重复名称更改R向量中的多个元素

6

假设我有一个包含重复名称的向量:

x <- c(a=1, b=2, a=3, c=4, c=5, b=1, d=1)

我希望您能查找和更改命名元素。如果我定义了一个元素:
ElementsToChange <- c("a","b","c")

ChangeTo <- c(9,8,7)

我想将所有名为“a”的元素更改为9,所有名为“b”的元素更改为8等。如果我这样做:
x[ElementsToChange] <- ChangeTo

这将仅更改第一个元素,而不是所有元素。

如何以简单而优雅的方式更改所有元素?


1
请问如何在Python中使用正则表达式来匹配一个字符串中的所有数字?我想要将这些数字提取出来并进行一些处理。谢谢! - agenis
1
另一种方法是 v1 <- setNames(setNames(ChangeTo, ElementsToChange)[names(x)], names(x));v1[is.na(v1)] <- x[is.na(v1)] - akrun
3
我想说的是,“嘿,这个问题可能会有帮助”;-) - agenis
6个回答

10
你可以使用单个split命令来完成:
split(x, names(x))[ElementsToChange] <- ChangeTo
#x
#a b a c c b d 
#9 8 9 7 7 8 1 

首先按照名称将x向量拆分,然后对属于ElementsToChange向量的所有元素进行子集,并用ChangeTo值替换这些值。

* 实际上,在这里你正在使用split<-,即在拆分的数据上进行赋值。原始向量后续会保留其结构。


2
这是一个非常棒的解决方案。我从来没有想到过在分割后可以进行赋值! - agenis

4

我猜你需要保留没有匹配的内容,这使得它稍微不太优雅:

ifelse(names(x)%in%ElementsToChange,ChangeTo[match(names(x),ElementsToChange)],x)
[1] 9 8 9 7 7 8 1

如果你想要恢复名称,你需要重新命名向量。

2
或者类似的,不使用ifelse,m <- match(names(x), ElementsToChange); replace(x, !is.na(m), ChangeTo[na.omit(m)]) - Frank
@Frank,为什么不用 x[!is.na(m)] <- ChangeTo[na.omit(m)] 而不是替换呢? - Mike H.
@MikeH 是的。看着 replace 的代码,它们本质上是相同的。replaceifelse 一样,创建一个新对象,而你的方法修改了 x(更接近于 OP 想要的)。 - Frank
1
@Frank,我觉得这是最完整/简单的解决方案,所以我更新了我的答案。不过既然你已经完成了大部分工作,随意发表它,我可以回到我的原始(更糟糕)的解决方案。 - Mike H.

3

当命名元素唯一时,命名元素的效果会更好,但您可以进行如下操作:

Reduce(function(x, z) {
  x[names(x)==z$k] <- z$v
  x
}, split(data.frame(k=ElementsToChange, v=ChangeTo), seq_along(ChangeTo)), init=x)
# a b a c c b d 
# 9 8 9 7 7 8 1

但是如果在数据框中使用适当的键/值,就可以更轻松地完成这项任务。
library(tidyverse)
dd <- data_frame(k=names(x), v=x)
tt <- data_frame(k=ElementsToChange, newv=ChangeTo)
dd %>% left_join(tt) %>% mutate(v=coalesce(newv, v), newv=NULL)

3
另一种选项是直接用<-替换,感谢@Frank的贡献:
m <- match(names(x), ElementsToChange)
x[!is.na(m)] <- ChangeTo[na.omit(m)]

x
a b a c c b d 
9 8 9 7 7 8 1 

由于它直接替换,因此它也保留名称。 您可以将x子集化为仅包含在ElementsToChange中的名称,然后用ChangeTo中匹配的元素替换它们的值。


2
ids = match(names(x), ElementsToChange)
replace(x, which(!is.na(ids)), ChangeTo[ids[!is.na(ids)]])
#a b a c c b d 
#9 8 9 7 7 8 1 

0
您可以使用此函数并提供您的 elementsToChange 和 changeTo 向量以获取更改后的列表。
library(dplyr)

change <- function(x, elementsToChange = c("a"), changeTo=c(5)){

  if(length(elementsToChange)!=length(changeTo)) {stop("length of elementsToChange is not equal to changeTo")}
  temp<- tibble(name = names(x), value = x)
  temp.change<- tibble(name = elementsToChange, value = changeTo)
  temp2<-temp%>%left_join(temp.change, by = "name")
  temp2<-within(temp2, {
    value.y[is.na(value.y)]<- value.x[is.na(value.y)]
  })
  ret<-temp2$value.y
  names(ret)<-temp2$name
  return(ret)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接