Uso de dataframes y tablas en R

En este artículo se describe cómo usar paquetes de R como SparkR, sparklyr y dplyr para trabajar con data.frame de R, dataframes de Spark y tablas en memoria.

Cuando trabaje con SparkR, sparklyr y dplyr, podría encontrarse con que puede completar una operación determinada con todos estos paquetes, y puede usar el paquete con el que se sienta más cómodo. Por ejemplo, para ejecutar una consulta, puede llamar a funciones como SparkR::sql, sparklyr::sdf_sql y dplyr::select. En otras ocasiones, es posible que pueda completar una operación con solo uno o dos de estos paquetes, y el paquete que elija dependerá de su escenario de uso. Por ejemplo, la forma de llamar a sparklyr::sdf_quantile difiere ligeramente de la forma en que se llama a dplyr::percentile_approx, aunque ambas funciones calculan cuantiles.

Puede usar SQL como puente entre SparkR y sparklyr. Por ejemplo, puede usar SparkR::sql para consultar las tablas que cree con sparklyr. Puede usar sparklyr::sdf_sql para consultar las tablas que cree con SparkR. Además, el código dplyr siempre se traduce a SQL en memoria antes de que se ejecute. Consulte también Interoperabilidad de API y Traducción de SQL.

Carga de SparkR, sparklyr y dplyr

Los paquetes de SparkR, sparklyr y dplyr se incluyen en la instancia de Databricks Runtime que está instalada en los clústeres de Azure Databricks. Por lo tanto, no es necesario llamar al objeto install.package habitual para poder empezar a llamar a estos paquetes. Aun así, debe cargar primero estos paquetes con library. Por ejemplo, en un cuaderno de R en un área de trabajo de Azure Databricks, ejecute el código siguiente en una celda del cuaderno para cargar SparkR, sparklyr y dplyr:

library(SparkR)
library(sparklyr)
library(dplyr)

Conexión de sparklyr a un clúster

Después de cargar sparklyr, debe llamar a sparklyr::spark_connect para conectarse al clúster especificando el método de conexión databricks. Por ejemplo, ejecute el código siguiente en una celda del cuaderno para conectarse al clúster que lo hospeda:

sc <- spark_connect(method = "databricks")

En cambio, un cuaderno de Azure Databricks ya establece el objeto SparkSession en el clúster para su uso con SparkR, por lo que no es necesario llamar a SparkR::sparkR.session para poder empezar a llamar a SparkR.

Carga de un archivo de datos JSON en el área de trabajo

Muchos de los ejemplos de código de este artículo se basan en datos de una ubicación específica del área de trabajo de Azure Databricks, con nombres de columna y tipos de datos específicos. Los datos de este ejemplo de código se originan en un archivo JSON denominado book.json de GitHub. Para obtener este archivo y cargarlo en el área de trabajo:

  1. Vaya al archivo books.json en GitHub y use un editor de texto para copiar su contenido en un archivo denominado books.json en algún lugar del equipo local.
  2. En la barra lateral del área de trabajo de Azure Databricks, haga clic en Catálogo.
  3. Haga clic en Create Table (Crear tabla).
  4. En la pestaña Cargar archivo, coloque el archivo books.json del equipo local en el cuadro Colocar archivos para cargar. También puede hacer clic para examinar e ir al archivo books.json del equipo local.

De forma predeterminada, Azure Databricks carga el archivo books.json local en la ubicación de DBFS del área de trabajo con la ruta de acceso /FileStore/tables/books.json.

No haga clic en Create Table with UI (Crear tabla con la interfaz de usuario) ni en Create Table in Notebook (Crear tabla en el cuaderno). En los ejemplos de código de este artículo se usan los datos del archivo books.json cargado en esta ubicación de DBFS.

Lectura de datos JSON en un dataframe

