Dela via


Arbeta med DataFrames och tabeller i R

Den här artikeln beskriver hur du använder R-paket som SparkR, sparklyr och dplyr för att arbeta med R data.frames, Spark DataFrames och minnesinterna tabeller.

Observera att när du arbetar med SparkR, sparklyr och dplyr kan du upptäcka att du kan slutföra en viss åtgärd med alla dessa paket, och du kan använda det paket som du är mest bekväm med. Om du till exempel vill köra en fråga kan du anropa funktioner som SparkR::sql, sparklyr::sdf_sqloch dplyr::select. Vid andra tillfällen kanske du kan slutföra en åtgärd med bara ett eller två av dessa paket, och den åtgärd du väljer beror på ditt användningsscenario. Till exempel skiljer sig sättet du anropar sparklyr::sdf_quantile något från hur du anropar dplyr::percentile_approx, även om båda funktionerna beräknar kvantantiklar.

Du kan använda SQL som en brygga mellan SparkR och sparklyr. Du kan till exempel använda SparkR::sql för att fråga efter tabeller som du skapar med sparklyr. Du kan använda sparklyr::sdf_sql för att fråga efter tabeller som du skapar med SparkR. Och dplyr koden översätts alltid till SQL i minnet innan den körs. Se även API-samverkan och SQL-översättning.

Läs in SparkR, sparklyr och dplyr

SparkR-, sparklyr- och dplyr-paketen ingår i Databricks Runtime som är installerat på Azure Databricks-kluster. Därför behöver du inte anropa det vanliga install.package innan du kan börja anropa dessa paket. Du måste dock fortfarande läsa in dessa paket med library först. Från en R-notebook-fil i en Azure Databricks-arbetsyta kör du till exempel följande kod i en notebook-cell för att läsa in SparkR, sparklyr och dplyr:

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

Anslut sparklyr till ett kluster

När du har läst in sparklyr måste du anropa sparklyr::spark_connect för att ansluta till klustret och ange databricks anslutningsmetoden. Kör till exempel följande kod i en notebook-cell för att ansluta till klustret som är värd för notebook-filen:

sc <- spark_connect(method = "databricks")

En Azure Databricks-notebook-fil etablerar däremot redan en SparkSession i klustret för användning med SparkR, så du behöver inte anropa SparkR::sparkR.session innan du kan börja anropa SparkR.

Ladda upp en JSON-datafil till din arbetsyta

Många av kodexemplen i den här artikeln baseras på data på en specifik plats på din Azure Databricks-arbetsyta, med specifika kolumnnamn och datatyper. Data för det här kodexemplet kommer från en JSON-fil med namnet book.json från GitHub. Så här hämtar du den här filen och laddar upp den till din arbetsyta:

  1. Gå till filen books.json på GitHub och använd en textredigerare för att kopiera innehållet till en fil med namnet books.json någonstans på den lokala datorn.
  2. I sidofältet för Azure Databricks-arbetsytan klickar du på Katalog.
  3. Klicka på Skapa tabell.
  4. På fliken Ladda upp fil släpper du books.json filen från den lokala datorn till rutan Släpp filer att ladda upp. Eller välj klicka för att bläddra och bläddra till books.json filen från den lokala datorn.

Som standard laddar Azure Databricks upp din lokala books.json fil till DBFS-platsen på arbetsytan med sökvägen /FileStore/tables/books.json.

Klicka inte på Skapa tabell med användargränssnitt eller Skapa tabell i Notebook. Kodexemplen i den här artikeln använder data i den uppladdade books.json filen på den här DBFS-platsen.

Läsa JSON-data i en DataFrame

Använd sparklyr::spark_read_json för att läsa den uppladdade JSON-filen till en DataFrame, ange anslutningen, sökvägen till JSON-filen och ett namn för den interna tabellrepresentationen av data. I det här exemplet måste du ange att book.json filen innehåller flera rader. Det är valfritt att ange kolumnernas schema här. Annars härleder sparklyr kolumnernas schema som standard. Kör till exempel följande kod i en notebook-cell för att läsa den uppladdade JSON-filens data till en DataFrame med namnet 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"
  )
)

Du kan använda SparkR::head, SparkR::showeller sparklyr::collect för att skriva ut de första raderna i en DataFrame. Som standard head skriver de första sex raderna ut som standard. show och collect skriv ut de första 10 raderna. Kör till exempel följande kod i en notebook-cell för att skriva ut de första raderna i DataFrame med namnet 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

Kör SQL-frågor och skriv till och läsa från en tabell

Du kan använda dplyr-funktioner för att köra SQL-frågor på en DataFrame. Kör till exempel följande kod i en notebook-cell för att använda dplyr::group_by och dployr::count för att få antal av författare från DataFrame med namnet jsonDF. Använd dplyr::arrange och dplyr::desc för att sortera resultatet i fallande ordning efter antal. Skriv sedan ut de första 10 raderna som standard.

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

