Создать фиктивные переменные из строки с несколькими значениями - PullRequest
0 голосов
/ 27 сентября 2018

У меня есть набор данных со столбцом, который содержит несколько значений, разделенных ;.

  name    sex     good_at
1 Tom      M   Drawing;Hiking
2 Mary     F   Cooking;Joking
3 Sam      M      Running
4 Charlie  M      Swimming

Я хотел бы создать фиктивную переменную для каждого уникального значения в good_at, такого как каждыйфиктивная переменная содержит TRUE или FALSE, чтобы указать, обладает ли этот индивидуум этим конкретным значением.

Желаемый результат

Drawing   Cooking
True       False
False      True
False      False
False      False

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018

Обзор

Чтобы создать фиктивные переменные для каждого уникального значения в good_at, необходимо выполнить следующие шаги:

  • Разделить good_at на несколько строк
  • Создатьфиктивные переменные - с использованием dummy::dummy() - для каждого значения в good_at для каждой name - sex пары
  • Преобразование данных в 4 столбца: name, sex, key и value
    • key содержит все имена столбцов фиктивных переменных
    • value содержит значения в каждой фиктивной переменной
  • Храните только записи, где value не ноль
  • Преобразуйте данные в одну запись для каждой пары имя-пол и столько столбцов, сколько есть в key
  • Приведение фиктивных столбцов клогические векторы.

код

# load necessary packages ----
library(dummy)
library(tidyverse)

# load necessary data ----
df <-
  read.table(text = "name    sex     good_at
1 Tom      M   Drawing;Hiking
             2 Mary     F   Cooking;Joking
             3 Sam      M      Running
             4 Charlie  M      Swimming"
             , header = TRUE
             , stringsAsFactors = FALSE)

# create a longer version of df -----
# where one record represents
# one unique name, sex, good_at value
df_clean <-
  df %>%
  separate_rows(good_at, sep = ";")

# create dummy variables for all unique values in "good_at" column ----
df_dummies <-
  df_clean %>%
  select(good_at) %>%
  dummy() %>%
  bind_cols(df_clean) %>%
  # drop "good_at" column 
  select(-good_at) %>%
  # make the tibble long by reshaping it into 4 columns:
  # name, sex, key and value
  # where key are the all dummy variable column names
  # and value are the values in each dummy variable
  gather(key, value, -name, -sex) %>%
  # keep records where
  # value is not equal to zero
  # note: this is due to "Tom" having both a 
  # "good_at_Drawing" value of 0 and 1. 
  filter(value != 0) %>%
  # make the tibble wide
  # with one record per name-sex pair
  # and as many columns as there are in key
  # with their values from value
  # and filling NA values to 0
  spread(key, value, fill = 0) %>%
  # for each name-sex pair
  # cast the dummy variables into logical vectors
  group_by(name, sex) %>%
  mutate_all(funs(as.integer(.) %>% as.logical())) %>%
  ungroup() %>%
  # just for safety let's join
  # the original "good_at" column
  left_join(y = df, by = c("name", "sex")) %>%
  # bring the original "good_at" column to the left-hand side 
  # of the tibble
  select(name, sex, good_at, matches("good_at_"))

# view result ----
df_dummies
# A tibble: 4 x 9
#   name  sex   good_at good_at_Cooking good_at_Drawing good_at_Hiking
#   <chr> <chr> <chr>   <lgl>           <lgl>           <lgl>         
# 1 Char… M     Swimmi… FALSE           FALSE           FALSE         
# 2 Mary  F     Cookin… TRUE            FALSE           FALSE         
# 3 Sam   M     Running FALSE           FALSE           FALSE         
# 4 Tom   M     Drawin… FALSE           TRUE            TRUE          
# ... with 3 more variables: good_at_Joking <lgl>, good_at_Running <lgl>,
#   good_at_Swimming <lgl>

# end of script #
0 голосов
/ 27 сентября 2018

Я создал функцию, которая дает желаемый результат:

dum <- function(kw, col, type=c(T, F)) {
t <- as.data.frame(grep(as.character(kw), col, ignore.case=T))
t$one <- type[1]
colnames(t) <- c("col1","dummy") 
t2 <- as.data.frame(grep(as.character(kw), col, ignore.case=T,
  invert=T))
t2$zero <- type[2]
colnames(t2) <- c("col1","dummy")
t3<-rbind(t, t2)
t3<-t3[order(t3$col1), ]
return(t3$dummy)
}

Это может быть не очень элегантно, но работает.Используя ваш пример, ваш фрейм данных равен df, а столбец, на который вы пытаетесь сослаться, - df$Good_at

Drawing <- dum("drawing", df$Good_at)
> Drawing
  TRUE
  FALSE
  ...

Cooking <- dum("cooking", df$Good_at)
> Cooking
  FALSE
  TRUE
  ...
...