Use sparklyr::spark_read_json para leer el archivo JSON cargado en un dataframe. Para ello, especifique la conexión, la ruta de acceso al archivo JSON y un nombre para la representación de tabla interna de los datos. En este ejemplo, debe especificar que el archivo book.json contiene varias líneas. Es opcional especificar aquí el esquema de las columnas. Si no lo hace, sparklyr deducirá el esquema de las columnas de forma predeterminada. Por ejemplo, ejecute el código siguiente en una celda de cuaderno para leer los datos del archivo JSON cargado en un dataframe denominado jsonDF:

jsonDF <- spark_read_json(
  sc      = sc,
  name    = "jsonTable",
  path    = "/FileStore/tables/books.json",
  options = list("multiLine" = TRUE),
  columns = c(
    author    = "character",
    country   = "character",
    imageLink = "character",
    language  = "character",
    link      = "character",
    pages     = "integer",
    title     = "character",
    year      = "integer"
  )
)

Puede usar SparkR::head, SparkR::show o sparklyr::collect para imprimir las primeras filas de un dataframe. De forma predeterminada, head imprime las seis primeras filas. show y collect imprimen las diez primeras filas. Por ejemplo, ejecute el código siguiente en una celda del cuaderno para imprimir las primeras filas del dataframe denominado jsonDF:

head(jsonDF)

# Source: spark<?> [?? x 8]
#   author                  country        image…¹ langu…² link  pages title  year
#   <chr>                   <chr>          <chr>   <chr>   <chr> <int> <chr> <int>
# 1 Chinua Achebe           Nigeria        images… English "htt…   209 Thin…  1958
# 2 Hans Christian Andersen Denmark        images… Danish  "htt…   784 Fair…  1836
# 3 Dante Alighieri         Italy          images… Italian "htt…   928 The …  1315
# 4 Unknown                 Sumer and Akk… images… Akkadi… "htt…   160 The … -1700
# 5 Unknown                 Achaemenid Em… images… Hebrew  "htt…   176 The …  -600
# 6 Unknown                 India/Iran/Ir… images… Arabic  "htt…   288 One …  1200
# … with abbreviated variable names ¹​imageLink, ²​language

show(jsonDF)

# Source: spark<jsonTable> [?? x 8]
#    author                  country       image…¹ langu…² link  pages title  year
#    <chr>                   <chr>         <chr>   <chr>   <chr> <int> <chr> <int>
#  1 Chinua Achebe           Nigeria       images… English "htt…   209 Thin…  1958
#  2 Hans Christian Andersen Denmark       images… Danish  "htt…   784 Fair…  1836
#  3 Dante Alighieri         Italy         images… Italian "htt…   928 The …  1315
#  4 Unknown                 Sumer and Ak… images… Akkadi… "htt…   160 The … -1700
#  5 Unknown                 Achaemenid E… images… Hebrew  "htt…   176 The …  -600
#  6 Unknown                 India/Iran/I… images… Arabic  "htt…   288 One …  1200
#  7 Unknown                 Iceland       images… Old No… "htt…   384 Njál…  1350
#  8 Jane Austen             United Kingd… images… English "htt…   226 Prid…  1813
#  9 Honoré de Balzac        France        images… French  "htt…   443 Le P…  1835
# 10 Samuel Beckett          Republic of … images… French… "htt…   256 Moll…  1952
# … with more rows, and abbreviated variable names ¹​imageLink, ²​language
# ℹ Use `print(n = ...)` to see more rows

collect(jsonDF)

