I am trying to fill a new column with appropriate values from a list using dplyr
. I tried to come up with a simple reproducible example, which can be found below. In short, I want to add a column "Param" to a dataframe, based on the values of the existing columns. The matching values are found in a separate list. I've tried functions as ifelse()
and switch
but I cannot make it work. Any tips on how this can be achieved?
Thank you in advance!
library(dplyr)
# Dataframe to start with
df <- as.data.frame(matrix(data = c(rep("A", times = 3),
rep("B", times = 3),
rep(1:3, times = 2)), ncol = 2))
colnames(df) <- c("Method", "Type")
df
#> Method Type
#> 1 A 1
#> 2 A 2
#> 3 A 3
#> 4 B 1
#> 5 B 2
#> 6 B 3
# Desired dataframe
desired <- cbind(df, Param = c(0.9, 0.8, 0.7, 0.6, 0.5, 0.4))
desired
#> Method Type Param
#> 1 A 1 0.9
#> 2 A 2 0.8
#> 3 A 3 0.7
#> 4 B 1 0.6
#> 5 B 2 0.5
#> 6 B 3 0.4
# Failed attempt
param <- list("A" = c("1" = 0.9, "2" = 0.8, "3" = 0.7),
"B" = c("1" = 0.6, "2" = 0.5, "3" = 0.4))
param
#> $A
#> 1 2 3
#> 0.9 0.8 0.7
#>
#> $B
#> 1 2 3
#> 0.6 0.5 0.4
df %>%
mutate(Param = ifelse(.$Method == "A", param$A[[.$Type]],
ifelse(.$Method == "B", param$B[[.$Type]], NA)))
#> Error: Problem with `mutate()` column `Param`.
#> ℹ `Param = ifelse(...)`.
#> x attempt to select more than one element in vectorIndex
CodePudding user response:
You can unlist your list and just add it to your df.
df$Param <- unlist(param)
Method Type Param
1 A 1 0.9
2 A 2 0.8
3 A 3 0.7
4 B 1 0.6
5 B 2 0.5
6 B 3 0.4
CodePudding user response:
As mentioned by @dario including matching data in dataframe would be easier.
library(dplyr)
library(tidyr)
df %>%
nest(data = Type) %>%
left_join(stack(param) %>% nest(data1 = values), by = c('Method' = 'ind')) %>%
unnest(c(data, data1))
# Method Type values
# <chr> <chr> <dbl>
#1 A 1 0.9
#2 A 2 0.8
#3 A 3 0.7
#4 B 1 0.6
#5 B 2 0.5
#6 B 3 0.4
CodePudding user response:
Sure this could be cleaner, but it will get the job done: Option 1:
df %>%
mutate(
Param = unlist(param)[
match(
paste0(
df$Method,
df$Type
),
names(
do.call(
c,
lapply(
param,
names
)
)
)
)
]
)
Option 2: (cleaner version):
df %>%
type.convert() %>%
left_join(
do.call(cbind, param) %>%
data.frame() %>%
mutate(Type = as.integer(row.names(.))) %>%
pivot_longer(!Type, names_to = "Method", values_to = "Param"),
by = c("Type", "Method")
)