[英]dplyr mutate new dynamic variables with case_when
我在這里和這里都知道類似的問題,但我無法找到適合我具體情況的正確解決方案。 我發現的一些是使用mutate_
等的解決方案但我知道這些現在已經過時了。 我對dplyr的動態用法不熟悉。
我有一個數據框,其中包含一些帶有兩個不同前綴的變量,alpha和beta:
df <- data.frame(alpha.num = c(1, 3, 5, 7),
alpha.char = c("a", "c", "e", "g"),
beta.num = c(2, 4, 6, 8),
beta.char = c("b", "d", "f", "h"),
which.to.use = c("alpha", "alpha", "beta", "beta"))
我想創建前綴為“selected”的新變量。 它們是“alpha”或“beta”列的副本,具體取決於在“which.to.use”列中為該行命名的列。 期望的輸出是:
desired.df <- data.frame(alpha.num = c(1, 3, 5, 7),
alpha.char = c("a", "c", "e", "g"),
beta.num = c(2, 4, 6, 8),
beta.char = c("b", "d", "f", "h"),
which.to.use = c("alpha", "alpha", "beta", "beta"),
chosen.num = c(1, 3, 6, 8),
chosen.char = c("a", "c", "f", "h"))
我失敗的嘗試:
varnames <- c("num", "char")
df %<>%
mutate(as.name(paste0("chosen.", varnames)) := case_when(
which.to.use == "alpha" ~ paste0("alpha.", varnames),
which.to.use == "beta" ~ pasteo("beta.", varnames)
))
我更喜歡純粹的dplyr解決方案,更好的是可以包含在修改df的更長管道中(即不需要停止創建“varnames”)。 謝謝你的幫助。
使用一些有趣的rlang
東西& purrr
:
library(rlang)
library(purrr)
library(dplyr)
df <- data.frame(alpha.num = c(1, 3, 5, 7),
alpha.char = c("a", "c", "e", "g"),
beta.num = c(2, 4, 6, 8),
beta.char = c("b", "d", "f", "h"),
which.to.use = c("alpha", "alpha", "beta", "beta"),
stringsAsFactors = F)
c("num", "char") %>%
map(~ mutate(df, !!sym(paste0("chosen.", .x)) :=
case_when(
which.to.use == "alpha" ~ !!sym(paste0("alpha.", .x)),
which.to.use == "beta" ~ !!sym(paste0("beta.", .x))
))) %>%
reduce(full_join)
結果:
alpha.num alpha.char beta.num beta.char which.to.use chosen.num chosen.char
1 1 a 2 b alpha 1 a
2 3 c 4 d alpha 3 c
3 5 e 6 f beta 6 f
4 7 g 8 h beta 8 h
沒有reduce(full_join)
:
c("num", "char") %>%
map_dfc(~ mutate(df, !!sym(paste0("chosen.", .x)) :=
case_when(
which.to.use == "alpha" ~ !!sym(paste0("alpha.", .x)),
which.to.use == "beta" ~ !!sym(paste0("beta.", .x))
))) %>%
select(-ends_with("1"))
alpha.num alpha.char beta.num beta.char which.to.use chosen.num chosen.char
1 1 a 2 b alpha 1 a
2 3 c 4 d alpha 3 c
3 5 e 6 f beta 6 f
4 7 g 8 h beta 8 h
說明:
(注意:我沒有完全或甚至沒有得到rlang
。也許其他人可以給出更好的解釋;)。)
當我們需要mutate
一個裸名稱來知道它是指一個變量名時,使用paste0
本身會產生一個字符串。
如果我們在sym
包裝paste0
,它將計算為一個裸名稱:
> x <- varrnames[1]
> sym(paste0("alpha.", x))
alpha.num
但mutate
不知道要評估,而是將其作為符號讀取:
> typeof(sym(paste0("alpha.", x)))
[1] "symbol"
“砰砰” !!
運算符評估sym
函數。 相比:
> expr(mutate(df, var = sym(paste0("alpha.", x))))
mutate(df, var = sym(paste0("alpha.", x)))
> expr(mutate(df, var = !!sym(paste0("alpha.", x))))
mutate(df, var = alpha.num)
所以使用!!sym
我們可以使用paste來動態調用dplyr的變量名。
使用A基礎R的方法apply
具有margin = 1
,我們選擇列,用於基於在所述值的每一行which.to.use
柱並從該行對應的列得到的值。
df[c("chosen.num", "chosen.char")] <-
t(apply(df, 1, function(x) x[grepl(x["which.to.use"], names(df))]))
df
# alpha.num alpha.char beta.num beta.char which.to.use chosen.num chosen.char
#1 1 a 2 b alpha 1 a
#2 3 c 4 d alpha 3 c
#3 5 e 6 f beta 6 f
#4 7 g 8 h beta 8 h
這是一個非常快的nest()/map()
策略。 它保持在tidyverse
,但不進入rlang
土地。
library(tidyverse)
df %>%
nest(-which.to.use) %>%
mutate(new_data = map2(data, which.to.use,
~ select(..1, matches(..2)) %>%
rename_all(funs(gsub(".*\\.", "choosen.", .) )))) %>%
unnest()
which.to.use alpha.num alpha.char beta.num beta.char choosen.num choosen.char
1 alpha 1 a 2 b 1 a
2 alpha 3 c 4 d 3 c
3 beta 5 e 6 f 6 f
4 beta 7 g 8 h 8 h
它抓取所有列,而不僅僅是num
和char
,而不是which.to.use
。 但這似乎是你(我)想要的IRL。 如果只想提取特定變量,可以在調用nest()
之前添加一個select(matches('(var1|var2|etc'))
行。
編輯:我使用select()
刪除不需要的列的原始建議將導致進行join
以便稍后將其恢復。 相反,如果您調整nest
參數,則只能在某些列上實現此操作。
我在這里添加了新的bool
列,但是對於“選擇”選擇它們將被忽略:
new_df <- data.frame(alpha.num = c(1, 3, 5, 7),
alpha.char = c("a", "c", "e", "g"),
alpha.bool = FALSE,
beta.num = c(2, 4, 6, 8),
beta.char = c("b", "d", "f", "h"),
beta.bool = TRUE,
which.to.use = c("alpha", "alpha", "beta", "beta"),
stringsAsFactors = FALSE)
new_df %>%
nest(matches("num|char")) %>% # only columns that match this pattern get nested, allows you to save others
mutate(new_data = map2(data, which.to.use,
~ select(..1, matches(..2)) %>%
rename_all(funs(gsub(".*\\.", "choosen.", .) )))) %>%
unnest()
alpha.bool beta.bool which.to.use alpha.num alpha.char beta.num beta.char choosen.num choosen.char
1 FALSE TRUE alpha 1 a 2 b 1 a
2 FALSE TRUE alpha 3 c 4 d 3 c
3 FALSE TRUE beta 5 e 6 f 6 f
4 FALSE TRUE beta 7 g 8 h 8 h
您也可以嘗試gather
/ spread
方法
df %>%
rownames_to_column() %>%
gather(k,v,-which.to.use,-rowname) %>%
separate(k,into = c("k1", "k2"), sep="[.]") %>%
filter(which.to.use == k1) %>%
mutate(k1="chosen") %>%
unite(k, k1, k2,sep=".") %>%
spread(k,v) %>%
select(.,chosen.num, chosen.char) %>%
bind_cols(df, .)
alpha.num alpha.char beta.num beta.char which.to.use chosen.num chosen.char
1 1 a 2 b alpha 1 a
2 3 c 4 d alpha 3 c
3 5 e 6 f beta 6 f
4 7 g 8 h beta 8 h
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.