# A tibble: 100 × 8
#    author                  country       image…¹ langu…² link  pages title  year
#    <chr>                   <chr>         <chr>   <chr>   <chr> <int> <chr> <int>
#  1 Chinua Achebe           Nigeria       images… English "htt…   209 Thin…  1958
#  2 Hans Christian Andersen Denmark       images… Danish  "htt…   784 Fair…  1836
#  3 Dante Alighieri         Italy         images… Italian "htt…   928 The …  1315
#  4 Unknown                 Sumer and Ak… images… Akkadi… "htt…   160 The … -1700
#  5 Unknown                 Achaemenid E… images… Hebrew  "htt…   176 The …  -600
#  6 Unknown                 India/Iran/I… images… Arabic  "htt…   288 One …  1200
#  7 Unknown                 Iceland       images… Old No… "htt…   384 Njál…  1350
#  8 Jane Austen             United Kingd… images… English "htt…   226 Prid…  1813
#  9 Honoré de Balzac        France        images… French  "htt…   443 Le P…  1835
# 10 Samuel Beckett          Republic of … images… French… "htt…   256 Moll…  1952
# … with 90 more rows, and abbreviated variable names ¹​imageLink, ²​language
# ℹ Use `print(n = ...)` to see more rows

Ejecución de consultas SQL, y escritura y lectura en una tabla

Puede usar funciones dplyr para ejecutar consultas SQL en un dataframe. Por ejemplo, ejecute el código siguiente en una celda del cuaderno para usar dplyr::group_by y dployr::count para obtener recuentos por autor del dataframe denominado jsonDF. Use dplyr::arrange y dplyr::desc para ordenar el resultado de forma descendente por recuento. Después, imprima las diez primeras filas de forma predeterminada.

group_by(jsonDF, author) %>%
  count() %>%
  arrange(desc(n))

# Source:     spark<?> [?? x 2]
# Ordered by: desc(n)
#    author                     n
#    <chr>                  <dbl>
#  1 Fyodor Dostoevsky          4
#  2 Unknown                    4
#  3 Leo Tolstoy                3
#  4 Franz Kafka                3
#  5 William Shakespeare        3
#  6 William Faulkner           2
#  7 Gustave Flaubert           2
#  8 Homer                      2
#  9 Gabriel García Márquez     2
# 10 Thomas Mann                2
# … with more rows
# ℹ Use `print(n = ...)` to see more rows

A continuación, puede usar sparklyr::spark_write_table para escribir el resultado en una tabla de Azure Databricks. Por ejemplo, ejecute el código siguiente en una celda del cuaderno para volver a ejecutar la consulta y, luego, escriba el resultado en una tabla denominada json_books_agg:

group_by(jsonDF, author) %>%
  count() %>%
  arrange(desc(n)) %>%
  spark_write_table(
    name = "json_books_agg",
    mode = "overwrite"
  )

Para comprobar que la tabla se ha creado, puede usar sparklyr::sdf_sql junto con SparkR::showDF para mostrar los datos de la tabla. Por ejemplo, ejecute el código siguiente en una celda del cuaderno para consultar la tabla en un dataframe y, después, use sparklyr::collect para imprimir las diez primeras filas del dataframe de forma predeterminada:

collect(sdf_sql(sc, "SELECT * FROM json_books_agg"))

# A tibble: 82 × 2
#    author                     n
#    <chr>                  <dbl>
#  1 Fyodor Dostoevsky          4
#  2 Unknown                    4
#  3 Leo Tolstoy                3
#  4 Franz Kafka                3
#  5 William Shakespeare        3
#  6 William Faulkner           2
#  7 Homer                      2
#  8 Gustave Flaubert           2
#  9 Gabriel García Márquez     2
# 10 Thomas Mann                2
# … with 72 more rows
# ℹ Use `print(n = ...)` to see more rows

También puede usar sparklyr::spark_read_table para hacer algo similar. Por ejemplo, ejecute el código siguiente en una celda del cuaderno para consultar el dataframe anterior denominado sparklyr::collect en un dataframe y, después, use jsonDF para imprimir las diez primeras filas del dataframe de forma predeterminada:

fromTable <- spark_read_table(
  sc   = sc,
  name = "json_books_agg"
)

collect(fromTable)

