向量化列选择
Vectorized column selection
当 selection 特定于每一行时,如何使用一列的值(例如下面的 x
)到可能列中的值 select?
x
变量确定变量 a
、b
或 c
是否应为给定行 selected。这是一个简化的例子;实际单元格不是列名和行号的串联。
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")
)
所需列的值为:
# ds$y_desired <- c("a1", "a2", "b3", "c4", "a5")
# ds$column_desired <- c("a" , "a" , "b" , "c" , "a" )
当然,以下不会产生单列,而是五列。
ds[, ds$column_desired]
下面会产生错误:
Error in mutate_impl(.data, dots) : basic_string::_M_replace_aux
.
ds %>%
dplyr::rowwise() %>%
dplyr::mutate(
y = .[[column_desired]]
) %>%
dplyr::ungroup()
如果我的真实场景只有两个或三个选择,我可能会使用 nested-ifs,但我想要一种通用的映射方法来适应更多的条件。
ds %>%
dplyr::mutate(
y_if_chain = ifelse(x==1, a, ifelse(x==2, b, c))
)
理想情况下,该方法可以通过查找 table 或其他一些元数据对象来指导:
ds_lookup <- tibble::tribble(
~x, ~desired_column,
1L, "a",
2L, "b",
3L, "c"
)
我确定以前有人问过这个列切换问题,但我没有找到适用的问题。
我想要 tidyverse solution (b/c that's what my team is most comfortable with), but I'm open to any tool. I couldn't figure out how to use a combination of apply and kimisc::vswitch.
试试这个:
ds$y_desired = apply(ds, 1, function(r) r[as.integer(r[1])+1])
我认为问题在于您的数据格式不符合您的需要。首先,我会使用 tidyr::gather()
:
从宽格式转换为长格式
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
然后根据您的要求(例如 x == 1, y == a
等)filter
,任务变得像 filter
一样微不足道
感谢@sirallen 和@Phil 向我展示了更好的方法。如果将来对任何人有帮助,这就是我最终使用的内容。它被概括为容纳
- 列的任意位置,
x
和 的任意值
- 元数据 table 将
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"
)
封装字符向量r
和查找table之间的映射。
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))
在学习了@sirallen 的回答后,我重读了 Hadley 的 chapter on functionals。以下是将 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))
)
当 selection 特定于每一行时,如何使用一列的值(例如下面的 x
)到可能列中的值 select?
x
变量确定变量 a
、b
或 c
是否应为给定行 selected。这是一个简化的例子;实际单元格不是列名和行号的串联。
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")
)
所需列的值为:
# ds$y_desired <- c("a1", "a2", "b3", "c4", "a5")
# ds$column_desired <- c("a" , "a" , "b" , "c" , "a" )
当然,以下不会产生单列,而是五列。
ds[, ds$column_desired]
下面会产生错误:
Error in mutate_impl(.data, dots) : basic_string::_M_replace_aux
.
ds %>%
dplyr::rowwise() %>%
dplyr::mutate(
y = .[[column_desired]]
) %>%
dplyr::ungroup()
如果我的真实场景只有两个或三个选择,我可能会使用 nested-ifs,但我想要一种通用的映射方法来适应更多的条件。
ds %>%
dplyr::mutate(
y_if_chain = ifelse(x==1, a, ifelse(x==2, b, c))
)
理想情况下,该方法可以通过查找 table 或其他一些元数据对象来指导:
ds_lookup <- tibble::tribble(
~x, ~desired_column,
1L, "a",
2L, "b",
3L, "c"
)
我确定以前有人问过这个列切换问题,但我没有找到适用的问题。
我想要 tidyverse solution (b/c that's what my team is most comfortable with), but I'm open to any tool. I couldn't figure out how to use a combination of apply and kimisc::vswitch.
试试这个:
ds$y_desired = apply(ds, 1, function(r) r[as.integer(r[1])+1])
我认为问题在于您的数据格式不符合您的需要。首先,我会使用 tidyr::gather()
:
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
然后根据您的要求(例如 x == 1, y == a
等)filter
,任务变得像 filter
一样微不足道
感谢@sirallen 和@Phil 向我展示了更好的方法。如果将来对任何人有帮助,这就是我最终使用的内容。它被概括为容纳
- 列的任意位置,
x
和 的任意值
- 元数据 table 将
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"
)
封装字符向量r
和查找table之间的映射。
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))
在学习了@sirallen 的回答后,我重读了 Hadley 的 chapter on functionals。以下是将 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))
)