Р: Какой эффективный способ перекодировать переменные? Как мне проставить средства? - PullRequest
0 голосов
/ 01 мая 2018

Мне было интересно, может ли кто-нибудь указать мне, как мне поступить с перекодированием нескольких переменных с одинаковыми правилами. У меня есть следующее df bhs1:

structure(list(bhs1_1 = c(NA, 1, NA, 2, 1, 2), bhs1_2 = c(NA, 
2, NA, 2, 1, 1), bhs1_3 = c(NA, 1, NA, 2, 2, 2), bhs1_4 = c(NA, 
2, NA, 1, 1, 1), bhs1_5 = c(NA, 1, NA, 1, 2, 2), bhs1_6 = c(NA, 
1, NA, 2, 1, 2), bhs1_7 = c(NA, 1, NA, 1, 2, 1), bhs1_8 = c(NA, 
2, NA, 2, 2, 2), bhs1_9 = c(NA, 1, NA, 2, 1, 1), bhs1_10 = c(NA, 
2, NA, 1, 2, 2), bhs1_11 = c(NA, 2, NA, 2, 2, 1), bhs1_12 = c(NA, 
2, NA, 2, 1, 1), bhs1_13 = c(NA, 1, NA, 1, 2, 2), bhs1_14 = c(NA, 
2, NA, 2, 1, 1), bhs1_15 = c(NA, 1, NA, 2, 2, 2), bhs1_16 = c(NA, 
2, NA, 2, 2, 2), bhs1_17 = c(NA, 2, NA, 2, 2, 1), bhs1_18 = c(NA, 
1, NA, 1, 2, 1), bhs1_19 = c(NA, 1, NA, 2, 1, 2), bhs1_20 = c(NA, 
2, NA, 2, 1, 1)), row.names = c(NA, -6L), class = c("tbl_df", 
"tbl", "data.frame")) 

Существует два правила преобразования для половины набора данных, например:

(bhs1_2, bhs1_4, bhs1_7, bhs1_9, bhs1_11, bhs1_12, bhs1_14, bhs1_16, bhs1_17, 
bhs1_18, bhs1_20) 
(if_else(1, 1, 0))

and 

(bhs1_1, bhs1_3, bhs1_5, bhs1_6, bhs1_8, bhs1_10, bhs1_13, 
bhs1_15, bhs1_19)
(if_else(2, 1, 0))

Есть ли элегантный способ написания кода, соответствующего этому варианту использования? Если да, то можете ли вы указать мне правильное направление и / или предоставить образец?

Ответы [ 4 ]

0 голосов
/ 01 мая 2018

Простое ifelse может быть полезным, учитывая, что OP хочет преобразовать NA на основе указанных правил:

case1 = c("bhs1_2", "bhs1_4", "bhs1_7", "bhs1_9", "bhs1_11", "bhs1_12",
          "bhs1_14", "bhs1_16", "bhs1_17", "bhs1_18", "bhs1_20")

case2 = c("bhs1_1", "bhs1_3", "bhs1_5", "bhs1_6", "bhs1_8", "bhs1_10",
          "bhs1_13", "bhs1_15", "bhs1_19")


df[case1] = ifelse(!is.na(df[case1]) & df[case1]==1,1,0)
df[case2] = ifelse(!is.na(df[case2]) & df[case2]==2,1,0)

#Test solution
df[1:7]
#   bhs1_1 bhs1_2 bhs1_3 bhs1_4 bhs1_5 bhs1_6 bhs1_7
# 1      0      0      0      0      0      0      0
# 2      0      0      0      0      0      0      1
# 3      0      0      0      0      0      0      0
# 4      1      0      1      1      0      1      1
# 5      0      1      1      1      1      0      0
# 6      1      1      1      1      1      1      1

** Обновлено: ** Если оставить NA как есть, то решение может быть:

df[case1] = ifelse(df[case1]==1,1,0)
df[case2] = ifelse(df[case2]==2,1,0)