# A tibble: 82 × 2
#    author                     n
#    <chr>                  <dbl>
#  1 Fyodor Dostoevsky          4
#  2 Unknown                    4
#  3 Leo Tolstoy                3
#  4 Franz Kafka                3
#  5 William Shakespeare        3
#  6 William Faulkner           2
#  7 Homer                      2
#  8 Gustave Flaubert           2
#  9 Gabriel García Márquez     2
# 10 Thomas Mann                2
# … with 72 more rows
# ℹ Use `print(n = ...)` to see more rows

Adición de columnas y cálculo de valores de columna en un dataframe

Puede usar funciones dplyr para agregar columnas a dataframes y calcular los valores de las columnas.

Por ejemplo, ejecute el código siguiente en una celda del cuaderno para obtener el contenido del dataframe denominado jsonDF. Use dplyr::mutate para agregar una columna denominada today y rellene esta nueva columna con la marca de tiempo actual. Después, escriba este contenido en un nuevo dataframe denominado withDate y use dplyr::collect para imprimir las diez primeras filas del nuevo dataframe de forma predeterminada.

Nota:

dplyr::mutate solo acepta argumentos que se ajustan a las funciones integradas de Hive (también conocidas como UDF) y a las funciones de agregado integradas (también conocidas como UDAF). Para obtener información general, consulte Funciones de Hive. Para obtener información sobre las funciones relacionadas con la fecha de esta sección, vea Funciones de fecha.

withDate <- jsonDF %>%
  mutate(today = current_timestamp())

collect(withDate)

# A tibble: 100 × 9
#    author    country image…¹ langu…² link  pages title  year today
#    <chr>     <chr>   <chr>   <chr>   <chr> <int> <chr> <int> <dttm>
#  1 Chinua A… Nigeria images… English "htt…   209 Thin…  1958 2022-09-27 21:32:59
#  2 Hans Chr… Denmark images… Danish  "htt…   784 Fair…  1836 2022-09-27 21:32:59
#  3 Dante Al… Italy   images… Italian "htt…   928 The …  1315 2022-09-27 21:32:59
#  4 Unknown   Sumer … images… Akkadi… "htt…   160 The … -1700 2022-09-27 21:32:59
#  5 Unknown   Achaem… images… Hebrew  "htt…   176 The …  -600 2022-09-27 21:32:59
#  6 Unknown   India/… images… Arabic  "htt…   288 One …  1200 2022-09-27 21:32:59
#  7 Unknown   Iceland images… Old No… "htt…   384 Njál…  1350 2022-09-27 21:32:59
#  8 Jane Aus… United… images… English "htt…   226 Prid…  1813 2022-09-27 21:32:59
#  9 Honoré d… France  images… French  "htt…   443 Le P…  1835 2022-09-27 21:32:59
# 10 Samuel B… Republ… images… French… "htt…   256 Moll…  1952 2022-09-27 21:32:59
# … with 90 more rows, and abbreviated variable names ¹​imageLink, ²​language
# ℹ Use `print(n = ...)` to see more rows

Ahora use dplyr::mutate para agregar dos columnas más al contenido del dataframe withDate. Las nuevas columnas month y year contienen el mes en forma de número y el año de la columna today. Después, escriba este contenido en un nuevo dataframe denominado withMMyyyy y use dplyr::select junto con dplyr::collect para imprimir las columnas author, title, month y year de las diez primeras filas del nuevo dataframe de forma predeterminada:

withMMyyyy <- withDate %>%
  mutate(month = month(today),
         year  = year(today))

collect(select(withMMyyyy, c("author", "title", "month", "year")))

