From 3f2b3ecc9916768ed2544ac1d3dc85661396ad63 Mon Sep 17 00:00:00 2001 From: Beatriz Milz Date: Sun, 28 Apr 2024 07:53:12 +1000 Subject: [PATCH] Built site for gh-pages --- .nojekyll | 2 +- databases.html | 12 ++++++------ datetimes.html | 2 +- iteration.html | 12 ++++++------ search.json | 6 +++--- sitemap.xml | 2 +- webscraping.html | 12 +----------- 7 files changed, 19 insertions(+), 29 deletions(-) diff --git a/.nojekyll b/.nojekyll index d1e379951..85d1edd6c 100644 --- a/.nojekyll +++ b/.nojekyll @@ -1 +1 @@ -9d325e23 \ No newline at end of file +ea56e044 \ No newline at end of file diff --git a/databases.html b/databases.html index 963cbfd40..cb6fe7e79 100644 --- a/databases.html +++ b/databases.html @@ -838,12 +838,12 @@

#> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:] #> destino atraso #> <chr> <dbl> -#> 1 SFO 2.67 -#> 2 GSP 15.9 -#> 3 SJU 2.52 -#> 4 GSO 14.1 -#> 5 STT -3.84 -#> 6 SAN 3.14 +#> 1 CLT 7.36 +#> 2 MDW 12.4 +#> 3 HOU 7.18 +#> 4 SDF 12.7 +#> 5 LAS 0.258 +#> 6 PHX 2.10 #> # ℹ more rows

Se você quiser saber mais em como o NULL funciona, você irá gostar do artigo “Three valued logic” de Markus Winand.

diff --git a/datetimes.html b/datetimes.html index d5ee5af9c..36d04915c 100644 --- a/datetimes.html +++ b/datetimes.html @@ -494,7 +494,7 @@

today()
 #> [1] "2024-04-28"
 now()
-#> [1] "2024-04-28 07:45:59 AEST"
+#> [1] "2024-04-28 07:51:35 AEST"