df[1:7]
#   bhs1_1 bhs1_2 bhs1_3 bhs1_4 bhs1_5 bhs1_6 bhs1_7
# 1     NA     NA     NA     NA     NA     NA     NA
# 2      0      0      0      0      0      0      1
# 3     NA     NA     NA     NA     NA     NA     NA
# 4      1      0      1      1      0      1      1
# 5      0      1      1      1      1      0      0
# 6      1      1      1      1      1      1      1
0 голосов
/ 01 мая 2018

Мы можем создать интересующие имена столбцов, а затем преобразовать их в двоичный (as.integer) из логического выражения

case1 <- c("bhs1_2", "bhs1_4", "bhs1_7", "bhs1_9", "bhs1_11", "bhs1_12", 
   "bhs1_14", "bhs1_16", "bhs1_17", "bhs1_18", "bhs1_20") 

case2 <-  c("bhs1_1", "bhs1_3", "bhs1_5", "bhs1_6", "bhs1_8", 
   "bhs1_10", "bhs1_13", "bhs1_15", "bhs1_19")
library(magrittr)
df1 %<>%
    mutate_at(vars(case1), funs(as.integer(.==1 ))) %<>%
    mutate_at(vars(case2), funs(as.integer(.==2)))

df1
# A tibble: 6 x 20
#  bhs1_1 bhs1_2 bhs1_3 bhs1_4 bhs1_5 bhs1_6 bhs1_7 bhs1_8 bhs1_9 bhs1_10
#   <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>  <int>   <int>
#1     NA     NA     NA     NA     NA     NA     NA     NA     NA      NA
#2      0      0      0      0      0      0      1      1      1       1
#3     NA     NA     NA     NA     NA     NA     NA     NA     NA      NA
#4      1      0      1      1      0      1      1      1      0       0
#5      0      1      1      1      1      0      0      1      1       1
#6      1      1      1      1      1      1      1      1      1       1
# ... with 10 more variables: bhs1_11 <int>, bhs1_12 <int>, bhs1_13 <int>,
#   bhs1_14 <int>, bhs1_15 <int>, bhs1_16 <int>, bhs1_17 <int>, bhs1_18 <int>,
#   bhs1_19 <int>, bhs1_20 <int>

Или эффективный вариант будет использовать data.table

library(data.table)
setDT(df1)[, (case1) := lapply(.SD, function(x) as.integer(x == 1 )),
  .SDcols = case1
      ][, (case2) := lapply(.SD, function(x) as.integer(x == 2)), 
  .SDcols = case2][]

ПРИМЕЧАНИЕ. Это не предполагает, что все значения одинаковы

0 голосов
/ 01 мая 2018

Вы можете использовать очень быстрый базовый способ R, как показано ниже:

case1=c("bhs1_10", "bhs1_11", "bhs1_12", "bhs1_13", "bhs1_14", "bhs1_15","bhs1_16", "bhs1_17", "bhs1_18", "bhs1_19", "bhs1_20")  

case2=c("bhs1_1", "bhs1_3", "bhs1_5", "bhs1_6", "bhs1_8", "bhs1_10", "bhs1_13", "bhs1_15", "bhs1_19")

dat[case1]=abs(dat[case1]-2)
dat[case2]=dat[case2]-1
0 голосов
/ 01 мая 2018

Вот решение с использованием dplyr

library(dplyr)
case1 <- vars(bhs1_2, bhs1_4, bhs1_7, bhs1_9, bhs1_11, bhs1_12, bhs1_14, bhs1_16, bhs1_17, 
  bhs1_18, bhs1_20) 
case2 <- vars(bhs1_1, bhs1_3, bhs1_5, bhs1_6, bhs1_8, bhs1_10, bhs1_13, 
  bhs1_15, bhs1_19)
result <- df %>%
  mutate_at(case1, ~ (. == 1) * 1L) %>%
  mutate_at(case2, ~ (. == 2) * 1L)

Примечание - я пропустил оператор ifelse - я просто проверяю ваше состояние, затем преобразовал ответы TRUE / FALSE в числа, умножив их на 1. Я также не уверен, как вы хотите, чтобы NA были обработано, но это игнорирует их.

Если вы не знакомы с оператором канала (%>%), он берет результат предыдущей функции и устанавливает его в качестве первого аргумента следующей функции. Он предназначен для улучшения читабельности кода за счет избежания большого количества вложений функций.

...