R 矢量化列选择

R 矢量化列选择,r,switch-statement,tidyverse,R,Switch Statement,Tidyverse,当选择特定于每一行时,如何使用一列的值(如下面的x)在可能的列中选择值 x变量确定是否应为给定行选择变量a、b或c。这里有一个简化的例子;真正的单元格不是列名和行号的串联 library(magrittr); requireNamespace("tibble"); requireNamespace("dplyr") ds <- tibble::tibble( x = c( 1 , 1 , 2 , 3 , 1 ), a = c("a1", "a2", "a

当选择特定于每一行时,如何使用一列的值(如下面的x)在可能的列中选择值

x变量确定是否应为给定行选择变量a、b或c。这里有一个简化的例子;真正的单元格不是列名和行号的串联

library(magrittr); requireNamespace("tibble"); requireNamespace("dplyr")

ds <- tibble::tibble(
  x   = c(  1 ,   1 ,   2 ,   3 ,   1 ),
  a   = c("a1", "a2", "a3", "a4", "a5"),
  b   = c("b1", "b2", "b3", "b4", "b5"),
  c   = c("c1", "c2", "c3", "c4", "c5")
)
并且以下内容会产生错误: mutate_impl.data中出错,dots:basic_string::_M_replace_aux

如果我的真实场景只有两个或三个选择,我可能会使用嵌套的ifs,但我希望使用一种通用的映射方法来适应更多的条件

ds %>% 
  dplyr::mutate(
    y_if_chain = ifelse(x==1, a, ifelse(x==2, b, c))
  )
理想情况下,该方法可以由查找表或其他元数据对象(如:

ds_lookup <- tibble::tribble(
  ~x,    ~desired_column,
  1L,                "a",
  2L,                "b",
  3L,                "c"
)
我肯定这个专栏转换问题以前被问过,但我没有找到一个适用的

我更喜欢我的团队最熟悉的b/c解决方案,但我对任何工具都持开放态度。我不知道如何使用和的组合。

试试这个:

ds$y_desired = apply(ds, 1, function(r) r[as.integer(r[1])+1])

我认为问题在于你的数据格式不符合你的需要。首先,我将使用tidyr::gather将长格式从宽格式转换为长格式:


然后,这项任务就变得非常简单,只需根据您所需的条件进行筛选,例如x==1、y==a等。

谢谢@siralen和@Phil为我展示了一种更好的方法。这是我最后使用的,如果它对将来的任何人都有帮助的话。这是广义的,以适应

立柱的任意位置, x的任意值,以及 元数据表将x值映射到所需的列 即a、b和c。 给定的观察数据集和查找数据集:

ds <- tibble::tibble(
  x   = c( 10 ,  10 ,  20 ,  30 ,  10 ),
  a   = c("a1", "a2", "a3", "a4", "a5"),
  b   = c("b1", "b2", "b3", "b4", "b5"),
  c   = c("c1", "c2", "c3", "c4", "c5")
)

ds_lookup <- tibble::tribble(
  ~x ,    ~desired_column,
  10L,                "a",
  20L,                "b",
  30L,                "c"
)
在从@siralen的答案中学习后,我重读了哈德利的文章。以下是将switch与apply系列的其他成员一起使用的解决方案,包括Tidyverse样式的链接

library(magrittr); requireNamespace("purrr"); requireNamespace("tibble"); requireNamespace("dplyr")

ds <- tibble::tibble(
  x   = c( 10 ,  10 ,  20 ,  30 ,  10 ),
  a   = c("a1", "a2", "a3", "a4", "a5"),
  b   = c("b1", "b2", "b3", "b4", "b5"),
  c   = c("c1", "c2", "c3", "c4", "c5")
)
determine_2 <- function( ss, a, b, c) {
  switch(
    as.character(ss),
    "10"    =   a,
    "20"    =   b,
    "30"    =   c
  )
}

# Each of these calls returns a vector.
unlist(Map(        determine_2, ds$x, ds$a, ds$b, ds$c))
mapply(            determine_2, ds$x, ds$a, ds$b, ds$c)
parallel::mcmapply(determine_2, ds$x, ds$a, ds$b, ds$c)                 # For Linux
unlist(purrr::pmap(list(        ds$x, ds$a, ds$b, ds$c), determine_2))

# Returns a dataset with the new variable.
ds %>%
  dplyr::mutate(
    y = unlist(purrr::pmap(list(x, a, b, c), determine_2))
  )

namesds[-1][ds$x]和paste0namesds[-1][ds$x],1:nRowdsAlt也适用于第2部分df1=as.data.frameds[-1];df1[cbindseq_alongds$x,ds$x]我不需要包真正的数据集没有列名和行号串联的单元格,因此无法利用示例的干净模式。我将编辑这篇文章来澄清这一点。谢谢你告诉我如何使用apply。在你提出解决方案之前,我并不认为r是一个被转换为字符的向量。我喜欢你的重组使逻辑变得更简单,并使我不再认为必须有一个应用/切换解决方案。次要的评论是,这使用了一个循环,而不是向量化的
ds$y_desired = apply(ds, 1, function(r) r[as.integer(r[1])+1])
library("tidyr")
ds %>% 
  gather(y, col, a:c)

# A tibble: 15 × 3
#        x     y   col
#    <dbl> <chr> <chr>
# 1      1     a    a1
# 2      1     a    a2
# 3      2     a    a3
# 4      3     a    a4
# 5      1     a    a5
# 6      1     b    b1
# 7      1     b    b2
# 8      2     b    b3
# 9      3     b    b4
# 10     1     b    b5
# 11     1     c    c1
# 12     1     c    c2
# 13     2     c    c3
# 14     3     c    c4
# 15     1     c    c5
ds <- tibble::tibble(
  x   = c( 10 ,  10 ,  20 ,  30 ,  10 ),
  a   = c("a1", "a2", "a3", "a4", "a5"),
  b   = c("b1", "b2", "b3", "b4", "b5"),
  c   = c("c1", "c2", "c3", "c4", "c5")
)

ds_lookup <- tibble::tribble(
  ~x ,    ~desired_column,
  10L,                "a",
  20L,                "b",
  30L,                "c"
)
determine_y <- function( r ) {
  # browser()
  lookup_row_index <- match(r['x'], ds_lookup$x)
  column_name      <- ds_lookup$desired_column[lookup_row_index]
  r[column_name]
}

ds$y <- apply(ds, 1, function(r) determine_y(r))
library(magrittr); requireNamespace("purrr"); requireNamespace("tibble"); requireNamespace("dplyr")

ds <- tibble::tibble(
  x   = c( 10 ,  10 ,  20 ,  30 ,  10 ),
  a   = c("a1", "a2", "a3", "a4", "a5"),
  b   = c("b1", "b2", "b3", "b4", "b5"),
  c   = c("c1", "c2", "c3", "c4", "c5")
)
determine_2 <- function( ss, a, b, c) {
  switch(
    as.character(ss),
    "10"    =   a,
    "20"    =   b,
    "30"    =   c
  )
}

# Each of these calls returns a vector.
unlist(Map(        determine_2, ds$x, ds$a, ds$b, ds$c))
mapply(            determine_2, ds$x, ds$a, ds$b, ds$c)
parallel::mcmapply(determine_2, ds$x, ds$a, ds$b, ds$c)                 # For Linux
unlist(purrr::pmap(list(        ds$x, ds$a, ds$b, ds$c), determine_2))

# Returns a dataset with the new variable.
ds %>%
  dplyr::mutate(
    y = unlist(purrr::pmap(list(x, a, b, c), determine_2))
  )