# A tibble: 100 × 4
#    author                  title                                     month  year
#    <chr>                   <chr>                                     <int> <int>
#  1 Chinua Achebe           Things Fall Apart                             9  2022
#  2 Hans Christian Andersen Fairy tales                                   9  2022
#  3 Dante Alighieri         The Divine Comedy                             9  2022
#  4 Unknown                 The Epic Of Gilgamesh                         9  2022
#  5 Unknown                 The Book Of Job                               9  2022
#  6 Unknown                 One Thousand and One Nights                   9  2022
#  7 Unknown                 Njál's Saga                                   9  2022
#  8 Jane Austen             Pride and Prejudice                           9  2022
#  9 Honoré de Balzac        Le Père Goriot                                9  2022
# 10 Samuel Beckett          Molloy, Malone Dies, The Unnamable, the …     9  2022
# … with 90 more rows
# ℹ Use `print(n = ...)` to see more rows

Ahora use dplyr::mutate para agregar dos columnas más al contenido del dataframe withMMyyyy. La nueva columna formatted_date contiene la parte yyyy-MM-dd de la columna today, mientras que la nueva columna day contiene el día en forma de número de la nueva columna formatted_date. Después, escriba este contenido en un nuevo dataframe denominado withUnixTimestamp y use dplyr::select junto con dplyr::collect para imprimir las columnas title, formatted_date y day de las diez primeras filas del nuevo dataframe de forma predeterminada:

withUnixTimestamp <- withMMyyyy %>%
  mutate(formatted_date = date_format(today, "yyyy-MM-dd"),
         day            = dayofmonth(formatted_date))

collect(select(withUnixTimestamp, c("title", "formatted_date", "day")))

# A tibble: 100 × 3
#    title                                           formatted_date   day
#    <chr>                                           <chr>          <int>
#  1 Things Fall Apart                               2022-09-27        27
#  2 Fairy tales                                     2022-09-27        27
#  3 The Divine Comedy                               2022-09-27        27
#  4 The Epic Of Gilgamesh                           2022-09-27        27
#  5 The Book Of Job                                 2022-09-27        27
#  6 One Thousand and One Nights                     2022-09-27        27
#  7 Njál's Saga                                     2022-09-27        27
#  8 Pride and Prejudice                             2022-09-27        27
#  9 Le Père Goriot                                  2022-09-27        27
# 10 Molloy, Malone Dies, The Unnamable, the trilogy 2022-09-27        27
# … with 90 more rows
# ℹ Use `print(n = ...)` to see more rows

Creación de una vista temporal

Puede crear vistas temporales con nombre en memoria basadas en dataframes existentes. Por ejemplo, ejecute el código siguiente en una celda del cuaderno para usar SparkR::createOrReplaceTempView con el fin de obtener el contenido del dataframe anterior denominado jsonTable y crear a partir de él una vista temporal denominada timestampTable. Luego, use sparklyr::spark_read_table para leer el contenido de la vista temporal. Use sparklyr::collect para imprimir las diez primeras filas de la tabla temporal de forma predeterminada:

createOrReplaceTempView(withTimestampDF, viewName = "timestampTable")

spark_read_table(
  sc = sc,
  name = "timestampTable"
) %>% collect()

# A tibble: 100 × 10
#    author    country image…¹ langu…² link  pages title  year today
#    <chr>     <chr>   <chr>   <chr>   <chr> <int> <chr> <int> <dttm>
#  1 Chinua A… Nigeria images… English "htt…   209 Thin…  1958 2022-09-27 21:11:56
#  2 Hans Chr… Denmark images… Danish  "htt…   784 Fair…  1836 2022-09-27 21:11:56
#  3 Dante Al… Italy   images… Italian "htt…   928 The …  1315 2022-09-27 21:11:56
#  4 Unknown   Sumer … images… Akkadi… "htt…   160 The … -1700 2022-09-27 21:11:56
#  5 Unknown   Achaem… images… Hebrew  "htt…   176 The …  -600 2022-09-27 21:11:56
#  6 Unknown   India/… images… Arabic  "htt…   288 One …  1200 2022-09-27 21:11:56
#  7 Unknown   Iceland images… Old No… "htt…   384 Njál…  1350 2022-09-27 21:11:56
#  8 Jane Aus… United… images… English "htt…   226 Prid…  1813 2022-09-27 21:11:56
#  9 Honoré d… France  images… French  "htt…   443 Le P…  1835 2022-09-27 21:11:56
# 10 Samuel B… Republ… images… French… "htt…   256 Moll…  1952 2022-09-27 21:11:56
# … with 90 more rows, 1 more variable: month <chr>, and abbreviated variable
#   names ¹​imageLink, ²​language
# ℹ Use `print(n = ...)` to see more rows, and `colnames()` to see all variable names

