用于将列乘以向量的 tidyverse 解决方案
tidyverse solution for multiplying columns by a vector
我在这里寻找解决方案: and here: What is the right way to multiply data frame by vector?,但它确实不起作用。
我想要做的是一种或多或少干净整洁的方式,我将列乘以一个向量,然后将它们作为新列添加到现有数据框中。以第一个 link:
中的数据为例
c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- data.frame(c1,c2,c3)
c1 c2 c3
1 1 4 7
2 2 5 8
3 3 6 9
v1 <- c(1,2,3)
我想要的结果是:
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
我试过了:
library(tidyverse)
d1 |>
mutate(pro = sweep(across(everything()), 2, v1, "*"))
但这里的问题是新列实际上是我的数据框中的一个数据框。我正在努力将这个数据帧中的数据帧转换为常规列。我假设,我可能首先在这个内部数据框上设置名称,然后取消嵌套,但想知道是否有更直接的方法通过使用 across
遍历每一列并使用 first/second/third 元素提供它 v1
?
(我知道我可能还可以先用三个新的相乘列创建一个独立的数据框,给它们一个唯一的名称,然后 bind_cols
在 d1 和带有产品的 df 上。)
如果是按行,那么一个选项是c_across
library(dplyr)
library(stringr)
library(tibble)
new <- as_tibble(setNames(as.list(v1), names(d1)))
d1 %>%
rowwise %>%
mutate(c_across(everything()) * new) %>%
rename_with(~ str_c("pro_", .x), everything()) %>%
bind_cols(d1, .)
-输出
1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
或者另一种选择是map2
library(purrr)
map2_dfc(d1, v1, `*`) %>%
rename_with(~ str_c("pro_", .x), everything()) %>%
bind_cols(d1, .)
-输出
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
此外,使用 OP 方法,它是一个 data.frame
列。可以 unpack
ed
library(tidyr)
d1 |>
mutate(pro = sweep(cur_data(), 2, v1, `*`)) |>
unpack(pro, names_sep = "_")
-输出
# A tibble: 3 × 6
c1 c2 c3 pro_c1 pro_c2 pro_c3
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
编辑:基于@deschen 对 names_sep
的评论
这可能很荒谬,但您可以使用
library(dplyr)
d1 %>%
mutate(across(everything(),
~.x * v1[which(names(d1) == cur_column())],
.names = "pro_{.col}"))
哪个returns
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
只是为了好玩,在看到您的一些解决方案后,我试错了一些。自从我开始忍受使用基础 R 本机管道的痛苦以来,它还不允许传递“。”作为第一个参数的静默参数,我不得不 fiddle 多讨论一下:
library(tidyverse)
d1 |>
(\(x)(bind_cols(x, x |>
map2_dfc(v1, `*`) |>
rename_with(.cols = everything(),
.fn = ~paste0("pro_", .)))))()
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
找到更简单的解决方案:
d1 |>
add_column(d1 |>
map2_dfc(v1, `*`) |>
rename_with(.cols = everything(),
.fn = ~paste0("pct_", .)))
这是常用 apply(. , 1, fun)
范例的 dplyr-ized 版本:
d1 %>% apply(1, "*", v1) %>% t %>% cbind(d1, .)
c1 c2 c3 c1 c2 c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
如果您想在绑定回起始数据帧之前将列名分配给矩阵,这会有点老套:
d1 %>% apply(1, "*", v1) %>% t %>% `colnames<-`(., paste0("pro_", colnames(.))) %>% cbind(d1, .)
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
类似于@IRTFM的解决方案,但不需要apply(...)
cbind(d1, t(t(d1)*v1))
## c1 c2 c3 c1 c2 c3
## 1 1 4 7 1 8 21
## 2 2 5 8 2 10 24
## 3 3 6 9 3 12 27
或者,
result <- cbind(d1, t(t(d1)*v1))
colnames(result) <- c(colnames(d1), paste0('pro_', colnames(d1)))
result
它给出了你想要的列名。
我在这里寻找解决方案:
我想要做的是一种或多或少干净整洁的方式,我将列乘以一个向量,然后将它们作为新列添加到现有数据框中。以第一个 link:
中的数据为例c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- data.frame(c1,c2,c3)
c1 c2 c3
1 1 4 7
2 2 5 8
3 3 6 9
v1 <- c(1,2,3)
我想要的结果是:
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
我试过了:
library(tidyverse)
d1 |>
mutate(pro = sweep(across(everything()), 2, v1, "*"))
但这里的问题是新列实际上是我的数据框中的一个数据框。我正在努力将这个数据帧中的数据帧转换为常规列。我假设,我可能首先在这个内部数据框上设置名称,然后取消嵌套,但想知道是否有更直接的方法通过使用 across
遍历每一列并使用 first/second/third 元素提供它 v1
?
(我知道我可能还可以先用三个新的相乘列创建一个独立的数据框,给它们一个唯一的名称,然后 bind_cols
在 d1 和带有产品的 df 上。)
如果是按行,那么一个选项是c_across
library(dplyr)
library(stringr)
library(tibble)
new <- as_tibble(setNames(as.list(v1), names(d1)))
d1 %>%
rowwise %>%
mutate(c_across(everything()) * new) %>%
rename_with(~ str_c("pro_", .x), everything()) %>%
bind_cols(d1, .)
-输出
1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
或者另一种选择是map2
library(purrr)
map2_dfc(d1, v1, `*`) %>%
rename_with(~ str_c("pro_", .x), everything()) %>%
bind_cols(d1, .)
-输出
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
此外,使用 OP 方法,它是一个 data.frame
列。可以 unpack
ed
library(tidyr)
d1 |>
mutate(pro = sweep(cur_data(), 2, v1, `*`)) |>
unpack(pro, names_sep = "_")
-输出
# A tibble: 3 × 6
c1 c2 c3 pro_c1 pro_c2 pro_c3
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
编辑:基于@deschen 对 names_sep
这可能很荒谬,但您可以使用
library(dplyr)
d1 %>%
mutate(across(everything(),
~.x * v1[which(names(d1) == cur_column())],
.names = "pro_{.col}"))
哪个returns
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
只是为了好玩,在看到您的一些解决方案后,我试错了一些。自从我开始忍受使用基础 R 本机管道的痛苦以来,它还不允许传递“。”作为第一个参数的静默参数,我不得不 fiddle 多讨论一下:
library(tidyverse)
d1 |>
(\(x)(bind_cols(x, x |>
map2_dfc(v1, `*`) |>
rename_with(.cols = everything(),
.fn = ~paste0("pro_", .)))))()
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
找到更简单的解决方案:
d1 |>
add_column(d1 |>
map2_dfc(v1, `*`) |>
rename_with(.cols = everything(),
.fn = ~paste0("pct_", .)))
这是常用 apply(. , 1, fun)
范例的 dplyr-ized 版本:
d1 %>% apply(1, "*", v1) %>% t %>% cbind(d1, .)
c1 c2 c3 c1 c2 c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
如果您想在绑定回起始数据帧之前将列名分配给矩阵,这会有点老套:
d1 %>% apply(1, "*", v1) %>% t %>% `colnames<-`(., paste0("pro_", colnames(.))) %>% cbind(d1, .)
c1 c2 c3 pro_c1 pro_c2 pro_c3
1 1 4 7 1 8 21
2 2 5 8 2 10 24
3 3 6 9 3 12 27
类似于@IRTFM的解决方案,但不需要apply(...)
cbind(d1, t(t(d1)*v1))
## c1 c2 c3 c1 c2 c3
## 1 1 4 7 1 8 21
## 2 2 5 8 2 10 24
## 3 3 6 9 3 12 27
或者,
result <- cbind(d1, t(t(d1)*v1))
colnames(result) <- c(colnames(d1), paste0('pro_', colnames(d1)))
result
它给出了你想要的列名。