Как создать мусорные ведра в sparklyr? - PullRequest
0 голосов
/ 31 января 2019

У меня есть примерный фрейм данных df в R и rd_3 в sparklyr.Я хочу создать столбец visit_category в фрейме данных spark.Я знаю, что мы можем использовать функцию Cut в R для создания того же столбца, но как я могу создать то же самое в sparklyr?

Для воспроизводимых целей

df<-data.frame(visit_duration=c(12,20,70,100),city=c("X","X","X","X"),visit_category=c("0-15","15-25","25-80","80-120"))

rd_3<-copy_to(sc,df)

Я не могу использовать операторы ifelse в качестве числа биновбольше 50Я использовал ft_bucketlizer в sparklyr, но он показал ошибку, как указано ниже

rd_3 %>%
ft_bucketizer("visit_duration", "Visit_Category", splits = c(0, 15, 25, 80 , 120)) %>% 
mutate(Visit_Category = factor(Visit_Category, labels = c("0-15","15-25","25-80","80-120")))

это ошибка, которую я получаю

Error: org.apache.spark.sql.catalyst.parser.ParseException: 
extraneous input 'AS' expecting {')', ','}(line 1, pos 98)

== SQL ==
SELECT `new_col`, `visit_duration`, FACTOR(`Visit_Category`, ("0-15", 
"15-25", "25-80", "80-120") AS "labels") AS `Visit_Category`

In addition: Warning message:
Named arguments ignored for SQL FACTOR 

1 Ответ

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

В Spark SQL нет factors или эквивалентных типов.Вместо этого, при необходимости, преобразователи Spark ML добавляют специальные метаданные столбцов.

В результате вызов factor интерпретируется как удаленные функции и передается через механизм перевода SQL, что приводит к полной бессмысленности.

ТеперьПредполагая, что вы действительно хотите пойти с Бакетизером, вам придется сгруппировать

splits <- c(0, 15, 25, 80, 120)

bucketized <- rd_3 %>%
   ft_bucketizer("visit_duration", "Visit_Category", splits = splits)

, создать справочную таблицу:

ref <- copy_to(sc, tibble(
  Visit_Category = seq_along(splits[-1]) - 1,
  label = paste0(
    splits[-length(splits)],
    "-",
    splits[-1]
  )
))

и присоединиться:

bucketized %>% left_join(ref, by = "Visit_Category")
# Source: spark<?> [?? x 4]
  visit_duration city  Visit_Category label 
           <dbl> <chr>          <dbl> <chr> 
1             12 X                  0 0-15  
2             20 X                  1 15-25 
3             70 X                  2 25-80 
4            100 X                  3 80-120

Хотя может быть проще просто создать CASE WHEN выражение, подобное этому:

library(rlang)

expr <- purrr::map2(
  splits[-length(splits)], splits[-1], 
 function(lo, hi) 
   glue::glue("visit_duration %BETWEEN% {lo} %AND% {hi} ~ '{lo}-{hi}'")
) %>%
  glue::glue_collapse(sep=",\n") %>% 
  paste("case_when(\n", ., ")")

rd_3 %>% mutate(result = !!parse_quo(expr, env = caller_frame()))
# Source: spark<?> [?? x 4]
  visit_duration city  visit_category result
           <dbl> <chr> <chr>          <chr> 
1             12 X     0-15           0-15  
2             20 X     15-25          15-25 
3             70 X     25-80          25-80 
4            100 X     80-120         80-120

или просто взять декартово произведение со ссылкой и отфильтровать результаты:

ref2 <- copy_to(sc, tibble(
  lo = splits[-length(splits)],
  hi = splits[-1]
))

cross_join(rd_3, ref2, explicit=TRUE) %>% 
  filter(visit_duration >= lo & visit_duration < hi) %>%
  mutate(label = paste0(lo, "-", hi)) %>%
  select(-lo, -hi)
# Source: spark<?> [?? x 6]
  visit_duration city  visit_category    lo    hi label     
           <dbl> <chr> <chr>          <dbl> <dbl> <chr>     
1             12 X     0-15               0    15 0.0-15.0  
2             20 X     15-25             15    25 15.0-25.0 
3             70 X     25-80             25    80 25.0-80.0 
4            100 X     80-120            80   120 80.0-120.0
...