Привязка рассчитывает к Dataframe, используя if_else или Count - PullRequest
1 голос
/ 11 февраля 2020

Я работал над кодом для добавления новых столбцов в существующий tbl_df. Добавьте количество столбцов для значений в столбцах; order_type, food_type, ice_cream_type и customer_info с некоторыми подробностями. Я изложил особенности, которые я ищу в каждом столбце ниже.

То, как я это вижу, есть два варианта: dplyr::if_else или комбинация dplyr::count и tidyr::pivot_wider.

Одним из возможных решений, о котором я подумал, было использование mutate_at и передача имен отдельных столбцов с помощью if_else, но я не уверен, что это будет лучшим способом сделать это.

Мое решение ниже использует tidyr и dplyr. Код выглядит так, как будто он менее эффективен, чем должен быть. Я думаю, что есть лучшее решение, чтобы делать то, что я ищу.

Я собираюсь сделать следующее:

  1. order_type будет учитываться только для «phone», а имя столбца будет принимать значение «phone» с «_order» после этого. Теоретически я смотрю, как взять значение из строки и добавить суффикс. Может быть glue или paste0?
  2. Все значения для food_type, но переименовать «мороженое» в ice_cream для имени столбца
  3. Подсчитать все в ice_cream_type, но создать только столбцы подсчета для значений не-NA
  4. Подсчитывать только те строки, которые имеют «первый раз» или начинаются с «повтор» в пределах customer_info столбец
  5. Присоединиться к оригиналу df
library(tidyverse)

df <- tibble::tribble(
         ~date, ~Initials, ~order_type,  ~food_type, ~ice_cream_type,    ~customer_info, ~cost,
    "2/1/2020",      "JS",     "phone", "ice cream",       "vanilla", "repeat_multiple",     5,
   "1/15/2019",      "JO",    "online",    "entree",              NA,      "first_time",    20,
  "12/29/2017",      "JE", "in-person",     "snack",              NA,         "no info",   6.5,
    "1/1/2018",      "OI",    "online",     "snack",              NA,    "repeat_first",     2,
    "2/1/2020",      "VM",     "phone",    "entree",              NA,         "no info",    12,
   "1/15/2019",      "PJ",     "phone",     "drink",              NA, "repeat_multiple",     3,
  "12/29/2017",      "JO",    "online",    "entree",              NA,    "repeat_first",    14,
    "1/1/2018",      "EE", "in-person", "ice cream",     "chocolate",      "first_time",     6,
    "2/1/2020",      "SL",    "online",    "entree",              NA,      "first_time",     6
  )


# order_type 
order_type_df <- df %>% 
  group_by(Initials) %>% 
  count(order_type) %>% 
  ungroup %>% 
  pivot_wider(names_from = order_type, 
              values_from = n,
              values_fill = list(n = 0)) %>% 
  select(Initials, phone_order = phone)

food_type_df <- df %>% 
  group_by(Initials) %>% 
  count(food_type) %>% 
  ungroup %>% 
  pivot_wider(names_from = food_type, 
              values_from = n,
              values_fill = list(n = 0)) %>% 
  rename(ice_cream = "ice cream")

ice_cream_df <- df %>% 
  group_by(Initials) %>% 
  count(ice_cream_type) %>% 
  ungroup %>% 
  pivot_wider(names_from = ice_cream_type, 
              values_from = n,
              values_fill = list(n = 0)) %>% 
  select(-"NA")

customer_info_df <- df %>% 
  group_by(Initials) %>% 
  count(customer_info) %>% 
  ungroup %>% 
  pivot_wider(names_from = customer_info, 
              values_from = n,
              values_fill = list(n = 0)) %>% 
  mutate(repeat_customer = repeat_first + repeat_multiple) %>% 
  select(Initials, first_time, repeat_customer)  



desired_df <- df %>% 
  left_join (order_type_df) %>% 
  left_join(food_type_df) %>% 
  left_join(customer_info_df) %>% 
  left_join(ice_cream_df)
#> Joining, by = "Initials"Joining, by = "Initials"Joining, by = "Initials"Joining,
#> by = "Initials"


desired_df 
#> # A tibble: 9 x 16
#>   date  Initials order_type food_type ice_cream_type customer_info  cost
#>   <chr> <chr>    <chr>      <chr>     <chr>          <chr>         <dbl>
#> 1 2/1/~ JS       phone      ice cream vanilla        repeat_multi~   5  
#> 2 1/15~ JO       online     entree    <NA>           first_time     20  
#> 3 12/2~ JE       in-person  snack     <NA>           no info         6.5
#> 4 1/1/~ OI       online     snack     <NA>           repeat_first    2  
#> 5 2/1/~ VM       phone      entree    <NA>           no info        12  
#> 6 1/15~ PJ       phone      drink     <NA>           repeat_multi~   3  
#> 7 12/2~ JO       online     entree    <NA>           repeat_first   14  
#> 8 1/1/~ EE       in-person  ice cream chocolate      first_time      6  
#> 9 2/1/~ SL       online     entree    <NA>           first_time      6  
#> # ... with 9 more variables: phone_order <int>, ice_cream <int>, snack <int>,
#> #   entree <int>, drink <int>, first_time <int>, repeat_customer <int>,
#> #   chocolate <int>, vanilla <int>

1 Ответ

0 голосов
/ 11 февраля 2020

Вместо поворота и нескольких left_join с можно использовать cSplit_e

library(splitstackshape)
library(dplyr)
library(tidyr)
library(stringr)
out <- df %>% 
       mutate(new_order = replace(order_type, 
            order_type != 'phone', NA_character_)) %>% 
       unite(coln, new_order, food_type, ice_cream_type, customer_info, sep=";") %>% 
       select(coln) %>%
       cSplit_e("coln", sep=";", type = "character", fill = 0, drop = TRUE) %>%
       rename_all(~ str_remove(., "coln_")) %>%
       bind_cols(df, .) %>%
       select(-`NA`)
out[8:ncol(out)]
# A tibble: 9 x 11
#  chocolate drink entree first_time `ice cream` `no info` phone repeat_first repeat_multiple snack vanilla
#      <dbl> <dbl>  <dbl>      <dbl>       <dbl>     <dbl> <dbl>        <dbl>           <dbl> <dbl>   <dbl>
#1         0     0      0          0           1         0     1            0               1     0       1
#2         0     0      1          1           0         0     0            0               0     0       0
#3         0     0      0          0           0         1     0            0               0     1       0
#4         0     0      0          0           0         0     0            1               0     1       0
#5         0     0      1          0           0         1     1            0               0     0       0
#6         0     1      0          0           0         0     1            0               1     0       0
#7         0     0      1          0           0         0     0            1               0     0       0
#8         1     0      0          1           1         0     0            0               0     0       0
#9         0     0      1          1           0         0     0            0               0     0       0

Мы также можем сделать это с map, передав имена столбцов

out2 <- map(names(df)[3:6], ~ 
          df %>%
              count(Initials, !! rlang::sym(.x)) %>% 
              pivot_wider(names_from = .x, values_from =n,
                 values_fill = list(n = 0))) %>% 
            reduce(full_join, by = 'Initials') %>% 
          select(-`NA`) %>%
          rename_all(~ str_c(., "newcols"))
          bind_cols(df, .)
...