基于另一个向量的条件创建新的向量

5
我有一个向量v1 = c(0, 3, 5, 1, 1, 1, 3, 5, 0)。如何创建一个等长的向量,但如果原向量中的值为0或3,则新向量中的值为-1,如果原向量中的值为1或5,则新向量中的值为1。
所以,对于v1 = c(0, 3, 5, 1, 1, 3, 5, 0),我期望得到一个新的向量: v2 = c(-1, -1, 1, 1, 1, -1, 1, -1)

在第一个版本v1中,你有更多的1吗?是打字错误吗? - zx8754
7个回答

7
另一种可能性是:
v2 <- c(-1,1)[1 + (v1 %in% c(1,5))]

这将会给出:

> v2
[1] -1 -1  1  1  1 -1  1 -1

这段代码的作用:

  • v1 %in% c(1,5) 创建了一个逻辑向量
  • 通过加上 1,你创建了一个由 12 组成的整数向量。
  • 您可以将其用作索引向量在 c(-1,1) 上,这将创建所需的结果。

如果 v1 包含除 0135 之外的其他数字,则应更加明确:

v2 <- c(-1,1)[(v1 %in% c(0,3)) + 2*(v1 %in% c(1,5))]

6
在包car中有一个名为recode()的函数:
library("car")
v1 = c(0, 3, 5, 1, 1, 3, 5, 0)
# v2 = c(-1, -1, 1, 1, 1, -1, 1, -1)
recode(v1, "c(0, 3)=-1; else=1")
# [1] -1 -1  1  1  1 -1  1 -1

或者(如果你想将NA设置为不在c(0,1,3,5)中的值):
recode(v1, "c(0, 3)=-1; c(1, 5)=1; else=NA")

5

我假设你对R完全不了解。你可以创建一个全是 0 的向量v2,然后使用简单的逻辑运算符来完成其余操作。如下:

v1 <- c(0, 3, 5, 1, 1, 1, 3, 5, 0)
#this creates a vector in which 0 is repeated length(v1) times
v2 <- rep(0,length(v1)) 

v2[v1 == 1 | v2 == 5] <- 1
v2[v1 == 0 | v2 == 3] <- -1    

2
你为什么要创建一个全是零的向量,而不直接定义它为v2 <- v1呢? - Seymour
@Seymour 旧的 numpy 习惯 - iliupersis

3
您期望的输出缺少一个值,因为其长度小于输入向量长度。
v1 = c(0, 3, 5, 1, 1, 1, 3, 5, 0)

v2 <- ifelse(v1 == 0 | v1 == 3, -1, ifelse(v1 == 1 | v1 == 5, 1, v1))

your_result <- c(-1, -1,  1,  1,  1,  1, -1,  1, -1)
identical(v2, your_result)
[1] TRUE

3
 v1 = c(0, 3, 5, 1, 1, 3, 5, 0)
 v2 <- ifelse(v1 == 0 | v1 == 3, -1, 1)
 v2
 # [1] -1 -1  1  1  1 -1  1 -1

使用vector()函数和ifelse()函数,按照条件填充空的向量进行替代方案I。

v1 = c(0, 3, 5, 1, 1, 3, 5, 0)
v1
# [1] 0 3 5 1 1 3 5 0

## Empty Numeric vector of length v1  
Vec <- vector("numeric",length = length(v1))
Vec
# [1] 0 0 0 0 0 0 0 0

## Filling for 0 or 3
Vec[] <- ifelse(v1 == 0 | v1 == 3, -1, v1)
Vec
# [1] -1 -1  5  1  1 -1  5 -1

## Filling for 1 or 5
Vec[] <- ifelse(v1 == 1 | v1 == 5, 1, Vec)
Vec
# [1] -1 -1  1  1  1 -1  1 -1

使用%in%,以及vector()ifelse()填充空向量的备选方案II

v1 = c(0, 3, 5, 1, 1, 3, 5, 0)
v1
# [1] 0 3 5 1 1 3 5 0

Result <- vector("numeric",length = length(v1))
Result
# [1] 0 0 0 0 0 0 0 0

Result[] <- ifelse(v1 %in% c(0,3), -1, v1)
Result
# [1] -1 -1  5  1  1 -1  5 -1

Result[] <- ifelse(Result %in% c(1,5), 1, Result)
Result
# [1] -1 -1  1  1  1 -1  1 -1

此解决方案没有考虑第二个条件。 - Seymour
由于只有两个条件,您不需要它。即使通过按条件填充空向量也提供了替代方案。 - Sowmya S. Manian

3
你也可以尝试使用tidyverse解决方案。
library(tidyverse)
mutate(tibble(a=c(0, 3, 5, 1, 1, 1, 3, 5, 0)),
              b=case_when(a %in% c(0,3) ~ -1,
                          a %in% c(1,5) ~ 1))
# A tibble: 9 x 2
      a     b
  <dbl> <dbl>
1    0.   -1.
2    3.   -1.
3    5.    1.
4    1.    1.
5    1.    1.
6    1.    1.
7    3.   -1.
8    5.    1.
9    0.   -1.

添加 pull 后,您将得到向量

.Last.value %>% pull(b)
[1] -1 -1  1  1  1  1 -1  1 -1

2

我看到了很多好的答案,我会再添加一种类似编程的方法。

v1 <- c(0, 3, 5, 1, 1, 1, 3, 5, 0)
v2 <- integer(length(v1))

for (i in 1:length(v1)){
  # if val is equal to 0 or 3 new value is set to -1
  if (v1[i] == 0 | v1[i] == 3){
    new_val <- -1
  }
  # if val is equal to 1 or 5 new value is set to 1
  else if (v1[i] == 1 | v1[i] == 5 ){
    new_val <- 1
  }
  # else the value remains the same
  else{
    new_val <- v1[i]
  }
  v2[i] <- new_val 
}
v2
# -1 -1  1  1  1  1 -1  1 -1

6
这句话的意思是,这种写法不太像编程,因为任何优秀的程序员都知道你不应该在循环中扩展一个向量。 - Roland
我想我的 Python 本性在这里发挥了最大的作用。我明白向量一直被复制,对于更大的数据集可能会很慢。然而,这只是一个小例子,运行良好。更多的编程意味着更完整地书写。因此,提问者可以获得关于 R 的更多知识。所以我希望你将有害评论留给自己。Stackoverflow 社区已经够有毒了。 - candah
1
在R中,for循环并不是你应该使用的工具,尽管在更低级别的编程语言中,它可能是首选。因此,我假设你只是出于教学目的而展示这个例子。然而,如果确实是这种情况,你当然应该通过预分配向量并将其赋值来展示良好的编程实践,在R中这很容易做到,并且在其他(更低级别的)编程语言中也是如此。没有任何借口可以推广不良实践。 - Roland
1
将答案更改为更高效的R解决方案。我现在要躲起来了。希望Roland找不到我:s - candah

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