Otherwise, the following sections describe the four ways you’re likely to create a date/time:

    diff --git a/iteration.html b/iteration.html index 617c16e40..be319abe2 100644 --- a/iteration.html +++ b/iteration.html @@ -1312,12 +1312,12 @@

    #> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:] #> year n #> <dbl> <dbl> -#> 1 2007 142 -#> 2 1967 142 -#> 3 1952 142 -#> 4 1957 142 -#> 5 1972 142 -#> 6 1992 142 +#> 1 1977 142 +#> 2 1987 142 +#> 3 2007 142 +#> 4 1967 142 +#> 5 1952 142 +#> 6 1957 142 #> # ℹ more rows

    diff --git a/search.json b/search.json index 6550ca10d..0ffebf2ab 100644 --- a/search.json +++ b/search.json @@ -1629,7 +1629,7 @@ "href": "datetimes.html#sec-creating-datetimes", "title": "17  Dates and times", "section": "\n17.2 Creating date/times", - "text": "17.2 Creating date/times\nThere are three types of date/time data that refer to an instant in time:\n\nA date. Tibbles print this as <date>.\nA time within a day. Tibbles print this as <time>.\nA date-time is a date plus a time: it uniquely identifies an instant in time (typically to the nearest second). Tibbles print this as <dttm>. Base R calls these POSIXct, but doesn’t exactly trip off the tongue.\n\nIn this chapter we are going to focus on dates and date-times as R doesn’t have a native class for storing times. If you need one, you can use the hms package.\nYou should always use the simplest possible data type that works for your needs. That means if you can use a date instead of a date-time, you should. Date-times are substantially more complicated because of the need to handle time zones, which we’ll come back to at the end of the chapter.\nTo get the current date or date-time you can use today() or now():\n\ntoday()\n#> [1] \"2024-04-28\"\nnow()\n#> [1] \"2024-04-28 07:45:59 AEST\"\n\nOtherwise, the following sections describe the four ways you’re likely to create a date/time:\n\nWhile reading a file with readr.\nFrom a string.\nFrom individual date-time components.\nFrom an existing date/time object.\n\n\n17.2.1 During import\nIf your CSV contains an ISO8601 date or date-time, you don’t need to do anything; readr will automatically recognize it:\n\ncsv <- \"\n date,datetime\n 2022-01-02,2022-01-02 05:12\n\"\nread_csv(csv)\n#> # A tibble: 1 × 2\n#> date datetime \n#> <date> <dttm> \n#> 1 2022-01-02 2022-01-02 05:12:00\n\nIf you haven’t heard of ISO8601 before, it’s an international standard2 for writing dates where the components of a date are organized from biggest to smallest separated by -. For example, in ISO8601 May 3 2022 is 2022-05-03. ISO8601 dates can also include times, where hour, minute, and second are separated by :, and the date and time components are separated by either a T or a space. For example, you could write 4:26pm on May 3 2022 as either 2022-05-03 16:26 or 2022-05-03T16:26.\nFor other date-time formats, you’ll need to use col_types plus col_date() or col_datetime() along with a date-time format. The date-time format used by readr is a standard used across many programming languages, describing a date component with a % followed by a single character. For example, %Y-%m-%d specifies a date that’s a year, -, month (as number) -, day. Table Tabela 17.1 lists all the options.\n\n\nTabela 17.1: All date formats understood by readr\n\n\n\nType\nCode\nMeaning\nExample\n\n\n\nYear\n%Y\n4 digit year\n2021\n\n\n\n%y\n2 digit year\n21\n\n\nMonth\n%m\nNumber\n2\n\n\n\n%b\nAbbreviated name\nFeb\n\n\n\n%B\nFull name\nFebruary\n\n\nDay\n%d\nOne or two digits\n2\n\n\n\n%e\nTwo digits\n02\n\n\nTime\n%H\n24-hour hour\n13\n\n\n\n%I\n12-hour hour\n1\n\n\n\n%p\nAM/PM\npm\n\n\n\n%M\nMinutes\n35\n\n\n\n%S\nSeconds\n45\n\n\n\n%OS\nSeconds with decimal component\n45.35\n\n\n\n%Z\nTime zone name\nAmerica/Chicago\n\n\n\n%z\nOffset from UTC\n+0800\n\n\nOther\n%.\nSkip one non-digit\n:\n\n\n\n%*\nSkip any number of non-digits\n\n\n\n\n\n\n\nAnd this code shows a few options applied to a very ambiguous date:\n\ncsv <- \"\n date\n 01/02/15\n\"\n\nread_csv(csv, col_types = cols(date = col_date(\"%m/%d/%y\")))\n#> # A tibble: 1 × 1\n#> date \n#> <date> \n#> 1 2015-01-02\n\nread_csv(csv, col_types = cols(date = col_date(\"%d/%m/%y\")))\n#> # A tibble: 1 × 1\n#> date \n#> <date> \n#> 1 2015-02-01\n\nread_csv(csv, col_types = cols(date = col_date(\"%y/%m/%d\")))\n#> # A tibble: 1 × 1\n#> date \n#> <date> \n#> 1 2001-02-15\n\nNote that no matter how you specify the date format, it’s always displayed the same way once you get it into R.\nIf you’re using %b or %B and working with non-English dates, you’ll also need to provide a locale(). See the list of built-in languages in date_names_langs(), or create your own with date_names(),\n\n17.2.2 From strings\nThe date-time specification language is powerful, but requires careful analysis of the date format. An alternative approach is to use lubridate’s helpers which attempt to automatically determine the format once you specify the order of the component. To use them, identify the order in which year, month, and day appear in your dates, then arrange “y”, “m”, and “d” in the same order. That gives you the name of the lubridate function that will parse your date. For example:\n\nymd(\"2017-01-31\")\n#> [1] \"2017-01-31\"\nmdy(\"January 31st, 2017\")\n#> [1] \"2017-01-31\"\ndmy(\"31-Jan-2017\")\n#> [1] \"2017-01-31\"\n\nymd() and friends create dates. To create a date-time, add an underscore and one or more of “h”, “m”, and “s” to the name of the parsing function:\n\nymd_hms(\"2017-01-31 20:11:59\")\n#> [1] \"2017-01-31 20:11:59 UTC\"\nmdy_hm(\"01/31/2017 08:01\")\n#> [1] \"2017-01-31 08:01:00 UTC\"\n\nYou can also force the creation of a date-time from a date by supplying a timezone:\n\nymd(\"2017-01-31\", tz = \"UTC\")\n#> [1] \"2017-01-31 UTC\"\n\nHere I use the UTC3 timezone which you might also know as GMT, or Greenwich Mean Time, the time at 0° longitude4 . It doesn’t use daylight saving time, making it a bit easier to compute with .\n\n17.2.3 From individual components\nInstead of a single string, sometimes you’ll have the individual components of the date-time spread across multiple columns. This is what we have in the flights data:\n\nflights |> \n select(year, month, day, hour, minute)\n#> # A tibble: 336,776 × 5\n#> year month day hour minute\n#> <int> <int> <int> <dbl> <dbl>\n#> 1 2013 1 1 5 15\n#> 2 2013 1 1 5 29\n#> 3 2013 1 1 5 40\n#> 4 2013 1 1 5 45\n#> 5 2013 1 1 6 0\n#> 6 2013 1 1 5 58\n#> # ℹ 336,770 more rows\n\nTo create a date/time from this sort of input, use make_date() for dates, or make_datetime() for date-times:\n\nflights |> \n select(year, month, day, hour, minute) |> \n mutate(departure = make_datetime(year, month, day, hour, minute))\n#> # A tibble: 336,776 × 6\n#> year month day hour minute departure \n#> <int> <int> <int> <dbl> <dbl> <dttm> \n#> 1 2013 1 1 5 15 2013-01-01 05:15:00\n#> 2 2013 1 1 5 29 2013-01-01 05:29:00\n#> 3 2013 1 1 5 40 2013-01-01 05:40:00\n#> 4 2013 1 1 5 45 2013-01-01 05:45:00\n#> 5 2013 1 1 6 0 2013-01-01 06:00:00\n#> 6 2013 1 1 5 58 2013-01-01 05:58:00\n#> # ℹ 336,770 more rows\n\nLet’s do the same thing for each of the four time columns in flights. The times are represented in a slightly odd format, so we use modulus arithmetic to pull out the hour and minute components. Once we’ve created the date-time variables, we focus in on the variables we’ll explore in the rest of the chapter.\n\nmake_datetime_100 <- function(year, month, day, time) {\n make_datetime(year, month, day, time %/% 100, time %% 100)\n}\n\nflights_dt <- flights |> \n filter(!is.na(dep_time), !is.na(arr_time)) |> \n mutate(\n dep_time = make_datetime_100(year, month, day, dep_time),\n arr_time = make_datetime_100(year, month, day, arr_time),\n sched_dep_time = make_datetime_100(year, month, day, sched_dep_time),\n sched_arr_time = make_datetime_100(year, month, day, sched_arr_time)\n ) |> \n select(origin, dest, ends_with(\"delay\"), ends_with(\"time\"))\n\nflights_dt\n#> # A tibble: 328,063 × 9\n#> origin dest dep_delay arr_delay dep_time sched_dep_time \n#> <chr> <chr> <dbl> <dbl> <dttm> <dttm> \n#> 1 EWR IAH 2 11 2013-01-01 05:17:00 2013-01-01 05:15:00\n#> 2 LGA IAH 4 20 2013-01-01 05:33:00 2013-01-01 05:29:00\n#> 3 JFK MIA 2 33 2013-01-01 05:42:00 2013-01-01 05:40:00\n#> 4 JFK BQN -1 -18 2013-01-01 05:44:00 2013-01-01 05:45:00\n#> 5 LGA ATL -6 -25 2013-01-01 05:54:00 2013-01-01 06:00:00\n#> 6 EWR ORD -4 12 2013-01-01 05:54:00 2013-01-01 05:58:00\n#> # ℹ 328,057 more rows\n#> # ℹ 3 more variables: arr_time <dttm>, sched_arr_time <dttm>, …\n\nWith this data, we can visualize the distribution of departure times across the year:\n\nflights_dt |> \n ggplot(aes(x = dep_time)) + \n geom_freqpoly(binwidth = 86400) # 86400 seconds = 1 day\n\n\n\n\n\n\n\nOr within a single day:\n\nflights_dt |> \n filter(dep_time < ymd(20130102)) |> \n ggplot(aes(x = dep_time)) + \n geom_freqpoly(binwidth = 600) # 600 s = 10 minutes\n\n\n\n\n\n\n\nNote that when you use date-times in a numeric context (like in a histogram), 1 means 1 second, so a binwidth of 86400 means one day. For dates, 1 means 1 day.\n\n17.2.4 From other types\nYou may want to switch between a date-time and a date. That’s the job of as_datetime() and as_date():\n\nas_datetime(today())\n#> [1] \"2024-04-28 UTC\"\nas_date(now())\n#> [1] \"2024-04-28\"\n\nSometimes you’ll get date/times as numeric offsets from the “Unix Epoch”, 1970-01-01. If the offset is in seconds, use as_datetime(); if it’s in days, use as_date().\n\nas_datetime(60 * 60 * 10)\n#> [1] \"1970-01-01 10:00:00 UTC\"\nas_date(365 * 10 + 2)\n#> [1] \"1980-01-01\"\n\n\n17.2.5 Exercises\n\n\nWhat happens if you parse a string that contains invalid dates?\n\nymd(c(\"2010-10-10\", \"bananas\"))\n\n\nWhat does the tzone argument to today() do? Why is it important?\n\nFor each of the following date-times, show how you’d parse it using a readr column specification and a lubridate function.\n\nd1 <- \"January 1, 2010\"\nd2 <- \"2015-Mar-07\"\nd3 <- \"06-Jun-2017\"\nd4 <- c(\"August 19 (2015)\", \"July 1 (2015)\")\nd5 <- \"12/30/14\" # Dec 30, 2014\nt1 <- \"1705\"\nt2 <- \"11:15:10.12 PM\"", + "text": "17.2 Creating date/times\nThere are three types of date/time data that refer to an instant in time:\n\nA date. Tibbles print this as <date>.\nA time within a day. Tibbles print this as <time>.\nA date-time is a date plus a time: it uniquely identifies an instant in time (typically to the nearest second). Tibbles print this as <dttm>. Base R calls these POSIXct, but doesn’t exactly trip off the tongue.\n\nIn this chapter we are going to focus on dates and date-times as R doesn’t have a native class for storing times. If you need one, you can use the hms package.\nYou should always use the simplest possible data type that works for your needs. That means if you can use a date instead of a date-time, you should. Date-times are substantially more complicated because of the need to handle time zones, which we’ll come back to at the end of the chapter.\nTo get the current date or date-time you can use today() or now():\n\ntoday()\n#> [1] \"2024-04-28\"\nnow()\n#> [1] \"2024-04-28 07:51:35 AEST\"\n\nOtherwise, the following sections describe the four ways you’re likely to create a date/time:\n\nWhile reading a file with readr.\nFrom a string.\nFrom individual date-time components.\nFrom an existing date/time object.\n\n\n17.2.1 During import\nIf your CSV contains an ISO8601 date or date-time, you don’t need to do anything; readr will automatically recognize it:\n\ncsv <- \"\n date,datetime\n 2022-01-02,2022-01-02 05:12\n\"\nread_csv(csv)\n#> # A tibble: 1 × 2\n#> date datetime \n#> <date> <dttm> \n#> 1 2022-01-02 2022-01-02 05:12:00\n\nIf you haven’t heard of ISO8601 before, it’s an international standard2 for writing dates where the components of a date are organized from biggest to smallest separated by -. For example, in ISO8601 May 3 2022 is 2022-05-03. ISO8601 dates can also include times, where hour, minute, and second are separated by :, and the date and time components are separated by either a T or a space. For example, you could write 4:26pm on May 3 2022 as either 2022-05-03 16:26 or 2022-05-03T16:26.\nFor other date-time formats, you’ll need to use col_types plus col_date() or col_datetime() along with a date-time format. The date-time format used by readr is a standard used across many programming languages, describing a date component with a % followed by a single character. For example, %Y-%m-%d specifies a date that’s a year, -, month (as number) -, day. Table Tabela 17.1 lists all the options.\n\n\nTabela 17.1: All date formats understood by readr\n\n\n\nType\nCode\nMeaning\nExample\n\n\n\nYear\n%Y\n4 digit year\n2021\n\n\n\n%y\n2 digit year\n21\n\n\nMonth\n%m\nNumber\n2\n\n\n\n%b\nAbbreviated name\nFeb\n\n\n\n%B\nFull name\nFebruary\n\n\nDay\n%d\nOne or two digits\n2\n\n\n\n%e\nTwo digits\n02\n\n\nTime\n%H\n24-hour hour\n13\n\n\n\n%I\n12-hour hour\n1\n\n\n\n%p\nAM/PM\npm\n\n\n\n%M\nMinutes\n35\n\n\n\n%S\nSeconds\n45\n\n\n\n%OS\nSeconds with decimal component\n45.35\n\n\n\n%Z\nTime zone name\nAmerica/Chicago\n\n\n\n%z\nOffset from UTC\n+0800\n\n\nOther\n%.\nSkip one non-digit\n:\n\n\n\n%*\nSkip any number of non-digits\n\n\n\n\n\n\n\nAnd this code shows a few options applied to a very ambiguous date:\n\ncsv <- \"\n date\n 01/02/15\n\"\n\nread_csv(csv, col_types = cols(date = col_date(\"%m/%d/%y\")))\n#> # A tibble: 1 × 1\n#> date \n#> <date> \n#> 1 2015-01-02\n\nread_csv(csv, col_types = cols(date = col_date(\"%d/%m/%y\")))\n#> # A tibble: 1 × 1\n#> date \n#> <date> \n#> 1 2015-02-01\n\nread_csv(csv, col_types = cols(date = col_date(\"%y/%m/%d\")))\n#> # A tibble: 1 × 1\n#> date \n#> <date> \n#> 1 2001-02-15\n\nNote that no matter how you specify the date format, it’s always displayed the same way once you get it into R.\nIf you’re using %b or %B and working with non-English dates, you’ll also need to provide a locale(). See the list of built-in languages in date_names_langs(), or create your own with date_names(),\n\n17.2.2 From strings\nThe date-time specification language is powerful, but requires careful analysis of the date format. An alternative approach is to use lubridate’s helpers which attempt to automatically determine the format once you specify the order of the component. To use them, identify the order in which year, month, and day appear in your dates, then arrange “y”, “m”, and “d” in the same order. That gives you the name of the lubridate function that will parse your date. For example:\n\nymd(\"2017-01-31\")\n#> [1] \"2017-01-31\"\nmdy(\"January 31st, 2017\")\n#> [1] \"2017-01-31\"\ndmy(\"31-Jan-2017\")\n#> [1] \"2017-01-31\"\n\nymd() and friends create dates. To create a date-time, add an underscore and one or more of “h”, “m”, and “s” to the name of the parsing function:\n\nymd_hms(\"2017-01-31 20:11:59\")\n#> [1] \"2017-01-31 20:11:59 UTC\"\nmdy_hm(\"01/31/2017 08:01\")\n#> [1] \"2017-01-31 08:01:00 UTC\"\n\nYou can also force the creation of a date-time from a date by supplying a timezone:\n\nymd(\"2017-01-31\", tz = \"UTC\")\n#> [1] \"2017-01-31 UTC\"\n\nHere I use the UTC3 timezone which you might also know as GMT, or Greenwich Mean Time, the time at 0° longitude4 . It doesn’t use daylight saving time, making it a bit easier to compute with .\n\n17.2.3 From individual components\nInstead of a single string, sometimes you’ll have the individual components of the date-time spread across multiple columns. This is what we have in the flights data:\n\nflights |> \n select(year, month, day, hour, minute)\n#> # A tibble: 336,776 × 5\n#> year month day hour minute\n#> <int> <int> <int> <dbl> <dbl>\n#> 1 2013 1 1 5 15\n#> 2 2013 1 1 5 29\n#> 3 2013 1 1 5 40\n#> 4 2013 1 1 5 45\n#> 5 2013 1 1 6 0\n#> 6 2013 1 1 5 58\n#> # ℹ 336,770 more rows\n\nTo create a date/time from this sort of input, use make_date() for dates, or make_datetime() for date-times:\n\nflights |> \n select(year, month, day, hour, minute) |> \n mutate(departure = make_datetime(year, month, day, hour, minute))\n#> # A tibble: 336,776 × 6\n#> year month day hour minute departure \n#> <int> <int> <int> <dbl> <dbl> <dttm> \n#> 1 2013 1 1 5 15 2013-01-01 05:15:00\n#> 2 2013 1 1 5 29 2013-01-01 05:29:00\n#> 3 2013 1 1 5 40 2013-01-01 05:40:00\n#> 4 2013 1 1 5 45 2013-01-01 05:45:00\n#> 5 2013 1 1 6 0 2013-01-01 06:00:00\n#> 6 2013 1 1 5 58 2013-01-01 05:58:00\n#> # ℹ 336,770 more rows\n\nLet’s do the same thing for each of the four time columns in flights. The times are represented in a slightly odd format, so we use modulus arithmetic to pull out the hour and minute components. Once we’ve created the date-time variables, we focus in on the variables we’ll explore in the rest of the chapter.\n\nmake_datetime_100 <- function(year, month, day, time) {\n make_datetime(year, month, day, time %/% 100, time %% 100)\n}\n\nflights_dt <- flights |> \n filter(!is.na(dep_time), !is.na(arr_time)) |> \n mutate(\n dep_time = make_datetime_100(year, month, day, dep_time),\n arr_time = make_datetime_100(year, month, day, arr_time),\n sched_dep_time = make_datetime_100(year, month, day, sched_dep_time),\n sched_arr_time = make_datetime_100(year, month, day, sched_arr_time)\n ) |> \n select(origin, dest, ends_with(\"delay\"), ends_with(\"time\"))\n\nflights_dt\n#> # A tibble: 328,063 × 9\n#> origin dest dep_delay arr_delay dep_time sched_dep_time \n#> <chr> <chr> <dbl> <dbl> <dttm> <dttm> \n#> 1 EWR IAH 2 11 2013-01-01 05:17:00 2013-01-01 05:15:00\n#> 2 LGA IAH 4 20 2013-01-01 05:33:00 2013-01-01 05:29:00\n#> 3 JFK MIA 2 33 2013-01-01 05:42:00 2013-01-01 05:40:00\n#> 4 JFK BQN -1 -18 2013-01-01 05:44:00 2013-01-01 05:45:00\n#> 5 LGA ATL -6 -25 2013-01-01 05:54:00 2013-01-01 06:00:00\n#> 6 EWR ORD -4 12 2013-01-01 05:54:00 2013-01-01 05:58:00\n#> # ℹ 328,057 more rows\n#> # ℹ 3 more variables: arr_time <dttm>, sched_arr_time <dttm>, …\n\nWith this data, we can visualize the distribution of departure times across the year:\n\nflights_dt |> \n ggplot(aes(x = dep_time)) + \n geom_freqpoly(binwidth = 86400) # 86400 seconds = 1 day\n\n\n\n\n\n\n\nOr within a single day:\n\nflights_dt |> \n filter(dep_time < ymd(20130102)) |> \n ggplot(aes(x = dep_time)) + \n geom_freqpoly(binwidth = 600) # 600 s = 10 minutes\n\n\n\n\n\n\n\nNote that when you use date-times in a numeric context (like in a histogram), 1 means 1 second, so a binwidth of 86400 means one day. For dates, 1 means 1 day.\n\n17.2.4 From other types\nYou may want to switch between a date-time and a date. That’s the job of as_datetime() and as_date():\n\nas_datetime(today())\n#> [1] \"2024-04-28 UTC\"\nas_date(now())\n#> [1] \"2024-04-28\"\n\nSometimes you’ll get date/times as numeric offsets from the “Unix Epoch”, 1970-01-01. If the offset is in seconds, use as_datetime(); if it’s in days, use as_date().\n\nas_datetime(60 * 60 * 10)\n#> [1] \"1970-01-01 10:00:00 UTC\"\nas_date(365 * 10 + 2)\n#> [1] \"1980-01-01\"\n\n\n17.2.5 Exercises\n\n\nWhat happens if you parse a string that contains invalid dates?\n\nymd(c(\"2010-10-10\", \"bananas\"))\n\n\nWhat does the tzone argument to today() do? Why is it important?\n\nFor each of the following date-times, show how you’d parse it using a readr column specification and a lubridate function.\n\nd1 <- \"January 1, 2010\"\nd2 <- \"2015-Mar-07\"\nd3 <- \"06-Jun-2017\"\nd4 <- c(\"August 19 (2015)\", \"July 1 (2015)\")\nd5 <- \"12/30/14\" # Dec 30, 2014\nt1 <- \"1705\"\nt2 <- \"11:15:10.12 PM\"", "crumbs": [ "✅ Transformar", "17  Dates and times" @@ -1969,7 +1969,7 @@ "href": "databases.html#sql", "title": "21  ✅ Bancos de dados", "section": "\n21.5 SQL", - "text": "21.5 SQL\nO resto do capítulo irá te ensinar um pouco de SQL pelas lentes do dbplyr. É uma introdução não tradicional ao SQL, mas esperamos que te leve rapidamente a um conhecimento básico. Felizmente, se você conhece dplyr você está em um bom lugar para rapidamente aprender SQL, pois muitos conceitos são iguais.\nNós iremos explorar o relacionamento entre dplyr e SQL usando alguns velhos amigos do pacote dados: voos e avioes. Estes conjuntos de dados são fáceis para usar no aprendizado sobre bancos de dados, e podemos copiá-las 4:\n\n# Copiando as tabelas para o banco de dados\ndbWriteTable(con, name = \"voos\", value = voos)\ndbWriteTable(con, name = \"avioes\", value = avioes)\n\n# Lendo as tabelas do banco de dados\nvoos <- tbl(con, \"voos\")\navioes <- tbl(con, \"avioes\")\n\n\n21.5.1 O básico do SQL\nOs componentes de nível mais alto do SQL são chamados declarações (statements). Declarações comuns incluem CREATE para definir novas tableas, INSERT para adicionar dados e SELECT para retornar dados. Iremos focar em declarações SELECT, também chamadas de consultas (queries), pois são quase que exclusivamente o que você precisa para atuar em ciência de dados.\nUm consulta é formada por cláusulas (clauses). Existem cinco cláusulas importantes: SELECT, FROM, WHERE, ORDER BY e GROUP BY. Toda consulta precisa ter cláusulas SELECT5 e FROM6 e a consulta mais simples é SELECT * FROM tabela, que seleciona todas colunas de determinada tabela . Isto é o que dbplyr gera de uma tabela sem mudanças :\n\nvoos |> show_query()\n#> <SQL>\n#> SELECT *\n#> FROM voos\navioes |> show_query()\n#> <SQL>\n#> SELECT *\n#> FROM avioes\n\nWHERE e ORDER BY controlam quais linhas serão incluídas e como estarão ordenadas:\n\nvoos |> \n filter(destino == \"IAH\") |> \n arrange(atraso_saida) |>\n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (destino = 'IAH')\n#> ORDER BY atraso_saida\n\nGROUP BY converte a consulta em uma sumarização, fazendo com que aconteça uma agregação:\n\nvoos |> \n group_by(destino) |> \n summarize(atraso_saida = mean(atraso_saida, na.rm = TRUE)) |> \n show_query()\n#> <SQL>\n#> SELECT destino, AVG(atraso_saida) AS atraso_saida\n#> FROM voos\n#> GROUP BY destino\n\nExistem duas principais diferenças entre verbos dplyr e cláusulas SELECT:\n\nNo SQL, a maiúscula e minúscula não fazem diferença: você pode escrever select, SELECT ou até SeLeCt. Neste livro ficaremos com a convenção comum de escrever as palavras-chaves SQL usando letras maiúsculas para distinguir de nomes de tabelas ou variáveis.\nNo SQL, a ordem importa: você sempre deve escrever as declarações em ordem SELECT, FROM, WHERE, GROUP BY, ORDER BY. É um pouco confuso, pois esta ordem não é a mesma de como as declarações são realmente avaliadas com FROM em primeiro, depois WHERE, GROUP BY, SELECT e ORDER BY.\n\nAs seções seguintes exploram com mais detalhes cada cláusula.\n\n\n\n\n\n\nObserve que apesar do SQL ser um padrão, ele é extramamente complexo e nenhum banco de dados o segue exatamente. Enquanto os componentes principais que iremos focar neste livro são muito similares entre os SGBDs, há muitas pequenas variações. Felizmente, dbplyr é desenhado para gerenciar este problema e gerar diferentes traduções para diferentes bancos de dados. Não é perfeito, mas está melhorando continuamente e se você encontrar um problema, pode abrir um caso (issue) no GitHub para nos ajudar a melhorar.\n\n\n\n\n21.5.2 SELECT\nA cláusula SELECT é o motor das consultas e faz o mesmo trabalho que select(), mutate(), rename(), relocate() e, como você aprenderá na próxima seção, summarize().\nselect(), rename() e relocate() tem uma tradução muito direta para o SELECT já que apenas afetam onde uma coluna aparece (e se aparece) assim como seu nome:\n\navioes |> \n select(codigo_cauda, tipo, fabricante, modelo, ano) |> \n show_query()\n#> <SQL>\n#> SELECT codigo_cauda, tipo, fabricante, modelo, ano\n#> FROM avioes\n\navioes |> \n select(codigo_cauda, tipo, fabricante, modelo, ano) |> \n rename(ano_construcao = ano) |> \n show_query()\n#> <SQL>\n#> SELECT codigo_cauda, tipo, fabricante, modelo, ano AS ano_construcao\n#> FROM avioes\n\navioes |> \n select(codigo_cauda, tipo, fabricante, modelo, ano) |> \n relocate(fabricante, modelo, .before = tipo) |> \n show_query()\n#> <SQL>\n#> SELECT codigo_cauda, fabricante, modelo, tipo, ano\n#> FROM avioes\n\nEste exemplo também mostra como SQL renomeia. Na terminologia SQL, renomear é chamado de aliasing e é feito com AS. Note que diferente de mutate(), o nome antigo vai ao lado esquerdo e o novo nome ao lado direito.\n\n\n\n\n\n\nNos exemplos acima, se tivéssemos os nomes de \"ano\" e \"tipo\", elas apareceriam entre aspas duplas. Isto é devido a year e type serem palavras reservadas (reserved words) no duckdb, então dbplyr coloca aspas para evitar potencial confusão entre nome de colunas/tabelas e os operadores SQL.\nQuando estiver trabalhando com outros bancos de dados é provavel que você veja todas as variáveis com aspas, pois apenas alguns poucos pacotes clientes, como o duckdb, sabem quais são todas as palavras reservadas, então eles colocam aspas em todas para evitar problemas.\nSELECT \"codigo_cauda\", \"tipo\", \"fabricante\", \"modelo\", \"ano\"\nFROM \"avioes\"\nAlguns outros bancos de dados usam a crase ao invés de aspas duplas:\nSELECT `codigo_cauda`, `tipo`, `fabricante`, `modelo`, `ano`\nFROM `avioes`\n\n\n\nA tradução para mutate() é da mesma forma bastante direta: cada variável se torna uma nova expressão no SELECT:\n\nvoos |> \n mutate(\n velocidade = distancia / (tempo_voo / 60)\n ) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*, distancia / (tempo_voo / 60.0) AS velocidade\n#> FROM voos\n\nRetornaremos para a tradução de componentes individuais (como /) na Seção 21.6.\n\n21.5.3 FROM\nA cláusula FROM define a fonte de dados. Será um pouco desinteressante por um período, pois estamos usando apenas uma única tabela. Você verá exemplos mais complexos quando chegarmos nas funções de união (join).\n\n21.5.4 GROUP BY\ngroup_by() é traduzido como a clásula GROUP BY7 e summarize() é traduzido como a cláusula SELECT:\n\ndiamantes_bd |> \n group_by(corte) |> \n summarize(\n n = n(),\n avg_price = mean(preco, na.rm = TRUE)\n ) |> \n show_query()\n#> <SQL>\n#> SELECT corte, COUNT(*) AS n, AVG(preco) AS avg_price\n#> FROM diamante\n#> GROUP BY corte\n\nRetornaremos em o que acontece com a tradução de n() e mean() na Seção 21.6.\n\n21.5.5 WHERE\nfilter() é traduzido como a cláusula WHERE:\n\nvoos |> \n filter(destino == \"IAH\" | destino == \"HOU\") |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (destino = 'IAH' OR destino = 'HOU')\n\nvoos |> \n filter(atraso_chegada > 0 & atraso_chegada < 20) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (atraso_chegada > 0.0 AND atraso_chegada < 20.0)\n\nExistem alguns detalhes importantes a serem observados aqui:\n\n\n| se torna OR e & se torna AND.\nSQL usa = para comparação, e não ==. SQL não possui atribuição (assignment), portanto não há potencial para confusão aqui.\nSQL usa somente '' para strings, não usa \"\". No SQL, \"\" é usado para identificar variáveis, como a `` do R.\n\nOutro operator SQL útil é o IN, o qual se parece muito com o %in%do R:\n\nvoos |> \n filter(destino %in% c(\"IAH\", \"HOU\")) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (destino IN ('IAH', 'HOU'))\n\nSQL usa NULL ao invés de NA. NULL se comporta de forma similar ao NA. A principal diferença é que enquanto são considerados nas comparações e aritmética, eles são silenciosamente ignorados quando sumarizados. dbplyr irá te lembrar disto a primeira vez que você encontrar:\n\nvoos |> \n group_by(destino) |> \n summarize(atraso = mean(atraso_chegada))\n#> Warning: Missing values are always removed in SQL aggregation functions.\n#> Use `na.rm = TRUE` to silence this warning\n#> This warning is displayed once every 8 hours.\n#> # Source: SQL [?? x 2]\n#> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:]\n#> destino atraso\n#> <chr> <dbl>\n#> 1 SFO 2.67\n#> 2 GSP 15.9 \n#> 3 SJU 2.52\n#> 4 GSO 14.1 \n#> 5 STT -3.84\n#> 6 SAN 3.14\n#> # ℹ more rows\n\nSe você quiser saber mais em como o NULL funciona, você irá gostar do artigo “Three valued logic” de Markus Winand.\nEm geral, você pode trabalhar com NULL usando as funções que você usaria para NA no R:\n\nvoos |> \n filter(!is.na(atraso_saida)) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (NOT((atraso_saida IS NULL)))\n\nEsta consulta SQL ilustra uma das desvatagens do dbplyr: apesar do SQL estar correto, ela não é tão simples quanto se estivesse sido escrita à mão. Neste caso, você poderia eliminar os parênteses e usar um operador especial que é mais simples de se ler:\nWHERE \"atraso_saida\" IS NOT NULL\nNote que se você usar filter() em uma variável que você criou usando um summarize, dbplyr irá gerar uma cláusula HAVING, ao invés de uma cláusula WHERE. Esta é uma das indiosincrasias do SQL: WHERE é avaliado antes do SELECT e GROUP BY, então o SQL precisa de uma outra cláusula que seja avaliada depois.\n\ndiamantes_bd |> \n group_by(corte) |> \n summarize(n = n()) |> \n filter(n > 100) |> \n show_query()\n#> <SQL>\n#> SELECT corte, COUNT(*) AS n\n#> FROM diamante\n#> GROUP BY corte\n#> HAVING (COUNT(*) > 100.0)\n\n\n21.5.6 ORDER BY\nOrdenar linhas involve uma tradução direta de arrange() para a cláusula ORDER BY:\n\nvoos |> \n arrange(ano, mes, dia, desc(atraso_saida)) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> ORDER BY ano, mes, dia, atraso_saida DESC\n\nNote como desc() é traduzido para DESC: esta é uma das muitas funções dplyr cujo o nome foi diretamente inspirado pelo SQL.\n\n21.5.7 Subconsultas\nAlgumas vezes não é possível traduzir um pipeline dplyr em uma única declaração SELECT e você precisa usar uma subconsulta. Uma subconsulta é apenas uma consulta usada como uma fonte de dados na cláusula FROM ao invés de uma tabela normal.\nO dbplyr tipicamente usa subconsultas para solucionar paleativamente limitações do SQL. Por exemplo, expressões na cláusula SELECT não podem referenciar colunas que acabaram de ser criadas. Isto significa que o seguinte pipeline (muito simples) precisa acontecer em duas etapas: a primeira consulta (interna) computa ano1 e então a segunda consulta (externa) pode computar ano2.\n\nvoos |> \n mutate(\n ano1 = ano + 1,\n ano2 = ano1 + 1\n ) |> \n show_query()\n#> <SQL>\n#> SELECT q01.*, ano1 + 1.0 AS ano2\n#> FROM (\n#> SELECT voos.*, ano + 1.0 AS ano1\n#> FROM voos\n#> ) q01\n\nVocê também verá isso se tentar filtrar com filter() a variável que você criou recentemente. Lembre-se que, apesar de WHERE ser escrita depois de SELECT, ela é avaliada antes, por isso você precisa de uma subconsulta neste simples exemplo:\n\nvoos |> \n mutate(ano1 = ano + 1) |> \n filter(ano1 == 2014) |> \n show_query()\n#> <SQL>\n#> SELECT q01.*\n#> FROM (\n#> SELECT voos.*, ano + 1.0 AS ano1\n#> FROM voos\n#> ) q01\n#> WHERE (ano1 = 2014.0)\n\nAlgumas vezes, dbplyr irá criar uma subconsulta mesmo onde não é necessário, pois não sabe ainda como otimizar tal tradução. Conforme dbplyr melhora, estes casos vão ficando mais raros, mas provavelmente nunca desaparecerão por completo.\n\n21.5.8 Uniões (Joins)\nSe você está familiarizado com uniões (joins) com dplyr, as uniões do SQL são bem parecidas. Aqui está um exemplo simples:\n\nvoos |> \n left_join(avioes |> rename(ano_construcao = ano), by = \"codigo_cauda\") |> \n show_query()\n#> <SQL>\n#> SELECT\n#> voos.*,\n#> avioes.ano AS ano_construcao,\n#> tipo,\n#> fabricante,\n#> modelo,\n#> motores,\n#> assentos,\n#> velocidade,\n#> tipo_motor\n#> FROM voos\n#> LEFT JOIN avioes\n#> ON (voos.codigo_cauda = avioes.codigo_cauda)\n\nA principal coisa a se notar aqui é a sintaxe: as uniões SQL usam sub-cláusulas da cláusula FROM para associar tabelas adicionais, usando ON para definir como as tabelas estão relacionadas.\nOs nomes das funções dplyr são tão parecidas com as do SQL que você pode facilmente adivinhar o SQL equivalente para inner_join(), right_join() e full_join():\nSELECT voos.*, \"tipo\", fabricante, modelo, motores, assentos, velocidade\nFROM voos\nINNER JOIN avioes ON (voos.codigo_cauda = avioes.codigo_cauda)\n\nSELECT voos.*, \"tipo\", fabricante, modelo, motores, assentos, velocidade\nFROM voos\nRIGHT JOIN avioes ON (voos.codigo_cauda = avioes.codigo_cauda)\n\nSELECT voos.*, \"tipo\", fabricante, modelo, motores, assentos, velocidade\nFROM voos\nFULL JOIN avioes ON (voos.codigo_cauda = avioes.codigo_cauda)\nÉ muito provavel que você precise de muitas uniões (joins) quando trabalhar com dados de um banco de dados. Isto porque tabelas são frequentemente armazenadas de uma forma altamente normalizada, onde cada “fato” é armazenado em um único local e para manter um conjunto de dados completo para análise, você precisa navegar por uma rede complexa de tabelas conectadas por chaves primárias (primary key) e chaves estrangeiras (foreign key). Se você encontrar este cenário, o pacote dm, de Tobias Schieferdecker, Kirill Müller e Darko Bergant é um salva-vidas. Ele pode automaticamente determinar as conexões entre as tabelas usando restrições (constraints) que as pessoas que adminstram bancos de dados (DBAs) geralmente fornecem, gera visualizações para que você entenda o que está acontecendo e gera as uniões (joins) que você precisa para conectar uma tabela à outra.\n\n21.5.9 Outros verbos\nO dbplyr também traduz outros verbos como distinct(), slice_*(), intersect(), e uma seleção crescente de funções do tidyr como pivot_longer() e pivot_wider(). O jeito mais fácil de ver a lista completa do que está disponível no momento é visitando o website dbplyr: https://dbplyr.tidyverse.org/reference/.\n\n21.5.10 Exercícios\n\nEm que se traduz a distinct()? E a head()?\n\nExplique o que cada um desses comandos SQL fazem e tente recriá-los usando dbplyr.\nSELECT * \nFROM voos\nWHERE atraso_saida < atraso_chegada\n\nSELECT *, distancia / (tempo_voo / 60) AS velocidade\nFROM voos", + "text": "21.5 SQL\nO resto do capítulo irá te ensinar um pouco de SQL pelas lentes do dbplyr. É uma introdução não tradicional ao SQL, mas esperamos que te leve rapidamente a um conhecimento básico. Felizmente, se você conhece dplyr você está em um bom lugar para rapidamente aprender SQL, pois muitos conceitos são iguais.\nNós iremos explorar o relacionamento entre dplyr e SQL usando alguns velhos amigos do pacote dados: voos e avioes. Estes conjuntos de dados são fáceis para usar no aprendizado sobre bancos de dados, e podemos copiá-las 4:\n\n# Copiando as tabelas para o banco de dados\ndbWriteTable(con, name = \"voos\", value = voos)\ndbWriteTable(con, name = \"avioes\", value = avioes)\n\n# Lendo as tabelas do banco de dados\nvoos <- tbl(con, \"voos\")\navioes <- tbl(con, \"avioes\")\n\n\n21.5.1 O básico do SQL\nOs componentes de nível mais alto do SQL são chamados declarações (statements). Declarações comuns incluem CREATE para definir novas tableas, INSERT para adicionar dados e SELECT para retornar dados. Iremos focar em declarações SELECT, também chamadas de consultas (queries), pois são quase que exclusivamente o que você precisa para atuar em ciência de dados.\nUm consulta é formada por cláusulas (clauses). Existem cinco cláusulas importantes: SELECT, FROM, WHERE, ORDER BY e GROUP BY. Toda consulta precisa ter cláusulas SELECT5 e FROM6 e a consulta mais simples é SELECT * FROM tabela, que seleciona todas colunas de determinada tabela . Isto é o que dbplyr gera de uma tabela sem mudanças :\n\nvoos |> show_query()\n#> <SQL>\n#> SELECT *\n#> FROM voos\navioes |> show_query()\n#> <SQL>\n#> SELECT *\n#> FROM avioes\n\nWHERE e ORDER BY controlam quais linhas serão incluídas e como estarão ordenadas:\n\nvoos |> \n filter(destino == \"IAH\") |> \n arrange(atraso_saida) |>\n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (destino = 'IAH')\n#> ORDER BY atraso_saida\n\nGROUP BY converte a consulta em uma sumarização, fazendo com que aconteça uma agregação:\n\nvoos |> \n group_by(destino) |> \n summarize(atraso_saida = mean(atraso_saida, na.rm = TRUE)) |> \n show_query()\n#> <SQL>\n#> SELECT destino, AVG(atraso_saida) AS atraso_saida\n#> FROM voos\n#> GROUP BY destino\n\nExistem duas principais diferenças entre verbos dplyr e cláusulas SELECT:\n\nNo SQL, a maiúscula e minúscula não fazem diferença: você pode escrever select, SELECT ou até SeLeCt. Neste livro ficaremos com a convenção comum de escrever as palavras-chaves SQL usando letras maiúsculas para distinguir de nomes de tabelas ou variáveis.\nNo SQL, a ordem importa: você sempre deve escrever as declarações em ordem SELECT, FROM, WHERE, GROUP BY, ORDER BY. É um pouco confuso, pois esta ordem não é a mesma de como as declarações são realmente avaliadas com FROM em primeiro, depois WHERE, GROUP BY, SELECT e ORDER BY.\n\nAs seções seguintes exploram com mais detalhes cada cláusula.\n\n\n\n\n\n\nObserve que apesar do SQL ser um padrão, ele é extramamente complexo e nenhum banco de dados o segue exatamente. Enquanto os componentes principais que iremos focar neste livro são muito similares entre os SGBDs, há muitas pequenas variações. Felizmente, dbplyr é desenhado para gerenciar este problema e gerar diferentes traduções para diferentes bancos de dados. Não é perfeito, mas está melhorando continuamente e se você encontrar um problema, pode abrir um caso (issue) no GitHub para nos ajudar a melhorar.\n\n\n\n\n21.5.2 SELECT\nA cláusula SELECT é o motor das consultas e faz o mesmo trabalho que select(), mutate(), rename(), relocate() e, como você aprenderá na próxima seção, summarize().\nselect(), rename() e relocate() tem uma tradução muito direta para o SELECT já que apenas afetam onde uma coluna aparece (e se aparece) assim como seu nome:\n\navioes |> \n select(codigo_cauda, tipo, fabricante, modelo, ano) |> \n show_query()\n#> <SQL>\n#> SELECT codigo_cauda, tipo, fabricante, modelo, ano\n#> FROM avioes\n\navioes |> \n select(codigo_cauda, tipo, fabricante, modelo, ano) |> \n rename(ano_construcao = ano) |> \n show_query()\n#> <SQL>\n#> SELECT codigo_cauda, tipo, fabricante, modelo, ano AS ano_construcao\n#> FROM avioes\n\navioes |> \n select(codigo_cauda, tipo, fabricante, modelo, ano) |> \n relocate(fabricante, modelo, .before = tipo) |> \n show_query()\n#> <SQL>\n#> SELECT codigo_cauda, fabricante, modelo, tipo, ano\n#> FROM avioes\n\nEste exemplo também mostra como SQL renomeia. Na terminologia SQL, renomear é chamado de aliasing e é feito com AS. Note que diferente de mutate(), o nome antigo vai ao lado esquerdo e o novo nome ao lado direito.\n\n\n\n\n\n\nNos exemplos acima, se tivéssemos os nomes de \"ano\" e \"tipo\", elas apareceriam entre aspas duplas. Isto é devido a year e type serem palavras reservadas (reserved words) no duckdb, então dbplyr coloca aspas para evitar potencial confusão entre nome de colunas/tabelas e os operadores SQL.\nQuando estiver trabalhando com outros bancos de dados é provavel que você veja todas as variáveis com aspas, pois apenas alguns poucos pacotes clientes, como o duckdb, sabem quais são todas as palavras reservadas, então eles colocam aspas em todas para evitar problemas.\nSELECT \"codigo_cauda\", \"tipo\", \"fabricante\", \"modelo\", \"ano\"\nFROM \"avioes\"\nAlguns outros bancos de dados usam a crase ao invés de aspas duplas:\nSELECT `codigo_cauda`, `tipo`, `fabricante`, `modelo`, `ano`\nFROM `avioes`\n\n\n\nA tradução para mutate() é da mesma forma bastante direta: cada variável se torna uma nova expressão no SELECT:\n\nvoos |> \n mutate(\n velocidade = distancia / (tempo_voo / 60)\n ) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*, distancia / (tempo_voo / 60.0) AS velocidade\n#> FROM voos\n\nRetornaremos para a tradução de componentes individuais (como /) na Seção 21.6.\n\n21.5.3 FROM\nA cláusula FROM define a fonte de dados. Será um pouco desinteressante por um período, pois estamos usando apenas uma única tabela. Você verá exemplos mais complexos quando chegarmos nas funções de união (join).\n\n21.5.4 GROUP BY\ngroup_by() é traduzido como a clásula GROUP BY7 e summarize() é traduzido como a cláusula SELECT:\n\ndiamantes_bd |> \n group_by(corte) |> \n summarize(\n n = n(),\n avg_price = mean(preco, na.rm = TRUE)\n ) |> \n show_query()\n#> <SQL>\n#> SELECT corte, COUNT(*) AS n, AVG(preco) AS avg_price\n#> FROM diamante\n#> GROUP BY corte\n\nRetornaremos em o que acontece com a tradução de n() e mean() na Seção 21.6.\n\n21.5.5 WHERE\nfilter() é traduzido como a cláusula WHERE:\n\nvoos |> \n filter(destino == \"IAH\" | destino == \"HOU\") |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (destino = 'IAH' OR destino = 'HOU')\n\nvoos |> \n filter(atraso_chegada > 0 & atraso_chegada < 20) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (atraso_chegada > 0.0 AND atraso_chegada < 20.0)\n\nExistem alguns detalhes importantes a serem observados aqui:\n\n\n| se torna OR e & se torna AND.\nSQL usa = para comparação, e não ==. SQL não possui atribuição (assignment), portanto não há potencial para confusão aqui.\nSQL usa somente '' para strings, não usa \"\". No SQL, \"\" é usado para identificar variáveis, como a `` do R.\n\nOutro operator SQL útil é o IN, o qual se parece muito com o %in%do R:\n\nvoos |> \n filter(destino %in% c(\"IAH\", \"HOU\")) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (destino IN ('IAH', 'HOU'))\n\nSQL usa NULL ao invés de NA. NULL se comporta de forma similar ao NA. A principal diferença é que enquanto são considerados nas comparações e aritmética, eles são silenciosamente ignorados quando sumarizados. dbplyr irá te lembrar disto a primeira vez que você encontrar:\n\nvoos |> \n group_by(destino) |> \n summarize(atraso = mean(atraso_chegada))\n#> Warning: Missing values are always removed in SQL aggregation functions.\n#> Use `na.rm = TRUE` to silence this warning\n#> This warning is displayed once every 8 hours.\n#> # Source: SQL [?? x 2]\n#> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:]\n#> destino atraso\n#> <chr> <dbl>\n#> 1 CLT 7.36 \n#> 2 MDW 12.4 \n#> 3 HOU 7.18 \n#> 4 SDF 12.7 \n#> 5 LAS 0.258\n#> 6 PHX 2.10 \n#> # ℹ more rows\n\nSe você quiser saber mais em como o NULL funciona, você irá gostar do artigo “Three valued logic” de Markus Winand.\nEm geral, você pode trabalhar com NULL usando as funções que você usaria para NA no R:\n\nvoos |> \n filter(!is.na(atraso_saida)) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> WHERE (NOT((atraso_saida IS NULL)))\n\nEsta consulta SQL ilustra uma das desvatagens do dbplyr: apesar do SQL estar correto, ela não é tão simples quanto se estivesse sido escrita à mão. Neste caso, você poderia eliminar os parênteses e usar um operador especial que é mais simples de se ler:\nWHERE \"atraso_saida\" IS NOT NULL\nNote que se você usar filter() em uma variável que você criou usando um summarize, dbplyr irá gerar uma cláusula HAVING, ao invés de uma cláusula WHERE. Esta é uma das indiosincrasias do SQL: WHERE é avaliado antes do SELECT e GROUP BY, então o SQL precisa de uma outra cláusula que seja avaliada depois.\n\ndiamantes_bd |> \n group_by(corte) |> \n summarize(n = n()) |> \n filter(n > 100) |> \n show_query()\n#> <SQL>\n#> SELECT corte, COUNT(*) AS n\n#> FROM diamante\n#> GROUP BY corte\n#> HAVING (COUNT(*) > 100.0)\n\n\n21.5.6 ORDER BY\nOrdenar linhas involve uma tradução direta de arrange() para a cláusula ORDER BY:\n\nvoos |> \n arrange(ano, mes, dia, desc(atraso_saida)) |> \n show_query()\n#> <SQL>\n#> SELECT voos.*\n#> FROM voos\n#> ORDER BY ano, mes, dia, atraso_saida DESC\n\nNote como desc() é traduzido para DESC: esta é uma das muitas funções dplyr cujo o nome foi diretamente inspirado pelo SQL.\n\n21.5.7 Subconsultas\nAlgumas vezes não é possível traduzir um pipeline dplyr em uma única declaração SELECT e você precisa usar uma subconsulta. Uma subconsulta é apenas uma consulta usada como uma fonte de dados na cláusula FROM ao invés de uma tabela normal.\nO dbplyr tipicamente usa subconsultas para solucionar paleativamente limitações do SQL. Por exemplo, expressões na cláusula SELECT não podem referenciar colunas que acabaram de ser criadas. Isto significa que o seguinte pipeline (muito simples) precisa acontecer em duas etapas: a primeira consulta (interna) computa ano1 e então a segunda consulta (externa) pode computar ano2.\n\nvoos |> \n mutate(\n ano1 = ano + 1,\n ano2 = ano1 + 1\n ) |> \n show_query()\n#> <SQL>\n#> SELECT q01.*, ano1 + 1.0 AS ano2\n#> FROM (\n#> SELECT voos.*, ano + 1.0 AS ano1\n#> FROM voos\n#> ) q01\n\nVocê também verá isso se tentar filtrar com filter() a variável que você criou recentemente. Lembre-se que, apesar de WHERE ser escrita depois de SELECT, ela é avaliada antes, por isso você precisa de uma subconsulta neste simples exemplo:\n\nvoos |> \n mutate(ano1 = ano + 1) |> \n filter(ano1 == 2014) |> \n show_query()\n#> <SQL>\n#> SELECT q01.*\n#> FROM (\n#> SELECT voos.*, ano + 1.0 AS ano1\n#> FROM voos\n#> ) q01\n#> WHERE (ano1 = 2014.0)\n\nAlgumas vezes, dbplyr irá criar uma subconsulta mesmo onde não é necessário, pois não sabe ainda como otimizar tal tradução. Conforme dbplyr melhora, estes casos vão ficando mais raros, mas provavelmente nunca desaparecerão por completo.\n\n21.5.8 Uniões (Joins)\nSe você está familiarizado com uniões (joins) com dplyr, as uniões do SQL são bem parecidas. Aqui está um exemplo simples:\n\nvoos |> \n left_join(avioes |> rename(ano_construcao = ano), by = \"codigo_cauda\") |> \n show_query()\n#> <SQL>\n#> SELECT\n#> voos.*,\n#> avioes.ano AS ano_construcao,\n#> tipo,\n#> fabricante,\n#> modelo,\n#> motores,\n#> assentos,\n#> velocidade,\n#> tipo_motor\n#> FROM voos\n#> LEFT JOIN avioes\n#> ON (voos.codigo_cauda = avioes.codigo_cauda)\n\nA principal coisa a se notar aqui é a sintaxe: as uniões SQL usam sub-cláusulas da cláusula FROM para associar tabelas adicionais, usando ON para definir como as tabelas estão relacionadas.\nOs nomes das funções dplyr são tão parecidas com as do SQL que você pode facilmente adivinhar o SQL equivalente para inner_join(), right_join() e full_join():\nSELECT voos.*, \"tipo\", fabricante, modelo, motores, assentos, velocidade\nFROM voos\nINNER JOIN avioes ON (voos.codigo_cauda = avioes.codigo_cauda)\n\nSELECT voos.*, \"tipo\", fabricante, modelo, motores, assentos, velocidade\nFROM voos\nRIGHT JOIN avioes ON (voos.codigo_cauda = avioes.codigo_cauda)\n\nSELECT voos.*, \"tipo\", fabricante, modelo, motores, assentos, velocidade\nFROM voos\nFULL JOIN avioes ON (voos.codigo_cauda = avioes.codigo_cauda)\nÉ muito provavel que você precise de muitas uniões (joins) quando trabalhar com dados de um banco de dados. Isto porque tabelas são frequentemente armazenadas de uma forma altamente normalizada, onde cada “fato” é armazenado em um único local e para manter um conjunto de dados completo para análise, você precisa navegar por uma rede complexa de tabelas conectadas por chaves primárias (primary key) e chaves estrangeiras (foreign key). Se você encontrar este cenário, o pacote dm, de Tobias Schieferdecker, Kirill Müller e Darko Bergant é um salva-vidas. Ele pode automaticamente determinar as conexões entre as tabelas usando restrições (constraints) que as pessoas que adminstram bancos de dados (DBAs) geralmente fornecem, gera visualizações para que você entenda o que está acontecendo e gera as uniões (joins) que você precisa para conectar uma tabela à outra.\n\n21.5.9 Outros verbos\nO dbplyr também traduz outros verbos como distinct(), slice_*(), intersect(), e uma seleção crescente de funções do tidyr como pivot_longer() e pivot_wider(). O jeito mais fácil de ver a lista completa do que está disponível no momento é visitando o website dbplyr: https://dbplyr.tidyverse.org/reference/.\n\n21.5.10 Exercícios\n\nEm que se traduz a distinct()? E a head()?\n\nExplique o que cada um desses comandos SQL fazem e tente recriá-los usando dbplyr.\nSELECT * \nFROM voos\nWHERE atraso_saida < atraso_chegada\n\nSELECT *, distancia / (tempo_voo / 60) AS velocidade\nFROM voos", "crumbs": [ "✅ Importar", "21  ✅ Bancos de dados" @@ -2419,7 +2419,7 @@ "href": "iteration.html#saving-multiple-outputs", "title": "26  Iteration", "section": "\n26.4 Saving multiple outputs", - "text": "26.4 Saving multiple outputs\nIn the last section, you learned about map(), which is useful for reading multiple files into a single object. In this section, we’ll now explore sort of the opposite problem: how can you take one or more R objects and save it to one or more files? We’ll explore this challenge using three examples:\n\nSaving multiple data frames into one database.\nSaving multiple data frames into multiple .csv files.\nSaving multiple plots to multiple .png files.\n\n\n26.4.1 Writing to a database\nSometimes when working with many files at once, it’s not possible to fit all your data into memory at once, and you can’t do map(files, read_csv). One approach to deal with this problem is to load your data into a database so you can access just the bits you need with dbplyr.\nIf you’re lucky, the database package you’re using will provide a handy function that takes a vector of paths and loads them all into the database. This is the case with duckdb’s duckdb_read_csv():\n\ncon <- DBI::dbConnect(duckdb::duckdb())\nduckdb::duckdb_read_csv(con, \"gapminder\", paths)\n\nThis would work well here, but we don’t have csv files, instead we have excel spreadsheets. So we’re going to have to do it “by hand”. Learning to do it by hand will also help you when you have a bunch of csvs and the database that you’re working with doesn’t have one function that will load them all in.\nWe need to start by creating a table that will fill in with data. The easiest way to do this is by creating a template, a dummy data frame that contains all the columns we want, but only a sampling of the data. For the gapminder data, we can make that template by reading a single file and adding the year to it:\n\ntemplate <- readxl::read_excel(paths[[1]])\ntemplate$year <- 1952\ntemplate\n#> # A tibble: 142 × 6\n#> country continent lifeExp pop gdpPercap year\n#> <chr> <chr> <dbl> <dbl> <dbl> <dbl>\n#> 1 Afghanistan Asia 28.8 8425333 779. 1952\n#> 2 Albania Europe 55.2 1282697 1601. 1952\n#> 3 Algeria Africa 43.1 9279525 2449. 1952\n#> 4 Angola Africa 30.0 4232095 3521. 1952\n#> 5 Argentina Americas 62.5 17876956 5911. 1952\n#> 6 Australia Oceania 69.1 8691212 10040. 1952\n#> # ℹ 136 more rows\n\nNow we can connect to the database, and use DBI::dbCreateTable() to turn our template into a database table:\n\ncon <- DBI::dbConnect(duckdb::duckdb())\nDBI::dbCreateTable(con, \"gapminder\", template)\n\ndbCreateTable() doesn’t use the data in template, just the variable names and types. So if we inspect the gapminder table now you’ll see that it’s empty but it has the variables we need with the types we expect:\n\ncon |> tbl(\"gapminder\")\n#> # Source: table<gapminder> [0 x 6]\n#> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:]\n#> # ℹ 6 variables: country <chr>, continent <chr>, lifeExp <dbl>, pop <dbl>,\n#> # gdpPercap <dbl>, year <dbl>\n\nNext, we need a function that takes a single file path, reads it into R, and adds the result to the gapminder table. We can do that by combining read_excel() with DBI::dbAppendTable():\n\nappend_file <- function(path) {\n df <- readxl::read_excel(path)\n df$year <- parse_number(basename(path))\n \n DBI::dbAppendTable(con, \"gapminder\", df)\n}\n\nNow we need to call append_file() once for each element of paths. That’s certainly possible with map():\n\npaths |> map(append_file)\n\nBut we don’t care about the output of append_file(), so instead of map() it’s slightly nicer to use walk(). walk() does exactly the same thing as map() but throws the output away:\n\npaths |> walk(append_file)\n\nNow we can see if we have all the data in our table:\n\ncon |> \n tbl(\"gapminder\") |> \n count(year)\n#> # Source: SQL [?? x 2]\n#> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:]\n#> year n\n#> <dbl> <dbl>\n#> 1 2007 142\n#> 2 1967 142\n#> 3 1952 142\n#> 4 1957 142\n#> 5 1972 142\n#> 6 1992 142\n#> # ℹ more rows\n\n\n26.4.2 Writing csv files\nThe same basic principle applies if we want to write multiple csv files, one for each group. Let’s imagine that we want to take the ggplot2::diamonds data and save one csv file for each clarity. First we need to make those individual datasets. There are many ways you could do that, but there’s one way we particularly like: group_nest().\n\nby_clarity <- diamonds |> \n group_nest(clarity)\n\nby_clarity\n#> # A tibble: 8 × 2\n#> clarity data\n#> <ord> <list<tibble[,9]>>\n#> 1 I1 [741 × 9]\n#> 2 SI2 [9,194 × 9]\n#> 3 SI1 [13,065 × 9]\n#> 4 VS2 [12,258 × 9]\n#> 5 VS1 [8,171 × 9]\n#> 6 VVS2 [5,066 × 9]\n#> # ℹ 2 more rows\n\nThis gives us a new tibble with eight rows and two columns. clarity is our grouping variable and data is a list-column containing one tibble for each unique value of clarity:\n\nby_clarity$data[[1]]\n#> # A tibble: 741 × 9\n#> carat cut color depth table price x y z\n#> <dbl> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>\n#> 1 0.32 Premium E 60.9 58 345 4.38 4.42 2.68\n#> 2 1.17 Very Good J 60.2 61 2774 6.83 6.9 4.13\n#> 3 1.01 Premium F 61.8 60 2781 6.39 6.36 3.94\n#> 4 1.01 Fair E 64.5 58 2788 6.29 6.21 4.03\n#> 5 0.96 Ideal F 60.7 55 2801 6.37 6.41 3.88\n#> 6 1.04 Premium G 62.2 58 2801 6.46 6.41 4 \n#> # ℹ 735 more rows\n\nWhile we’re here, let’s create a column that gives the name of output file, using mutate() and str_glue():\n\nby_clarity <- by_clarity |> \n mutate(path = str_glue(\"diamonds-{clarity}.csv\"))\n\nby_clarity\n#> # A tibble: 8 × 3\n#> clarity data path \n#> <ord> <list<tibble[,9]>> <glue> \n#> 1 I1 [741 × 9] diamonds-I1.csv \n#> 2 SI2 [9,194 × 9] diamonds-SI2.csv \n#> 3 SI1 [13,065 × 9] diamonds-SI1.csv \n#> 4 VS2 [12,258 × 9] diamonds-VS2.csv \n#> 5 VS1 [8,171 × 9] diamonds-VS1.csv \n#> 6 VVS2 [5,066 × 9] diamonds-VVS2.csv\n#> # ℹ 2 more rows\n\nSo if we were going to save these data frames by hand, we might write something like:\n\nwrite_csv(by_clarity$data[[1]], by_clarity$path[[1]])\nwrite_csv(by_clarity$data[[2]], by_clarity$path[[2]])\nwrite_csv(by_clarity$data[[3]], by_clarity$path[[3]])\n...\nwrite_csv(by_clarity$by_clarity[[8]], by_clarity$path[[8]])\n\nThis is a little different to our previous uses of map() because there are two arguments that are changing, not just one. That means we need a new function: map2(), which varies both the first and second arguments. And because we again don’t care about the output, we want walk2() rather than map2(). That gives us:\n\nwalk2(by_clarity$data, by_clarity$path, write_csv)\n\n\n26.4.3 Saving plots\nWe can take the same basic approach to create many plots. Let’s first make a function that draws the plot we want:\n\ncarat_histogram <- function(df) {\n ggplot(df, aes(x = carat)) + geom_histogram(binwidth = 0.1) \n}\n\ncarat_histogram(by_clarity$data[[1]])\n\n\n\n\n\n\n\nNow we can use map() to create a list of many plots7 and their eventual file paths:\n\nby_clarity <- by_clarity |> \n mutate(\n plot = map(data, carat_histogram),\n path = str_glue(\"clarity-{clarity}.png\")\n )\n\nThen use walk2() with ggsave() to save each plot:\n\nwalk2(\n by_clarity$path,\n by_clarity$plot,\n \\(path, plot) ggsave(path, plot, width = 6, height = 6)\n)\n\nThis is shorthand for:\n\nggsave(by_clarity$path[[1]], by_clarity$plot[[1]], width = 6, height = 6)\nggsave(by_clarity$path[[2]], by_clarity$plot[[2]], width = 6, height = 6)\nggsave(by_clarity$path[[3]], by_clarity$plot[[3]], width = 6, height = 6)\n...\nggsave(by_clarity$path[[8]], by_clarity$plot[[8]], width = 6, height = 6)", + "text": "26.4 Saving multiple outputs\nIn the last section, you learned about map(), which is useful for reading multiple files into a single object. In this section, we’ll now explore sort of the opposite problem: how can you take one or more R objects and save it to one or more files? We’ll explore this challenge using three examples:\n\nSaving multiple data frames into one database.\nSaving multiple data frames into multiple .csv files.\nSaving multiple plots to multiple .png files.\n\n\n26.4.1 Writing to a database\nSometimes when working with many files at once, it’s not possible to fit all your data into memory at once, and you can’t do map(files, read_csv). One approach to deal with this problem is to load your data into a database so you can access just the bits you need with dbplyr.\nIf you’re lucky, the database package you’re using will provide a handy function that takes a vector of paths and loads them all into the database. This is the case with duckdb’s duckdb_read_csv():\n\ncon <- DBI::dbConnect(duckdb::duckdb())\nduckdb::duckdb_read_csv(con, \"gapminder\", paths)\n\nThis would work well here, but we don’t have csv files, instead we have excel spreadsheets. So we’re going to have to do it “by hand”. Learning to do it by hand will also help you when you have a bunch of csvs and the database that you’re working with doesn’t have one function that will load them all in.\nWe need to start by creating a table that will fill in with data. The easiest way to do this is by creating a template, a dummy data frame that contains all the columns we want, but only a sampling of the data. For the gapminder data, we can make that template by reading a single file and adding the year to it:\n\ntemplate <- readxl::read_excel(paths[[1]])\ntemplate$year <- 1952\ntemplate\n#> # A tibble: 142 × 6\n#> country continent lifeExp pop gdpPercap year\n#> <chr> <chr> <dbl> <dbl> <dbl> <dbl>\n#> 1 Afghanistan Asia 28.8 8425333 779. 1952\n#> 2 Albania Europe 55.2 1282697 1601. 1952\n#> 3 Algeria Africa 43.1 9279525 2449. 1952\n#> 4 Angola Africa 30.0 4232095 3521. 1952\n#> 5 Argentina Americas 62.5 17876956 5911. 1952\n#> 6 Australia Oceania 69.1 8691212 10040. 1952\n#> # ℹ 136 more rows\n\nNow we can connect to the database, and use DBI::dbCreateTable() to turn our template into a database table:\n\ncon <- DBI::dbConnect(duckdb::duckdb())\nDBI::dbCreateTable(con, \"gapminder\", template)\n\ndbCreateTable() doesn’t use the data in template, just the variable names and types. So if we inspect the gapminder table now you’ll see that it’s empty but it has the variables we need with the types we expect:\n\ncon |> tbl(\"gapminder\")\n#> # Source: table<gapminder> [0 x 6]\n#> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:]\n#> # ℹ 6 variables: country <chr>, continent <chr>, lifeExp <dbl>, pop <dbl>,\n#> # gdpPercap <dbl>, year <dbl>\n\nNext, we need a function that takes a single file path, reads it into R, and adds the result to the gapminder table. We can do that by combining read_excel() with DBI::dbAppendTable():\n\nappend_file <- function(path) {\n df <- readxl::read_excel(path)\n df$year <- parse_number(basename(path))\n \n DBI::dbAppendTable(con, \"gapminder\", df)\n}\n\nNow we need to call append_file() once for each element of paths. That’s certainly possible with map():\n\npaths |> map(append_file)\n\nBut we don’t care about the output of append_file(), so instead of map() it’s slightly nicer to use walk(). walk() does exactly the same thing as map() but throws the output away:\n\npaths |> walk(append_file)\n\nNow we can see if we have all the data in our table:\n\ncon |> \n tbl(\"gapminder\") |> \n count(year)\n#> # Source: SQL [?? x 2]\n#> # Database: DuckDB v0.10.0 [root@Darwin 21.6.0:R 4.3.3/:memory:]\n#> year n\n#> <dbl> <dbl>\n#> 1 1977 142\n#> 2 1987 142\n#> 3 2007 142\n#> 4 1967 142\n#> 5 1952 142\n#> 6 1957 142\n#> # ℹ more rows\n\n\n26.4.2 Writing csv files\nThe same basic principle applies if we want to write multiple csv files, one for each group. Let’s imagine that we want to take the ggplot2::diamonds data and save one csv file for each clarity. First we need to make those individual datasets. There are many ways you could do that, but there’s one way we particularly like: group_nest().\n\nby_clarity <- diamonds |> \n group_nest(clarity)\n\nby_clarity\n#> # A tibble: 8 × 2\n#> clarity data\n#> <ord> <list<tibble[,9]>>\n#> 1 I1 [741 × 9]\n#> 2 SI2 [9,194 × 9]\n#> 3 SI1 [13,065 × 9]\n#> 4 VS2 [12,258 × 9]\n#> 5 VS1 [8,171 × 9]\n#> 6 VVS2 [5,066 × 9]\n#> # ℹ 2 more rows\n\nThis gives us a new tibble with eight rows and two columns. clarity is our grouping variable and data is a list-column containing one tibble for each unique value of clarity:\n\nby_clarity$data[[1]]\n#> # A tibble: 741 × 9\n#> carat cut color depth table price x y z\n#> <dbl> <ord> <ord> <dbl> <dbl> <int> <dbl> <dbl> <dbl>\n#> 1 0.32 Premium E 60.9 58 345 4.38 4.42 2.68\n#> 2 1.17 Very Good J 60.2 61 2774 6.83 6.9 4.13\n#> 3 1.01 Premium F 61.8 60 2781 6.39 6.36 3.94\n#> 4 1.01 Fair E 64.5 58 2788 6.29 6.21 4.03\n#> 5 0.96 Ideal F 60.7 55 2801 6.37 6.41 3.88\n#> 6 1.04 Premium G 62.2 58 2801 6.46 6.41 4 \n#> # ℹ 735 more rows\n\nWhile we’re here, let’s create a column that gives the name of output file, using mutate() and str_glue():\n\nby_clarity <- by_clarity |> \n mutate(path = str_glue(\"diamonds-{clarity}.csv\"))\n\nby_clarity\n#> # A tibble: 8 × 3\n#> clarity data path \n#> <ord> <list<tibble[,9]>> <glue> \n#> 1 I1 [741 × 9] diamonds-I1.csv \n#> 2 SI2 [9,194 × 9] diamonds-SI2.csv \n#> 3 SI1 [13,065 × 9] diamonds-SI1.csv \n#> 4 VS2 [12,258 × 9] diamonds-VS2.csv \n#> 5 VS1 [8,171 × 9] diamonds-VS1.csv \n#> 6 VVS2 [5,066 × 9] diamonds-VVS2.csv\n#> # ℹ 2 more rows\n\nSo if we were going to save these data frames by hand, we might write something like:\n\nwrite_csv(by_clarity$data[[1]], by_clarity$path[[1]])\nwrite_csv(by_clarity$data[[2]], by_clarity$path[[2]])\nwrite_csv(by_clarity$data[[3]], by_clarity$path[[3]])\n...\nwrite_csv(by_clarity$by_clarity[[8]], by_clarity$path[[8]])\n\nThis is a little different to our previous uses of map() because there are two arguments that are changing, not just one. That means we need a new function: map2(), which varies both the first and second arguments. And because we again don’t care about the output, we want walk2() rather than map2(). That gives us:\n\nwalk2(by_clarity$data, by_clarity$path, write_csv)\n\n\n26.4.3 Saving plots\nWe can take the same basic approach to create many plots. Let’s first make a function that draws the plot we want:\n\ncarat_histogram <- function(df) {\n ggplot(df, aes(x = carat)) + geom_histogram(binwidth = 0.1) \n}\n\ncarat_histogram(by_clarity$data[[1]])\n\n\n\n\n\n\n\nNow we can use map() to create a list of many plots7 and their eventual file paths:\n\nby_clarity <- by_clarity |> \n mutate(\n plot = map(data, carat_histogram),\n path = str_glue(\"clarity-{clarity}.png\")\n )\n\nThen use walk2() with ggsave() to save each plot:\n\nwalk2(\n by_clarity$path,\n by_clarity$plot,\n \\(path, plot) ggsave(path, plot, width = 6, height = 6)\n)\n\nThis is shorthand for:\n\nggsave(by_clarity$path[[1]], by_clarity$plot[[1]], width = 6, height = 6)\nggsave(by_clarity$path[[2]], by_clarity$plot[[2]], width = 6, height = 6)\nggsave(by_clarity$path[[3]], by_clarity$plot[[3]], width = 6, height = 6)\n...\nggsave(by_clarity$path[[8]], by_clarity$plot[[8]], width = 6, height = 6)", "crumbs": [ "✅ Programar", "26  Iteration" diff --git a/sitemap.xml b/sitemap.xml index f3f816776..11cc4257f 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -122,7 +122,7 @@ https://cienciadedatos.github.io/pt-r4ds/webscraping.html - 2024-04-27T21:41:29.886Z + 2024-04-27T21:49:14.275Z https://cienciadedatos.github.io/pt-r4ds/program.html diff --git a/webscraping.html b/webscraping.html index dbfc09d7f..9e0158944 100644 --- a/webscraping.html +++ b/webscraping.html @@ -460,17 +460,7 @@

    -
    -
    - -
    -
    -

    Olá! Este capítulo do livro ainda não está traduzido para a versão Português-BR.
    Caso você queira contribuir com o projeto de tradução, leia as instruções em: https://github.com/cienciadedatos/pt-r4ds/wiki
    A versão original (em inglês) do livro R for Data Science está disponível em: https://r4ds.hadley.nz/

    -
    -
    -
    -

    +

    24.1 Introdução

    Este capítulo faz a introdução do básico sobre raspagem de dados (web scraping) com o pacote rvest. Raspagem de dados é uma ferramenta muito útil para extração de dados de páginas web. Alguns websites oferecem uma API, um conjunto de requisições HTTP estruturadas que retornam dados no formato JSON, com o qual você pode lidar usando as técnicas do Capítulo 23. Sempre que possível, você deve usar uma API1, pois geralmente te retornará dados mais confiáveis. Entretanto, infelizmente, programar com APIs web está fora do escopo deste livro. Ao invés disso, ensinaremos sobre raspagem de dados, uma técnica que funciona independentemente de o site fornecer uma API ou não.

    Neste capítulo, discutiremos primeiro sobre ética e legalidade da raspagem de dados antes de falar sobre o básico de HTML. Você aprenderá o básico sobre seletores CSS para localizar elementos específicos em uma página, e como usar funções do rvest para obter dados de textos e atributos de um HTML para o R. Depois, discutiremos algumas técnicas para descobrir qual seletor CSS você precisa para a página que está fazendo a raspagem de dados e terminaremos falando sobre alguns estudos de caso e uma breve discussão sobre websites dinâmicos.