Условно мутировать несколько столбцов в R - PullRequest
2 голосов
/ 06 января 2020

У меня есть фрейм данных со столбцом фактора с уровнями j , а также j векторов длины k . Я хотел бы заполнить столбцы k в первом кадре данных значениями из последних векторов, в зависимости от фактора.

Упрощенный пример (три уровня, три вектора, два значения):

df1 <- data.frame("Factor" = rep(c("A", "B", "C"), times = 5))
vecA <- c(1, 2)
vecB <- c(2, 1)
vecC <- c(3, 3)

Вот решение с использованием вложенных операторов ifelse:

library(tidyverse)
df1 %>%
  mutate(V1 = ifelse(Factor == "A", vecA[1], 
                     ifelse(Factor == "B", vecB[1], vecC[1])),
         V2 = ifelse(Factor == "A", vecA[2], 
                     ifelse(Factor == "B", vecB[2], vecC[2])))

Я хотел бы избегать вложенных операторов ifelse. В идеале я бы также хотел не менять каждый столбец отдельно.

Ответы [ 3 ]

1 голос
/ 06 января 2020

Вот одна идея. В глобальной среде получите все объекты, которые начинаются с "ve c", что делается с помощью mget(). Это создает список. Для каждого элемента в списке вставьте числа с «_» между ними. Затем расположите имена в векторе для следующего процесса соединения. После объединения разбейте столбец, значения с cSplit(). Я надеюсь, что этот подход будет применим к вашей реальной ситуации.

library(tidyverse)
library(splitstackshape)

# Create a character vector.
mychr <- map_chr(.x = mget(ls(pattern = "vec")),
                 .f = function(x) {paste0(x, collapse = "_")})

# Remove "vec" in names.
names(mychr) <- sub(x = names(mychr), pattern = "vec", replacement = "")

#   A     B     C 
#"1_2" "2_1" "3_3"

# stack() creates a data frame. Use it in left_join().
# Then, split the column, values into two columns. You probably have more than
# two. So I decided to use cSplit() here.

left_join(df1, stack(mychr), by = c("Factor" = "ind")) %>%
cSplit(splitCols = "values", sep = "_", direction = "wide", type.convert = FALSE)

#    Factor values_1 values_2
# 1:      A        1        2
# 2:      B        2        1
# 3:      C        3        3
# 4:      A        1        2
# 5:      B        2        1
# 6:      C        3        3
# 7:      A        1        2
# 8:      B        2        1
# 9:      C        3        3
#10:      A        1        2
#11:      B        2        1
#12:      C        3        3
#13:      A        1        2
#14:      B        2        1
#15:      C        3        3
1 голос
/ 06 января 2020

Вот вариант base R

df1[c('V1', 'V2')] <- do.call(Map, c(f = c, mget(ls(pattern="^vec[A-C]$"))))
df1
#    Factor V1 V2
#1       A  1  2
#2       B  2  1
#3       C  3  3
#4       A  1  2
#5       B  2  1
#6       C  3  3
#7       A  1  2
#8       B  2  1
#9       C  3  3
#10      A  1  2
#11      B  2  1
#12      C  3  3
#13      A  1  2
#14      B  2  1
#15      C  3  3

Или с transpose из purrr

library(dplyr)
library(purrr)
mget(ls(pattern="^vec[A-C]$")) %>% 
     transpose %>% 
     setNames(c('V1', 'V2')) %>% 
     cbind(df1, .)
0 голосов
/ 06 января 2020

Вот способ сделать:

# modify the vectors
l <- list('A' = vecA, 'B' = vecB, 'C' = vecC)

# create df with mapping
df2 = data.frame(t(sapply(df1$Factor, function(x) l[[x]])))
colnames(df2) <- c('V1', 'V2')

new_df = cbind(df1, df2)

   Factor V1 V2
1       A  1  2
2       B  2  1
3       C  3  3
4       A  1  2
5       B  2  1
6       C  3  3
7       A  1  2
8       B  2  1
9       C  3  3
10      A  1  2
11      B  2  1
12      C  3  3
13      A  1  2
14      B  2  1
15      C  3  3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...