Home > Mobile >  Add new column with appropriate values from separate list
Add new column with appropriate values from separate list

Time:10-11

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")
  )
  • Related