Dela via


Arbeta med DataFrames och tables i R

Viktig

SparkR i Databricks är inaktuell i Databricks Runtime 16.0 och senare. Databricks rekommenderar att du använder sparklyr i stället.

Den här artikeln beskriver hur du använder R-paket som SparkR, sparklyroch dplyr för att arbeta med R data.frames, Spark DataFramesoch minnesintern tables.

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 tables som du skapar med sparklyr. Du kan använda sparklyr::sdf_sql för att fråga tables som du skapar med SparkR. Och dplyr kod översätts alltid till SQL i minnet innan den körs. Se även API-samverkan och SQL Translation.

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 den 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- 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)

Ansluta 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 som anslutningsmetod. 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")

Däremot upprättar en Azure Databricks-notebook redan en SparkSession i klustret för att använda med SparkR, så du behöver inte köra SparkR::sparkR.session innan du kan börja köra 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 column namn och datatyper. Data för det här kodexemplet kommer från en JSON-fil med namnet book.json inifrån GitHub. Gör så här för att get filen och ladda upp den till din arbetsyta:

  1. Gå till den books.json filen 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å Catalog.
  3. Klicka på Skapa Table.
  4. På fliken Ladda upp fil släpper du filen books.json från den lokala datorn till rutan Släpp filer för att ladda upp. Eller select, klicka för att bläddra, och navigera till filen books.json från din lokala dator.

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

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

Läs JSON-data till 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 table representationen av data. I det här exemplet måste du ange att filen book.json innehåller flera rader. Det är valfritt att ange columnsschema här. Annars härleder sparklyr columnsschema 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 skriver head ut de första sex raderna som standard. show och collect skriva 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äs från en table

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 notebookcell för att använda dplyr::group_by och dployr::count för att beräkna get antalet per författare från DataFrame som heter 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 table 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 table 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 table har skapats kan du sedan använda sparklyr::sdf_sql tillsammans med SparkR::showDF för att visa tabledata. Kör till exempel följande kod i en notebook-cell för att hämta table till en DataFrame och använd sedan sparklyr::collect för att som standard skriva ut de första 10 raderna av DataFrame:

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 göra frågor mot den tidigare nämnda DataFrame jsonDF och omvandla den till en ny DataFrame. Använd sedan sparklyr::collect för att som standard skriva ut de första 10 raderna av DataFrame:

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 columns och beräkna columnvalues i en dataram

Du kan använda dplyr-funktioner för att lägga till columns i DataFrames och för att beräkna columnsvalues.

Exempelvis kan du köra följande kod i en notebook-cell för att get innehållet i dataramen med namnet jsonDF. Använd dplyr::mutate om du vill lägga till en column med namnet todayoch fylla den nya column 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.

Note

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

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

Använd nu dplyr::mutate för att lägga till ytterligare två columns i innehållet i withDate DataFrame. Den nya month och yearcolumns innehåller den numeriska månaden och året från todaycolumn. Skriv sedan innehållet till en ny DataFrame med namnet withMMyyyyoch använd dplyr::select tillsammans med dplyr::collect för att skriva ut author, title, month och yearcolumns av den nya DataFrame första tio raderna 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

Använd nu dplyr::mutate för att lägga till ytterligare två columns i innehållet i withMMyyyy DataFrame. Den nya formatted_datecolumns innehåller yyyy-MM-dd-delen från todaycolumn, medan den nya daycolumn innehåller den numeriska dagen i den nya formatted_datecolumn. Skriv sedan innehållet till en ny DataFrame med namnet withUnixTimestampoch använd dplyr::select tillsammans med dplyr::collect för att skriva ut title, formatted_dateoch daycolumns av den nya DataFrames 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 views i minnet som baseras på befintliga DataFrames. Exempelvis kan du köra följande kod i en notebook-cell för att använda SparkR::createOrReplaceTempView till att get innehållet i den föregående DataFrame med namnet jsonTable och skapa en tillfällig vy av den med namnet timestampTable. Använd sedan sparklyr::spark_read_table för att läsa innehållet i den temporära vyn. Använd sparklyr::collect för att skriva ut de första 10 raderna i den tillfälliga table 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 för att använda sparklyr::sdf_copy_to för att skriva innehållet i den iris datauppsättning som är inbyggd i R till en dataram med namnet iris. Använd sparklyr::sdf_collect för att skriva ut de första 10 raderna i den tillfälliga table 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

Använd nu dplyr::group_by för att gruppera rader efter Speciescolumn. Använd dplyr::summarize tillsammans med dplyr::percentile_approx för att beräkna sammanfattningsstatistik vid den 25:e, 50:e, 75:e och 100:e kvartilen för Sepal_Lengthcolumn med avseende på Species. Använd sparklyr::collect och skriv ut resultaten:

Not

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