Du kan sedan använda sparklyr::spark_write_table för att skriva resultatet till en tabell i Azure Databricks. Kör till exempel följande kod i en notebook-cell för att köra frågan igen och skriv sedan resultatet till en tabell med namnet json_books_agg:

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

För att kontrollera att tabellen har skapats kan du använda sparklyr::sdf_sql tillsammans med SparkR::showDF för att visa tabellens data. Kör till exempel följande kod i en notebook-cell för att köra frågor mot tabellen till en DataFrame och använd sparklyr::collect sedan för att skriva ut de första 10 raderna i DataFrame som standard:

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

Du kan också använda sparklyr::spark_read_table för att göra något liknande. Kör till exempel följande kod i en notebook-cell för att köra frågor mot föregående DataFrame med namnet jsonDF i en DataFrame och använd sparklyr::collect sedan för att skriva ut de första 10 raderna i DataFrame som standard:

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

Lägga till kolumner och beräkningskolumnvärden i en DataFrame

Du kan använda dplyr-funktioner för att lägga till kolumner i DataFrames och för att beräkna kolumners värden.

Kör till exempel följande kod i en notebook-cell för att hämta innehållet i dataramen med namnet jsonDF. Använd dplyr::mutate för att lägga till en kolumn med namnet todayoch fylla den nya kolumnen med den aktuella tidsstämpeln. Skriv sedan innehållet till en ny DataFrame med namnet withDate och använd dplyr::collect för att skriva ut den nya DataFrames första 10 rader som standard.

Kommentar

dplyr::mutate accepterar endast argument som överensstämmer med Hive:s inbyggda funktioner (även kallade UDF:er) och inbyggda aggregeringsfunktioner (även kallade UDAF:er). Allmän information finns i Hive Functions. Information om datumrelaterade funktioner i det här avsnittet finns i Datumfunktioner.

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

dplyr::mutate Använd nu för att lägga till ytterligare två kolumner i innehållet i withDate DataFrame. De nya month kolumnerna och year innehåller den numeriska månaden och året från today kolumnen. Skriv sedan innehållet till en ny DataFrame med namnet withMMyyyyoch använd dplyr::select tillsammans med dplyr::collect för att skriva ut kolumnerna author, titlemonth och year i den nya DataFrame:s första tio rader som standard:

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

dplyr::mutate Använd nu för att lägga till ytterligare två kolumner i innehållet i withMMyyyy DataFrame. De nya formatted_date kolumnerna innehåller yyyy-MM-dd delen från today kolumnen, medan den nya day kolumnen innehåller den numeriska dagen från den nya formatted_date kolumnen. Skriv sedan innehållet till en ny DataFrame med namnet withUnixTimestampoch använd dplyr::select tillsammans med dplyr::collect för att skriva ut kolumnerna title, formatted_dateoch day i den nya DataFrame:s första tio rader som standard:

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

Skapa en tillfällig vy

Du kan skapa namngivna tillfälliga vyer i minnet som baseras på befintliga DataFrames. Kör till exempel följande kod i en notebook-cell som ska användas SparkR::createOrReplaceTempView för att hämta innehållet i föregående DataFrame med namnet jsonTable och göra en tillfällig vy av den med namnet timestampTable. sparklyr::spark_read_table Använd sedan för att läsa den tillfälliga vyns innehåll. Använd sparklyr::collect för att skriva ut de första 10 raderna i den temporära tabellen som standard:

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

Utföra statistisk analys på en DataFrame

Du kan använda sparklyr tillsammans med dplyr för statistiska analyser.

Skapa till exempel en DataFrame att köra statistik på. Det gör du genom att köra följande kod i en notebook-cell som ska användas sparklyr::sdf_copy_to för att skriva innehållet i datauppsättningen iris som är inbyggd i R till en DataFrame med namnet iris. Använd sparklyr::sdf_collect för att skriva ut de första 10 raderna i den temporära tabellen som standard:

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

dplyr::group_by Använd nu för att gruppera rader efter Species kolumnen. Använd dplyr::summarize tillsammans med dplyr::percentile_approx för att beräkna sammanfattningsstatistik med kolumnens 25:e, 50:e, 75:e och 100:e quantiles av Sepal_LengthSpecies. Använd sparklyr::collect en utskrift av resultatet:

Kommentar

dplyr::summarize accepterar endast argument som överensstämmer med Hive:s inbyggda funktioner (även kallade UDF:er) och inbyggda aggregeringsfunktioner (även kallade UDAF:er). Allmän information finns i Hive Functions. Mer information om percentile_approxfinns i Inbyggda aggregerade funktioner (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

Liknande resultat kan till exempel beräknas med hjälp sparklyr::sdf_quantileav :

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