Sparklyr заполняет NA/NULL в искровом фрейме

Я хотел бы назначить NA/NULL в кадре данных искры своему ближайшему соседу. Я пришел из R фона, поэтому я использую sparklyr, но не могу придумать, как это сделать.

Вот пример кода:

 set.seed(1)    
 example <- data.frame (ID = 1:10, Cat = letters[1:5], 
                       Numb = sample(c(NA, NA, NA, NA, 1:10), 10))
     ID Cat Numb
  1   1   a   NA
  2   2   b    1
  3   3   c    3
  4   4   d    6
  5   5   e   NA
  6   6   a    5
  7   7   b    4
  8   8   c    9
  9   9   d   10
  10 10   e   NA 

Поэтому я хотел бы заполнить столбец Numb, ID 1 NA - ID2 Numb 1, ID 5 - либо ID 4 и 6 (6 или 5), а также значение ID 10 - ID 9 (10). Это можно сделать в R легко. Есть ли способ сделать это в Spark через Sparklyr?

Вот мое решение R:

example$Numb1 <- example$Numb[c(1,1:(nrow(example)-1))]
example$Numb2 <- example$Numb[c(2:(nrow(example)), nrow(example))]
example$Merge <- ifelse(is.na(example$Numb), ifelse(is.na(example$Numb1), 
example$Numb2, example$Numb1), example$Numb)

    ID Cat Numb Numb1 Numb2 Merge
1   1   a   NA    NA     1     1
2   2   b    1    NA     3     1
3   3   c    3     1     6     3
4   4   d    6     3    NA     6
5   5   e   NA     6     5     6
6   6   a    5    NA     4     5
7   7   b    4     5     9     4
8   8   c    9     4    10     9
9   9   d   10     9    NA    10
10 10   e   NA    10    NA    10

Конечно, все может стать более сложным, если у меня будет несколько значений NA в последовательных строках. Может быть, еще одно предложение можно посоветовать.

Но для sparklyr я понятия не имею, что я могу сделать.

1 ответ

Решение

Вот частично работающее решение с SQL-запросом и mutate функция от dplyr пакет. Он не затрагивает ситуацию множественных значений NA в последовательных строках, поскольку это перевод вашего базового решения R, но он может быть полезен для других (более полных) подходов.

Я использовал функции Lag и Lead в HiveQL, чтобы выполнить "сдвиг" вниз и вверх вашего столбца. Он включает в себя создание новой вспомогательной таблицы Spark (пример2), которая содержит столбцы "Numb1" и "Numb2". Затем, после создания вспомогательной таблицы, вы можете создать столбец "Объединенный" с mutate

library(DBI)
library(sparklyr)
library(dplyr)

set.seed(1)    
exampleDF <- data.frame (ID = 1:10, Cat = letters[1:5], 
                         Numb = sample(c(NA, NA, NA, NA, 1:10), 10))

# Connection to Spark and creation of the table to test.
sc <- spark_connect("local")
example <- copy_to(sc, exampleDF)  

# Create a Spark table with columns Numb1 and Numb2
DBI::dbSendQuery(sc, "CREATE TABLE example2 AS (SELECT ID, Cat, Numb, LAG(Numb, 1) over (PARTITION BY 1 ORDER BY ID) AS Numb1,
             LEAD(Numb, 1) over (PARTITION BY 1 ORDER BY ID) AS Numb2 FROM exampledf)")

# Load the auxiliary table as a Spark DataFrame
ex2 <- tbl(sc, "example2")

# Mutate in order to create the Merged column
res <- ex2 %>%
  mutate(Merged = ifelse(is.na(Numb), ifelse(is.na(Numb1), Numb2, Numb1), Numb))

res

# Source:   lazy query [?? x 6]
# Database: spark_connection
      id   cat  numb numb1 numb2 Merged
   <int> <chr> <int> <int> <int>  <int>
 1     1     a    NA    NA     1      1
 2     2     b     1    NA     3      1
 3     3     c     3     1     6      3
 4     4     d     6     3    NA      6
 5     5     e    NA     6     5      6
 6     6     a     5    NA     4      5
 7     7     b     4     5     9      4
 8     8     c     9     4    10      9
 9     9     d    10     9    NA     10
10    10     e    NA    10    NA     10

Как примечание, вы также можете избежать использования mutate функция (и все ifelses) с помощью COALESCE функция. Я думаю, что это будет намного эффективнее.

DBI::dbGetQuery(sc, "SELECT ID, Cat, Numb, COALESCE(Numb, Numb1, Numb2) AS Merged FROM example2")
   ID Cat Numb Merged
1   1   a   NA      1
2   2   b    1      1
3   3   c    3      3
4   4   d    6      6
5   5   e   NA      6
6   6   a    5      5
7   7   b    4      4
8   8   c    9      9
9   9   d   10     10
10 10   e   NA     10

Надеюсь, это поможет.

РЕДАКТИРОВАНИЕ

Если вы хотите вообще избежать использования SQL, вы можете сделать это также с dplyr функции:

example %>% arrange(ID) %>%
    mutate(Numb1 = lag(Numb, 1)) %>%
    mutate(Numb2 = lead(Numb, 1L)) %>%
    mutate(Merged = ifelse(is.na(Numb), ifelse(is.na(Numb1), Numb2, Numb1), Numb))
# Source:     lazy query [?? x 6]
# Database:   spark_connection
# Ordered by: ID
      ID   Cat  Numb Numb1 Numb2 Merged
   <int> <chr> <int> <int> <int>  <int>
 1     1     a    NA    NA     1      1
 2     2     b     1    NA     3      1
 3     3     c     3     1     6      3
 4     4     d     6     3    NA      6
 5     5     e    NA     6     5      6
 6     6     a     5    NA     4      5
 7     7     b     4     5     9      4
 8     8     c     9     4    10      9
 9     9     d    10     9    NA     10
10    10     e    NA    10    NA     10
# ... with more rows

У меня были некоторые проблемы с кодированием двух последовательных mutate функции (вот почему я использовал смешанный подход SQL-dplyr в первую очередь). Я закончил тем, что открыл проблему на sparklyr.

Другие вопросы по тегам