“Case_when”取决于R中元素的索引?

uttx8gqw  于 5个月前  发布在  其他
关注(0)|答案(4)|浏览(83)

向量化操作的工作方式是将逻辑应用于向量的每个元素。
但是,假设我有一个向量,即。

> 1:10
[1]  1  2  3  4  5  6  7  8  9 10

字符串
我想应用一个函数,比如说,对除了第一个和最后一个元素之外的每个元素乘以0.5:我想把它们乘以0.3。
有没有一个dspur(或任何其他矢量化)的方法来做到这一点?
我知道sapply与if-else结构可以做到这一点,即。

sapply(seq(1:10), #I know seq() is not actually needed in this particular case
    function(i) {
        if(i == 1 | i == length(1:10)) {
            (1:10)[i]*0.3
        } else {
            (1:10)[i]*0.5
        }
    }
)


.但是使用索引依赖的case_when的向量化解决方案会很好。

fhity93d

fhity93d1#

由于您在标题中明确提到了case_when,因此一个索引相关的case_when解决方案可能是:

library(dplyr)

x <- 1:10

data.frame(x) %>%
  mutate(x_mult = case_when(
    row_number() == 1 | row_number() == n() ~ x * 3,
    TRUE ~ x * 5
  ))

字符串
输出量:

x x_mult
1   1      3
2   2     10
3   3     15
4   4     20
5   5     25
6   6     30
7   7     35
8   8     40
9   9     45
10 10     30

rpppsulh

rpppsulh2#

ifelse是矢量化的,因此您可以使用

x <- 1:10
x * ifelse(seq_along(x) %in% c(1, length(x)), 0.3, 0.5)
#[1] 0.3 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 3.0

字符串
这是另一个具有相同逻辑但没有ifelse的。

x * c(0.5, 0.3)[seq_along(x) %in% c(1, length(x)) + 1]


其中seq_along(x) %in% c(1, length(x)) + 1创建一个索引(1或2),并用于子集向量c(0.5, 0.3)乘以x。然而,在我看来,使用ifelse不那么令人困惑。

jv2fixgn

jv2fixgn3#

因此,正如我所看到的,你想用乘以0.3的值替换第一个和最后一个元素,否则乘以0.5。
你可以通过以下方式做到这一点:

x <- 1:10
x[ x == 1 | x == length(x)] <- 0.3 * x[1]
x <- 0.5 * x

字符串
作为一个功能:

modify_by_factors <- function(vec, first_last_k=0.3, other_k=0.5) {
  # multiply by other_k all values by vectorization
  res <- vec * other_k
  
  # overwrite first and last value
  res[1] <- vec[1] * first_last_k
  res[length(vec)] <- vec[length(vec)] * first_last_k

  # return result vector
  res
}


使用此函数,您可以将0.3和0.5作为因子更改为不同的值。
速度方面,这可能是比使用ifelsemutate或任何apply函数更快的解决方案。

v9tzhpje

v9tzhpje4#

还有一个选择:

library(magrittr)

foo <- \(x) {
  n <- length(x)
  x[ c(1,n)] %<>% multiply_by(0.3)
  x[-c(1,n)] %<>% multiply_by(0.5)
  x
}

foo(1:10)
# [1] 0.3 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 3.0

字符串

相关问题