Как преобразовать длинный в широкий формат для одного столбца с несколькими категориальными значениями - PullRequest
0 голосов
/ 03 января 2019

У меня есть данные, которые содержат столбец с названием «состояния» с несколькими значениями, разделенными запятыми, как показано ниже

test <- structure(list(states = c("WA", "SC", "IN", "IN", "WI", "NY",
"CA, CO, CT, DE, FL, GA, IA, ID, IL, IN, LA, MD, MI, MT, NJ, NV, OH, PA, SC, TX, UT, VA, WA", 
"CA, CO, DE, GA, IL, LA, MA, MD, MI, MO, NJ, NV, NY, PA, VA, TX, WA", 
"LA, MS", "DC, MD, VA", "AL, GA, NC", "MN WI", "MN WI", "KS, OK, TX", 
"KS, MO, OK, TX", "IN, MI, NY, OH, PA", "CO, NE", "CO", "CO, NE", 
"AZ, CA, CO, NV, TX, WA", "AZ, CA, NV, TX, UT,WA", "AZ, CA, NV, TX, UT, WA", 
"CA, CT, IL, WA", "AL, AZ, CA, IL, MI, MO, MT, NJ, NM, OH, OK, PA, TX, VA, WI", 
"AL, NC, TX, VA", "IL, MO, NJ, OH", "AZ, CA, CO, MN", "CO, IA, KY, TX", 
"CO, IA, KY, MI, NC, NE, OH, PA, TX", "AR, GA, NC, NM, OK", "AL & WV", 
"KY, MN, ND, OH,OR,PA", "KS", "AL, AR, AZ, CA, CT, DE, FL, GA, HI, IA, IL, IN, KS, KY, LA, MA, MD, MI, MN, MO, MS, NC, NE, NJ, NM, NY, OH, OK, OR, PA, RI, SC, TN, TX, UT, VA, WI", 
"AR, CO, GA, IL, LA, MI, MN, MS, MT, NC, ND, NE, OH, PA, RI, SC, TX, WI", 
"AL, AR, AZ, CA, CT, DE, FL, GA, HI, IA, IL, IN, KS, KY, LA, MA, MD, MI, MN, MO, MS, NC, NE, NJ, NM, NY, OH, OK, OR, PA, RI, SC, TN, TX, UT, VA, WI", 
"AL, AR, AZ, CA, CT, DE, FL, GA, HI, IA, IL, IN, KS, KY, LA, MA, MD, MI, MN, MO, MS, NC, NE, NJ, NM, NY, OH, OK, OR, PA, RI, SC, TN, TX, UT, VA, WI", 
"AL, AZ, FL, KS, MI, MN, MO, NC, OK, WI", "GA, SC", "CA, CO, FL, IL, KY, NJ, OH, TX, VA", 
"AL, AZ, CA, FL, GA, NJ, NM, NV, OH, PA, TX, VA", "ALL 50 STATES", 
"ALL 50 STATES", "ALL 50 STATES", "AL, AZ, FL, GA, MI, NJ, NY, OH, OR, PA, TX, UT"
)), .Names = "states", row.names = c(NA, -45L), class = c("tbl_df", 
                                                            "tbl", "data.frame"))
test

Я хотел бы преобразовать его в формат, в котором каждое «состояние» представлено в виде столбца, а 1 указывает на наличие состояний, а в противном случае - на ноль.

Спасибо

Ответы [ 2 ]

0 голосов
/ 03 января 2019

Сначала я загружаю библиотеки.

# Load libraries
library(dplyr)
library(magrittr)
library(datasets)

Затем я заменяю ALL 50 STATES в вашем наборе данных на сокращения всех 50 состояний.(state.abb происходит из пакета datasets.)

# Change "ALL 50 STATES" to state abbreviations
test %<>%
  mutate(states = ifelse(states == "ALL 50 STATES", paste0(state.abb, collapse = ","), states))

Наконец, я прохожу каждый элемент и разбираю состояния с помощью strsplit, подсчитываю каждое состояние с помощью table, связываю результатывместе во фрейм данных, используя bind_rows, и замените NA s нулями на replace_na и mutate_all.

# Count assuming state only can appear once per row
do.call(bind_rows, lapply(test$states, function(x)table(strsplit(x, "[[:punct:][:space:]]+")))) %>% 
  mutate_all(replace_na, replace = 0)

[ NB Ваш набор данных немного запутан: большинство состояний разделены запятыми, но некоторые содержат только пробелы или амперсанды.Я использовал [[:punct:][:space:]]+ для учета всех этих возможностей.]

Это пример первых 10 строк и первых 10 состояний:

#      WA    SC    IN    WI    NY    CA    CO    CT    DE    FL
#   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     1     0     0     0     0     0     0     0     0     0
# 2     0     1     0     0     0     0     0     0     0     0
# 3     0     0     1     0     0     0     0     0     0     0
# 4     0     0     1     0     0     0     0     0     0     0
# 5     0     0     0     1     0     0     0     0     0     0
# 6     0     0     0     0     1     0     0     0     0     0
# 7     1     1     1     0     0     1     1     1     1     1
# 8     1     0     0     0     1     1     1     0     1     0
# 9     0     0     0     0     0     0     0     0     0     0
# 10    0     0     0     0     0     0     0     0     0     0
0 голосов
/ 03 января 2019

Это может быть то, что вы хотите.Поскольку вы не предоставили ожидаемый результат, это моя интерпретация, основанная на вашем описании.Идея состоит в том, чтобы добавить индекс с rowid_to_column, заменить «ВСЕ 50 СТАТЕЙ» на «ВСЕ», разделить состояния на основе символов и пробела на separate_rows, а затем spread фрейм данных.

library(tidyverse)

test2 <- test %>%
  # Create index
  rowid_to_column() %>%
  # Replace ALL 50 STATES with ALL
  mutate(states = replace(states, states %in% "ALL 50 STATES", "ALL")) %>%
  # Separate states with punct and space
  separate_rows(states, sep = "[[:punct:][:space:]]+") %>%
  group_by(rowid) %>%
  mutate(Group_ID = row_number(), Present = 1L) %>%
  spread(states, Present, fill = 0L) %>%
  select(-Group_ID)
...