Как записать наличие / отсутствие разделенных элементов больших строк в отдельных столбцах данных - PullRequest
0 голосов
/ 26 апреля 2020

У меня есть датафрейм с длинными и грязными цепочками бытовых удобств. Я хочу разбить строки на уникальные удобства, создать для каждой уникальной удобства новый столбец в кадре данных и записать в новых столбцах наличие / отсутствие отдельных удобств в строках. Используя вложенные циклы for, я нашел способ выполнить sh задачу. Однако я хотел бы знать, как можно получить тот же результат, используя одну из функций семейства apply или метод dplyr, чтобы избежать циклов.

Воспроизводимые данные:

df <- data.frame(
  id = 1:4,
  amenities = c('{"Wireless Internet","Wheelchair accessible",Kitchen,Elevator,"Buzzer/wireless intercom",Heating}',
                '{TV,"Cable TV",Internet,"Wireless Internet","Air conditioning",Kitchen,"Smoking allowed","Pets allowed"}',
                '{"Buzzer/wireless intercom",Heating,"Family/kid friendly","Smoke detector",Carbon monoxide}',
                '{Washer,Dryer,Essentials,Shampoo,Hangers,"Laptop friendly workspace"}'))

На данный момент я сделал следующее:

amenities_clean <- gsub('[{}"]', '', df$amenities) # remove unwanted stuff 
amenities_split <- strsplit(amenities_clean, ",") # split rows into individual amenities
amenities_unique <- unique(unlist(strsplit(amenities_clean, ","))) # get a list of unique amenities 
df[amenities_unique] <- NA # set up the columns for each amenity

Чтобы записать в новых столбцах, присутствуют или нет отдельные удобства в строках, я использую str_detect а также вложенные циклы for:

# record presence/absence of individual amenities in each new column:
library(stringr)
for(i in 1:ncol(df[amenities_unique])){
  for(j in 1:nrow(df)){
    df[amenities_unique][j,i] <- 
      ifelse(str_detect(amenities_split[j], names(df[amenities_unique][i])), 1, 0)
  }
}

Хотя это приводит к появлению предупреждений, они не кажутся вредными, так как результат выглядит хорошо:

df
  id                                                                                                amenities Wireless Internet
1  1        {"Wireless Internet","Wheelchair accessible",Kitchen,Elevator,"Buzzer/wireless intercom",Heating}                 1
2  2 {TV,"Cable TV",Internet,"Wireless Internet","Air conditioning",Kitchen,"Smoking allowed","Pets allowed"}                 1
3  3              {"Buzzer/wireless intercom",Heating,"Family/kid friendly","Smoke detector",Carbon monoxide}                 0
4  4                                    {Washer,Dryer,Essentials,Shampoo,Hangers,"Laptop friendly workspace"}                 0
  Wheelchair accessible Kitchen Elevator Buzzer/wireless intercom Heating TV Cable TV Internet Air conditioning Smoking allowed
1                     1       1        1                        1       1  0        0        1                0               0
2                     0       1        0                        0       0  1        1        1                1               1
3                     0       0        0                        1       1  0        0        0                0               0
4                     0       0        0                        0       0  0        0        0                0               0
  Pets allowed Family/kid friendly Smoke detector Carbon monoxide Washer Dryer Essentials Shampoo Hangers Laptop friendly workspace
1            0                   0              0               0      0     0          0       0       0                         0
2            1                   0              0               0      0     0          0       0       0                         0
3            0                   1              1               1      0     0          0       0       0                         0
4            0                   0              0               0      1     1          1       1       1                         1

Учитывая предупреждения и данные запутанность вложенных циклов, как можно получить тот же результат, используя функцию из семейства функций apply или dplyr?

Ответы [ 2 ]

1 голос
/ 26 апреля 2020

Я полагаю, что это дает нужный результат:

library(tidyverse)

df %>%
  mutate(amenities = str_replace_all(amenities, '["{}]', '')) %>% 
  separate_rows(amenities, sep = ",") %>% 
  pivot_wider(names_from = amenities, values_from = amenities, values_fn = list(amenities = is.character)) %>% 
  mutate_all(replace_na, 0) 

Результат:

# A tibble: 4 x 22
     id `Wireless Inter~ `Wheelchair acc~ Kitchen Elevator `Buzzer/wireles~ Heating    TV `Cable TV` Internet `Air conditioni~ `Smoking allowe~
  <dbl>            <dbl>            <dbl>   <dbl>    <dbl>            <dbl>   <dbl> <dbl>      <dbl>    <dbl>            <dbl>            <dbl>
1     1                1                1       1        1                1       1     0          0        0                0                0
2     2                1                0       1        0                0       0     1          1        1                1                1
3     3                0                0       0        0                1       1     0          0        0                0                0
4     4                0                0       0        0                0       0     0          0        0                0                0
# ... with 10 more variables: `Pets allowed` <dbl>, `Family/kid friendly` <dbl>, `Smoke detector` <dbl>, `Carbon monoxide` <dbl>, Washer <dbl>,
#   Dryer <dbl>, Essentials <dbl>, Shampoo <dbl>, Hangers <dbl>, `Laptop friendly workspace` <dbl>
1 голос
/ 26 апреля 2020

После чистки вы можете использовать cSplit_e с splitstackshape.

df$amenities_clean <- gsub('[{}"]', '', df$amenities) 
splitstackshape::cSplit_e(df, "amenities_clean", type = "character", fill = 0)

Чтобы решить эту проблему с помощью одной из функций применения, мы можем сделать:

temp <- strsplit(df$amenities_clean, ",")
amenities_unique <- unique(unlist(temp))
cbind(df, t(sapply(temp, function(x) 
                   table(factor(x, levels = amenities_unique)))))
...