Realización de análisis estadísticos en un dataframe

Puede usar sparklyr junto con dplyr para análisis estadísticos.

Por ejemplo, cree un dataframe para ejecutar estadísticas en él. Para ello, ejecute el código siguiente en una celda del cuaderno con el fin de usar sparklyr::sdf_copy_to para escribir el contenido del conjunto de datos iris integrado en R en un elemento dataframe denominado iris. Use sparklyr::sdf_collect para imprimir las diez primeras filas de la tabla temporal de forma predeterminada:

irisDF <- sdf_copy_to(
  sc        = sc,
  x         = iris,
  name      = "iris",
  overwrite = TRUE
)

sdf_collect(irisDF, "row-wise")

# A tibble: 150 × 5
#    Sepal_Length Sepal_Width Petal_Length Petal_Width Species
#           <dbl>       <dbl>        <dbl>       <dbl> <chr>
#  1          5.1         3.5          1.4         0.2 setosa
#  2          4.9         3            1.4         0.2 setosa
#  3          4.7         3.2          1.3         0.2 setosa
#  4          4.6         3.1          1.5         0.2 setosa
#  5          5           3.6          1.4         0.2 setosa
#  6          5.4         3.9          1.7         0.4 setosa
#  7          4.6         3.4          1.4         0.3 setosa
#  8          5           3.4          1.5         0.2 setosa
#  9          4.4         2.9          1.4         0.2 setosa
# 10          4.9         3.1          1.5         0.1 setosa
# … with 140 more rows
# ℹ Use `print(n = ...)` to see more rows

Ahora use dplyr::group_by para agrupar las filas por la columna Species. Use dplyr::summarize junto con dplyr::percentile_approx para calcular estadísticas de resumen según los cuantiles 25, 50, 75 y 100 de la columna Sepal_Length por Species. Use sparklyr::collect para imprimir los resultados:

Nota:

dplyr::summarize solo acepta argumentos que se ajustan a las funciones integradas de Hive (también conocidas como UDF) y a las funciones de agregado integradas (también conocidas como UDAF). Para obtener información general, consulte Funciones de Hive. Para obtener información sobre percentile_approx, vea Funciones de agregado integradas (UDAF).

quantileDF <- irisDF %>%
  group_by(Species) %>%
  summarize(
    quantile_25th = percentile_approx(
      Sepal_Length,
      0.25
    ),
    quantile_50th = percentile_approx(
      Sepal_Length,
      0.50
    ),
    quantile_75th = percentile_approx(
      Sepal_Length,
      0.75
    ),
    quantile_100th = percentile_approx(
      Sepal_Length,
      1.0
    )
  )

collect(quantileDF)

# A tibble: 3 × 5
#   Species    quantile_25th quantile_50th quantile_75th quantile_100th
#   <chr>              <dbl>         <dbl>         <dbl>          <dbl>
# 1 virginica            6.2           6.5           6.9            7.9
# 2 versicolor           5.6           5.9           6.3            7
# 3 setosa               4.8           5             5.2            5.8

Se pueden calcular resultados similares, por ejemplo, mediante sparklyr::sdf_quantile:

print(sdf_quantile(
  x = irisDF %>%
    filter(Species == "virginica"),
  column = "Sepal_Length",
  probabilities = c(0.25, 0.5, 0.75, 1.0)
))

# 25%  50%  75% 100%
# 6.2  6.5  6.9  7.9