R: Przetwarzanie danych z pakietem dplyr

Przygotowanie danych do analizy – jeżeli po przeczytaniu tych czterech słów przeszły cię ciarki po plecach to znak, że najwyższy czas poznać pakiet dplyr. Prawdopodobnie dopiero zaczynasz przygodę z R, być może masz już lepsze lub gorsze doświadczenia z pracy z danymi w Excelu, a może znasz Pythonowe pandas i chcesz zdobyć podobne umiejętności w R. Niezależnie od twojej motywacji to jest doskonały moment na poznanie dplyr (lepszy był tylko wczoraj). Zachęcam cię więc do uruchomienia R, pobrania danych i ćwiczenia razem z artykułem.

Na początek kilka słów o pakiecie dplyr służącym do przetwarzania danych. Jego autorem jest Hadley Wickham, R-owy guru, a obecnie Chief Scientist w RStudio. Hadley jest autorem wielu popularnych pakietów, a to dlatego, że są one dobrze przemyślane i intuicyjne w użyciu. Podobnie jest z dplyrem, jeżeli umiesz zastować jedną funkcję to już umiesz zastosować je wszystkie (no, prawie :)).W tym poradniku omówię najważniejsze funkcje pakietu dplyr, które pozwalają na filtrowanie i wybór danych, sortowanie, dodawanie nowych zmiennych, grupowanie oraz tworzenie raportów i zestawień. Jednym słowem wszystkie operacje, które są potrzebne do podstawowego przetwarzania danych. Strona pakietu dplyr: https://dplyr.tidyverse.org/

Najlepiej uczyć się na przykładach, które rozbudzają naszą ciekawość w związku z czym zajmiemy się winem. Postaramy się w analityczny sposób odpowiedzieć na takie pytania jak: – Czy dobre wino musi być drogie? – Które kraje produkują drogie wino, a które tanie? – Które wina mają najlepszy stosunek cena/jakość?

Instalacja i wczytanie pakietu tidyverse

Zanim zaczniemy musimy zainstalować dplyr. Najlepszym pomysłem będzie instalacja i wczytanie całego pakietu tidyverse. Tidyverse to zbiór wiodących pakietów do data science. W jego skład wchodzą pakiety do wczytywania, analizy i wizualizacji danych, pracy z tekstem i datami oraz pakiet purrr do programowania funkcyjnego. Jednym z pakietów jest właśnie dplyr, którym będziemy się zajmować. Tidyverse jest przydatny w każdej analizie, więc warto go znać. Ja wręcz wczytuję ten pakiet “z automatu”, bo wiem, że na pewno będzie mi potrzebny.

install.packages("tidyverse")
library(tidyverse)

Instalacja i wczytanie wyłącznie pakietów dplyr i readr

Alternatywnie możemy zainstalować i wczytać tylko te pakiety, z których będziemy korzystać.

install.packages("dplyr")
install.packages("readr")
library(dplyr) # przetwarzanie danych
library(readr) # import/eksport danych

Dane – recenzje win

Dane, które wykorzystamy w analizie to recenzje win z serwisu winemag.com. Zbiór został zescrapowany i udostępniony w serwisie kaggle przez użytkownika ‘zynicide’ i można go pobrać tutaj: https://www.kaggle.com/zynicide/wine-reviews

Dane zawierają informacje z prawie 130 tysięcy recenzji win takie jak ocena, cena wina, nazwisko i nick recenzenta, treść recenzji oraz nazwa i pochodzenie wina.

Oceny przyznawane są winom w blind testach wg. następującej skali:

  • 98–100 Classic The pinnacle of quality.
  • 94–97 Superb A great achievement.
  • 90–93 Excellent Highly recommended.
  • 87–89 Very Good Often good value; well recommended.
  • 83–86 Good Suitable for everyday consumption; often good value.
  • 80–82 Acceptable Can be employed in casual, less-critical circumstances.
  • Products deemed Unacceptable (receiving a rating below 80 points) are not reviewed.

źródło: https://www.winemag.com

Dane są w formacie .csv i do ich wczytania wykorzystamy pakiet readr.

wines <- read_csv("winemag-data-130k-v2.csv")
## Warning: Missing column names filled in: 'X1' [1]
## Parsed with column specification:
## cols(
##   X1 = col_integer(),
##   country = col_character(),
##   description = col_character(),
##   designation = col_character(),
##   points = col_integer(),
##   price = col_double(),
##   province = col_character(),
##   region_1 = col_character(),
##   region_2 = col_character(),
##   taster_name = col_character(),
##   taster_twitter_handle = col_character(),
##   title = col_character(),
##   variety = col_character(),
##   winery = col_character()
## )

Tibble

Tidyverse wprowadził nową klasę o nazwie tibble. Tibble to ulepszona wersja data.frame. Główne różnice to ładniejsze formatowanie oraz ujednolicenie klas i typów danych otrzymywanych wyników, ale o tym innym razem. Na razie proponuję po prostu korzystać z tibble zamiast z data.frame i się nie przejmować szczegółami.

Pakiet readr automatycznie wczytuje dane jako tibble, więc możemy poniższy krok pominąć. Jeżeli natomiat mamy dane wczytane jako data.frame możemy zamienić je na tibble funkcją as_tibble():

wines <- as_tibble(wines)
class(wines) # sprawdzamy klasę obiektu
## [1] "tbl_df"     "tbl"        "data.frame"

Oglądanie i filtrowanie danych – glimpse, filter, sample,…

Zanim zaczniemy warto obejrzeć nasze dane. Ile jest zmiennych, ile jest obserwacji? Jakiego typu są dane? W tym celu dobrze jest zastosować funkcje str() lub glimpse().

W dplyrze odpowiednik funkcji str() to funkcja glimpse(). Nie ma między nimi dużej różnicy, glimpse() ma troche ładniejsze formatowanie.

glimpse(wines)
## Observations: 129,971
## Variables: 14
## $ X1                    <int> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12...
## $ country               <chr> "Italy", "Portugal", "US", "US", "US", "...
## $ description           <chr> "Aromas include tropical fruit, broom, b...
## $ designation           <chr> "Vulka Bianco", "Avidagos", NA, "Reserve...
## $ points                <int> 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, ...
## $ price                 <dbl> NA, 15, 14, 13, 65, 15, 16, 24, 12, 27, ...
## $ province              <chr> "Sicily & Sardinia", "Douro", "Oregon", ...
## $ region_1              <chr> "Etna", NA, "Willamette Valley", "Lake M...
## $ region_2              <chr> NA, NA, "Willamette Valley", NA, "Willam...
## $ taster_name           <chr> "Kerin O’Keefe", "Roger Voss", "Paul Gre...
## $ taster_twitter_handle <chr> "@kerinokeefe", "@vossroger", "@paulgwin...
## $ title                 <chr> "Nicosia 2013 Vulka Bianco  (Etna)", "Qu...
## $ variety               <chr> "White Blend", "Portuguese Red", "Pinot ...
## $ winery                <chr> "Nicosia", "Quinta dos Avidagos", "Rains...

Jako wynik otrzymujemy transpozycję naszych danych, tak by łatwo było obejrzeć je wszystkie, nawet gdy jest dużo zmiennych. Mamy też informacje o liczbie zmiennych i obserwacji oraz o typach poszczegółnych zmiennych.

Skoro wiemy już jak wyglądają nasze dane czas rozpocząć zabawę z pakietem dplyr.

Filter – filtrowanie obserwacji

Czy stać nas na doskonałe wino?
Możemy skorzystać z funkcji filter w celu odfiltrowania obserwacji spełniających pewne kryteria. Warunki podajemy po przecinku. Jako przykład odfiltrujemy wina, które otrzymały ocenę co najmniej 94 oraz kosztują mniej niż $25.

filter(wines, points >= 94, price < 25)
## # A tibble: 66 x 14
##       X1 country  description   designation points price province region_1
##    <int> <chr>    <chr>         <chr>        <int> <dbl> <chr>    <chr>   
##  1  5011 US       Truly stunni~ Lewis Esta~     95   20. Washing~ Columbi~
##  2  6267 US       This tastes ~ Lucille La~     94   18. Washing~ Yakima ~
##  3 10763 Portugal His skills s~ Rapariga d~     94   23. Alentej~ <NA>    
##  4 12944 France   The Côte du ~ Côte du Py~     94   24. Beaujol~ Morgon  
##  5 12945 France   Be grateful ~ Vieilles V~     94   24. Beaujol~ Moulin-~
##  6 12967 France   A firm and s~ <NA>            94   24. Beaujol~ Moulin-~
##  7 15196 France   The home vin~ Château Bo~     95   20. Southwe~ Madiran 
##  8 15211 US       The deep gol~ <NA>            94   22. Oregon   Willame~
##  9 17294 US       Opulento is ~ Opulento D~     94   20. Washing~ Yakima ~
## 10 17983 France   This is one ~ <NA>            94   20. Provence Coteaux~
## # ... with 56 more rows, and 6 more variables: region_2 <chr>,
## #   taster_name <chr>, taster_twitter_handle <chr>, title <chr>,
## #   variety <chr>, winery <chr>

Widzimy, że takich win jest 66 i co ciekawe prawie wszytkie pochodzą z USA. Być może ma na to wpływ fakt, że oceny win pochodzą z amerykańskiego portalu (patriotyzm i niższe koszty dystrybucji lokalnych win).

Sample – losowanie obserwacji

Jeżeli chcielibyśmy obejrzeć próbkę danych lub przetestować kod na małym wycinku naszego zbioru, przydatne będą funkcję sample_frac i sample_n. Pozwolą nam one odpowienio wylosować fragment obserwacji lub określoną ich liczbę. Przykładowo wylosujemy 1% wszystkich obserwacji.

sample_frac(wines, 0.01)
## # A tibble: 1,300 x 14
##        X1 country description   designation points price province region_1
##     <int> <chr>   <chr>         <chr>        <int> <dbl> <chr>    <chr>   
##  1  70182 Italy   This wine st~ Riserva         89   30. Tuscany  Chianti~
##  2  49323 Italy   Bold and ele~ Sugarille       94  190. Tuscany  Brunell~
##  3  53605 Italy   This wine op~ Sorgente        85   18. Lombardy Lugana  
##  4  67225 US      A light, eth~ <NA>            90   24. Califor~ Solano ~
##  5  46670 US      Black fruit ~ Riserva         85   29. North C~ Swan Cr~
##  6 109721 US      This very li~ Reserve         88   30. Washing~ Columbi~
##  7 122385 US      A big, soft ~ <NA>            85   11. Califor~ Califor~
##  8  90728 US      For some rea~ Three Coin~     91   28. Califor~ Sonoma ~
##  9  46987 US      Slightly dus~ Barrel Age~     86   18. New York New York
## 10  80441 Italy   This wine be~ Riserva         86   NA  Tuscany  Brunell~
## # ... with 1,290 more rows, and 6 more variables: region_2 <chr>,
## #   taster_name <chr>, taster_twitter_handle <chr>, title <chr>,
## #   variety <chr>, winery <chr>

Wylosowanych zostało 1300 obserwacji.

Top n – Topowe obserwacje

Które wina są najlepsze?
Funkcja top_n pozwala nam na odfiltrowanie n topowych obserwacji wg. wybranej zmiennej. Przykładowo możemy odfiltrować 3 wina, które zdobyły najwięcej punktów.

top_n(wines, 3, points)
## # A tibble: 19 x 14
##        X1 country  description  designation points price province region_1
##     <int> <chr>    <chr>        <chr>        <int> <dbl> <chr>    <chr>   
##  1    345 Austral~ This wine c~ Rare           100  350. Victoria Rutherg~
##  2   7335 Italy    Thick as mo~ Occhio di ~    100  210. Tuscany  Vin San~
##  3  36528 France   This is a f~ Brut           100  259. Champag~ Champag~
##  4  39286 Italy    A perfect w~ Masseto        100  460. Tuscany  Toscana 
##  5  42197 Portugal This is the~ Barca-Velha    100  450. Douro    <NA>    
##  6  45781 Italy    This gorgeo~ Riserva        100  550. Tuscany  Brunell~
##  7  45798 US       Tasted in a~ <NA>           100  200. Califor~ Napa Va~
##  8  58352 France   This is a m~ <NA>           100  150. Bordeaux Saint-J~
##  9  89728 France   This latest~ Cristal Vi~    100  250. Champag~ Champag~
## 10  89729 France   This new re~ Le Mesnil ~    100  617. Champag~ Champag~
## 11 111753 France   Almost blac~ <NA>           100 1500. Bordeaux Pauillac
## 12 111754 Italy    It takes on~ Cerretalto     100  270. Tuscany  Brunell~
## 13 111755 France   This is the~ <NA>           100 1500. Bordeaux Saint-É~
## 14 111756 France   A hugely po~ <NA>           100  359. Bordeaux Saint-J~
## 15 113929 US       In 2005 Cha~ Royal City     100   80. Washing~ Columbi~
## 16 114972 Portugal A powerful ~ Nacional V~    100  650. Port     <NA>    
## 17 118058 US       This wine d~ La Muse        100  450. Califor~ Sonoma ~
## 18 122935 France   Full of rip~ <NA>           100  848. Bordeaux Pessac-~
## 19 123545 US       Initially a~ Bionic Frog    100   80. Washing~ Walla W~
## # ... with 6 more variables: region_2 <chr>, taster_name <chr>,
## #   taster_twitter_handle <chr>, title <chr>, variety <chr>, winery <chr>

Okazuje się, że zamiast 3 obserwacji otrzymaliśmy 19. To dlatego, że istnieją więcej niż 3 obserwację, które uzyskały najwyższą notę i uzyskują one miejsce ex aequo. Przy okazji widzimy, że rozpiętość cenowa jest znaczna – tą samą ocenę otrzymały wina za $80 i $1500. Mimo, że różnica jest prawie dwudziestokrotna obie ceny przyprawiają o zawrót głowy.

Spójrzmy lepiej na wina przy których możemy spędzić piątkowy wieczór. Używając znaku minusa możemy uzyskać top najmniejsze wartości, na przykład 100 najtańszych win.

top_n(wines, 100, -price)
## # A tibble: 177 x 14
##       X1 country  description   designation points price province region_1
##    <int> <chr>    <chr>         <chr>        <int> <dbl> <chr>    <chr>   
##  1  1620 Portugal The very loc~ Brado Bran~     85    6. Alentej~ <NA>    
##  2  1987 Spain    Berry and ch~ Flirty Bird     85    4. Central~ Vino de~
##  3  2335 US       Reserved aro~ <NA>            85    6. Washing~ Washing~
##  4  2618 Argenti~ Lightly bram~ <NA>            83    6. Mendoza~ Mendoza 
##  5  2780 Portugal This feels v~ Morgado da~     84    5. Alentej~ <NA>    
##  6  3167 Italy    Packaged in ~ Mini            86    5. Veneto   Prosecco
##  7  3948 Portugal Soft, sweet ~ Coreto          83    6. Lisboa   <NA>    
##  8  3950 Portugal On the dry s~ Escolha         83    5. Vinho V~ <NA>    
##  9  5152 Spain    A steal for ~ Vina Borgia     87    6. Norther~ Campo d~
## 10  5789 France   This is a ja~ <NA>            83    5. France ~ Vin de ~
## # ... with 167 more rows, and 6 more variables: region_2 <chr>,
## #   taster_name <chr>, taster_twitter_handle <chr>, title <chr>,
## #   variety <chr>, winery <chr>

Otrzymaliśmy listę 177 win w granicach $4 – $6, czyli ok. kilkunastu złotych. To w kontekście piątkowego wieczoru brzmi o wiele lepiej. Warto zwrócić uwagę, że otrzymane wyniki nie są posortowane. Do sortowania służy inna funkcja – arrange.

Arrange – Sortowanie

Domyślnie wyniki sortowane są od najmniejszego do największego, a w przypadku liter od A do Z. Jeżel zależy nam na odwrotnym sortowaniu musimy dodać funkcję desc() (descending – malejąco) do sortowanej zmiennej. W przypadku zmiennych numerycznych dziala również znak minus.

arrange(wines, desc(points))
## # A tibble: 129,971 x 14
##       X1 country  description   designation points price province region_1
##    <int> <chr>    <chr>         <chr>        <int> <dbl> <chr>    <chr>   
##  1   345 Austral~ This wine co~ Rare           100  350. Victoria Rutherg~
##  2  7335 Italy    Thick as mol~ Occhio di ~    100  210. Tuscany  Vin San~
##  3 36528 France   This is a fa~ Brut           100  259. Champag~ Champag~
##  4 39286 Italy    A perfect wi~ Masseto        100  460. Tuscany  Toscana 
##  5 42197 Portugal This is the ~ Barca-Velha    100  450. Douro    <NA>    
##  6 45781 Italy    This gorgeou~ Riserva        100  550. Tuscany  Brunell~
##  7 45798 US       Tasted in a ~ <NA>           100  200. Califor~ Napa Va~
##  8 58352 France   This is a ma~ <NA>           100  150. Bordeaux Saint-J~
##  9 89728 France   This latest ~ Cristal Vi~    100  250. Champag~ Champag~
## 10 89729 France   This new rel~ Le Mesnil ~    100  617. Champag~ Champag~
## # ... with 129,961 more rows, and 6 more variables: region_2 <chr>,
## #   taster_name <chr>, taster_twitter_handle <chr>, title <chr>,
## #   variety <chr>, winery <chr>

Poniższy kod zwóci nam ten sam wynik:

arrange(wines, -points)

Praca ze zmiennymi

Dplyr pozwala nam na dodawanie i usuwanie zmiennych oraz przekształcanie tych już istniejących. Poznamy trzy najbardziej przydante funkcje: select, rename i mutate.

Select – Wybór zmiennych

Wybiranie zmiennych z danych jest bardzo proste. Służy do tego funkcja select(). W poniższym przykładzie wybierzemy cztery zmienne mówiące o pochodzeniu wina: country, oraz po kolei zmienne od province do region_2.

select(wines, country, province:region_2)
## # A tibble: 129,971 x 4
##    country  province          region_1            region_2         
##    <chr>    <chr>             <chr>               <chr>            
##  1 Italy    Sicily & Sardinia Etna                <NA>             
##  2 Portugal Douro             <NA>                <NA>             
##  3 US       Oregon            Willamette Valley   Willamette Valley
##  4 US       Michigan          Lake Michigan Shore <NA>             
##  5 US       Oregon            Willamette Valley   Willamette Valley
##  6 Spain    Northern Spain    Navarra             <NA>             
##  7 Italy    Sicily & Sardinia Vittoria            <NA>             
##  8 France   Alsace            Alsace              <NA>             
##  9 Germany  Rheinhessen       <NA>                <NA>             
## 10 France   Alsace            Alsace              <NA>             
## # ... with 129,961 more rows

Znak minus powala nam wykluczyć zmienną z danych. Pozbywamy się zmiennej X1.

select(wines, -X1)
## # A tibble: 129,971 x 13
##    country description designation points price province region_1 region_2
##    <chr>   <chr>       <chr>        <int> <dbl> <chr>    <chr>    <chr>   
##  1 Italy   Aromas inc~ Vulka Bian~     87   NA  Sicily ~ Etna     <NA>    
##  2 Portug~ This is ri~ Avidagos        87   15. Douro    <NA>     <NA>    
##  3 US      Tart and s~ <NA>            87   14. Oregon   Willame~ Willame~
##  4 US      Pineapple ~ Reserve La~     87   13. Michigan Lake Mi~ <NA>    
##  5 US      Much like ~ Vintner's ~     87   65. Oregon   Willame~ Willame~
##  6 Spain   Blackberry~ Ars In Vit~     87   15. Norther~ Navarra  <NA>    
##  7 Italy   Here's a b~ Belsito         87   16. Sicily ~ Vittoria <NA>    
##  8 France  This dry a~ <NA>            87   24. Alsace   Alsace   <NA>    
##  9 Germany Savory dri~ Shine           87   12. Rheinhe~ <NA>     <NA>    
## 10 France  This has g~ Les Natures     87   27. Alsace   Alsace   <NA>    
## # ... with 129,961 more rows, and 5 more variables: taster_name <chr>,
## #   taster_twitter_handle <chr>, title <chr>, variety <chr>, winery <chr>

W zasadzie w każdej funkcji pakietu dplyr zasada jest taka sama. Minus wyklucza daną zmienną lub sortuje/wybiera malejąco natomiast dwukropek pozwala na wybór zakresu zmiennych.

Rename – zmiana nazwy zmiennej

Zamienimy nazwę zmiennej points na score.

rename(wines, score = points)
## # A tibble: 129,971 x 14
##       X1 country  description    designation score price province region_1
##    <int> <chr>    <chr>          <chr>       <int> <dbl> <chr>    <chr>   
##  1     0 Italy    Aromas includ~ Vulka Bian~    87   NA  Sicily ~ Etna    
##  2     1 Portugal This is ripe ~ Avidagos       87   15. Douro    <NA>    
##  3     2 US       Tart and snap~ <NA>           87   14. Oregon   Willame~
##  4     3 US       Pineapple rin~ Reserve La~    87   13. Michigan Lake Mi~
##  5     4 US       Much like the~ Vintner's ~    87   65. Oregon   Willame~
##  6     5 Spain    Blackberry an~ Ars In Vit~    87   15. Norther~ Navarra 
##  7     6 Italy    Here's a brig~ Belsito        87   16. Sicily ~ Vittoria
##  8     7 France   This dry and ~ <NA>           87   24. Alsace   Alsace  
##  9     8 Germany  Savory dried ~ Shine          87   12. Rheinhe~ <NA>    
## 10     9 France   This has grea~ Les Natures    87   27. Alsace   Alsace  
## # ... with 129,961 more rows, and 6 more variables: region_2 <chr>,
## #   taster_name <chr>, taster_twitter_handle <chr>, title <chr>,
## #   variety <chr>, winery <chr>

Pamiętajmy, że zmiana nie zostanie zastosowana dopóki nie przypiszemy jej do naszego obiektu. Na przykład wines = rename(wines, score = points).

Mutate – Dodawanie nowych zmiennych

Ile te wina kosztują w złotówkach?
Możemy dodać nową zmienną lub przekształcić już istniejącą za pomocą funkcji mutate(). Przykładowo dodamy zmienną “price_pln”, która będzie ceną wina w złotych. Przyjmijmy kurs dolara do złotego na poziomie 3,70.

Przemnażamy zmienną price przez kurs wymiany.

usd_to_pln = 3.7
wines = mutate(wines, price_pln = price * usd_to_pln)

Pamiętajmu o przypisaniu wyniku naszej operacji do zmiennej. W przeciwnym wypadku zmiana nie zostanie zapisana.

Gropowanie, agregacja i statystyki

Pakiet dplyr pozwala na agregację danych, liczenie statystyk dla całego zbioru lub wybranych kategorii. Możemy tworzyć zestawienia podobne do tabel przestawnych z Excela, choć do tego przyda nam się jeszcze jeden pakiet z arsenału tidyversa – tidyr.

Summarise – statystyki

Ile średnio kosztuje butelka recenzowanego wina?
Policzymy średnią i odchylenie standardowe dla cen wina. Nasze wyniki nazwiemy mean_price oraz std_price. Ponieważ w naszym zbiorze występują brakujące wartości musimy je zignorować za pomocą argumentu na.rm = T w funkcjach mean() i sd(). W przeciwnym wypadku jako wynik otrzymamy NA lub NaN.

summarise(wines,
          mean_price = mean(price, na.rm = T),
          std_price = sd(price, na.rm = T))
## # A tibble: 1 x 2
##   mean_price std_price
##        <dbl>     <dbl>
## 1       35.4      41.0

Średnia cena wina wynosi $35.4, a odchylenie standardowe $41. Odchylenie standardowe jest bardzo duże, dlatego że oprócz win będących w zasięgu cenowym przeciętnego kupującego wystepują w danych wina ekstremalnie drogie, luksusowe. Spójrzmy na poniższe zestawienie:

quantile(wines$price, na.rm = T, probs = c(0, 0.1, 0.25, 0.50, 0.75, 0.9, 1))
##   0%  10%  25%  50%  75%  90% 100% 
##    4   12   17   25   42   65 3300

Funkcja quantile() z pakietu stats pozwala na policzenie poszczególnych kwantyli. Okazuje się, że 90% win kosztuje poniżej $65, a najdroższe wino w danych aż $3300! W związku z tak dużą skośnością rozkładu średnia nie będzie dobra miarą do raportowania cen wina i zdecydowanie lepiej będzie posłużyć się medianą.

summarise(wines,
          median_price = median(price, na.rm = T))
## # A tibble: 1 x 1
##   median_price
##          <dbl>
## 1          25.

Mediana wyniosła $25, czyli połowa win była tańsza od tej kwoty, a połowa była droższa.

Summarise służy nie tylko do liczenia średniej lub mediany. Możemy wykorzystać ją do różnego rodzaju statystyk. Z tych najczęściej używanych warto wyróżnić: – mean() – średnia – median() – mediana – sd() – odchylenie standardowe – min() – minimum – max() – maksimum – n() – liczba obserwacji – n_distinct() – liczba unikatowych obserwacji

Pipes – wiele funkcji po kolei

Które wina mają najlepszy stosunek ceny do jakości?
Żeby odpowiedzieć na takie pytanie powinniśmy stworzyć zmienną cena/jakość (price_score_ratio), która powie nam ile złotych płacimy przeciętnie za każdy zdobyty punkt. Następnie posortujemy wina według naszego nowo utworzonego wskaźnika. Żeby zestawienie było czytelne wybierzemy tylko te kolumny, które nas najbardziej interesują: nazwa wina, cena, ocena, stosunek ceny do jakości (title, price_pln, points, price_score_ratio).

Już wiemy jak wykonać każdą z opisanych wyżej operacji: tworzenie nowych zmiennych, sortowanie, wybór kolumn, ale warto poznać sposób, który pozwoli te wszystkie kroki zgrabnie połączyć. Tym sposobem będzie znak %>% tzw. ‘pipe operator’. Jak to działa? Wynik operacji przekazywany jest do następnej operacji jako jej pierwszy argument. Czyli jeżeli w pierwszym kroku utworzymy nową zmienną to następna funkcja jako pierwszy argument przyjmie dane już zawierające tą nową zmienną.

Spójrzmy na przykład, w którym do danych dodajemy wkaźnik cena/jakość, następnie wybieramy kolumny i sortujemy wyniki. Warto zwrócić uwagę, że żadna z funkcji nie zawiera już pierwszego argumentu (.data =) ponieważ jest on przekazywany znakiem %>% z poprzedniego wyniku. Innymi słowy x %>% f(y) to jest to samo co f(x, y).

wines %>% 
  mutate(price_score_ratio = price_pln/points) %>% 
  select(title, price_pln, points, price_score_ratio) %>% 
  arrange(price_score_ratio)
## # A tibble: 129,971 x 4
##    title                                 price_pln points price_score_rat~
##    <chr>                                     <dbl>  <int>            <dbl>
##  1 Bandit NV Merlot (California)              14.8     86            0.172
##  2 Cramele Recas 2011 UnWineD Pinot Gri~      14.8     86            0.172
##  3 Felix Solis 2013 Flirty Bird Syrah (~      14.8     85            0.174
##  4 Dancing Coyote 2015 White (Clarksbur~      14.8     85            0.174
##  5 Broke Ass 2009 Red Malbec-Syrah (Men~      14.8     84            0.176
##  6 Bandit NV Chardonnay (California)          14.8     84            0.176
##  7 Terrenal 2010 Cabernet Sauvignon (Ye~      14.8     84            0.176
##  8 Bandit NV Merlot (California)              14.8     84            0.176
##  9 Terrenal 2010 Estate Bottled Tempran~      14.8     84            0.176
## 10 Pam's Cuties NV Unoaked Chardonnay (~      14.8     83            0.178
## # ... with 129,961 more rows

Okazuje się, że wedłgu naszego wskaźnika najbardziej opłacają się najtańsze wina. Zgodnie z powiedzeniem “tanie wino jest dobre bo jest dobre i tanie” 🙂 Wyśróbujmy w takim razie trochę wymagania i odfiltrujmy tylko te obserwacje, które uzyskały 90 lub więcej punktów. Do naszego pipe’a dodajmy funkcję filter().

wines %>% 
  mutate(price_score_ratio = price_pln/points) %>% 
  select(title, price_pln, points, price_score_ratio) %>% 
  filter(points >= 90) %>% 
  arrange(price_score_ratio)
## # A tibble: 49,045 x 4
##    title                                 price_pln points price_score_rat~
##    <chr>                                     <dbl>  <int>            <dbl>
##  1 Herdade dos Machados 2012 Toutalga R~      25.9     91            0.285
##  2 Snoqualmie 2006 Winemaker's Select R~      29.6     91            0.325
##  3 Esser Cellars 2001 Chardonnay (Calif~      29.6     90            0.329
##  4 Aveleda 2013 Quinta da Aveleda Estat~      29.6     90            0.329
##  5 Rothbury Estate 2001 Chardonnay (Sou~      29.6     90            0.329
##  6 Chateau Ste. Michelle 2011 Riesling ~      33.3     91            0.366
##  7 Chateau Ste. Michelle 2010 Dry Riesl~      33.3     91            0.366
##  8 Barnard Griffin 2012 Fumé Blanc Sauv~      33.3     91            0.366
##  9 Mano A Mano 2011 Tempranillo (Vino d~      33.3     90            0.370
## 10 Aveleda 2014 Quinta da Aveleda Estat~      33.3     90            0.370
## # ... with 49,035 more rows

Kod zapisany z pomocą pipes jest bardzo czytelny, operacje wykonywane są krok po kroku i jednocześnie nie musimy wszystkich wyników tymczasowych zapisywać do zmiennej. Jeżeli chcemy ułatwić sobie wpisywanie %>% warto zapamiętać skrót klawiszowy w RStudio Ctrl+Shift+M.

Group_by – grupowanie danych

Który kraj produkuje najtańsze wina?
Widzieliśmy już statystyki dla całego zbioru danych, ale warto przyjrzeć się poszczególnym krajom. Do tego celu przyda nam się funkcja group_by() pozwalająca na liczenie statystyk lub tworzenie zmiennych w ramach grup. Stworzymy zestawienie przeciętnych cen wina dla poszczególnych krajów. Zanim zastosujemy funkcję summarise grupujemy dane według kraju (country). Ten jeden krok wystarczy, by otrzymać zestawienie cen per kraj.

wines %>% 
  group_by(country) %>% 
  summarise(median_price_pln = median(price_pln, na.rm = T))
## # A tibble: 44 x 2
##    country                median_price_pln
##    <chr>                             <dbl>
##  1 Argentina                          62.9
##  2 Armenia                            53.6
##  3 Australia                          77.7
##  4 Austria                            92.5
##  5 Bosnia and Herzegovina             46.2
##  6 Brazil                             74.0
##  7 Bulgaria                           48.1
##  8 Canada                            111. 
##  9 Chile                              55.5
## 10 China                              66.6
## # ... with 34 more rows

Otrzymalismy bardzo ładne zestawienie, ale do rzetelnej oceny brakuje nam jeszcze kilku informacji. Oprócz mediany ceny policzymy również średnią ocenę dla win z danego kraju. W końcu nie chcemy kupić wina tylko dlatego, że jest tanie, zależy nam na tym żeby jego jakość była przyzwoita. Dodatkowo odrzucimy kraje, dla których jest mało obserwacji. Funkcja n() zastosowana w summarise() pozwoli nam sprawdzić ile win z danego kraju jest w danych. Nie wszystkie kraje słyną z produkcji tego trunku i trudno uznać np. jedno wino z Chin za reprezentatywną próbę.

wines %>% 
  group_by(country) %>% 
  summarise(median_price_pln = median(price_pln, na.rm = T),
            avg_score = mean(points, na.rm = T),
            n_of_wines = n()) %>% 
  arrange(median_price_pln) %>% 
  filter(n_of_wines >= 20)
## # A tibble: 30 x 4
##    country   median_price_pln avg_score n_of_wines
##    <chr>                <dbl>     <dbl>      <int>
##  1 Romania               33.3      86.4        120
##  2 Bulgaria              48.1      87.9        141
##  3 Moldova               48.1      87.2         59
##  4 Chile                 55.5      86.5       4472
##  5 Portugal              59.2      88.3       5691
##  6 Argentina             62.9      86.7       3800
##  7 Georgia               64.8      87.7         86
##  8 Morocco               66.6      88.6         28
##  9 Spain                 66.6      87.3       6645
## 10 Greece                70.3      87.3        466
## # ... with 20 more rows

Posortowaliśmy wyniki od najtańszych krajów do najdroższych (arrange()) i odrzuciliśmy kraje, które mają poniżej 20 obserwacji (filter()). Wniosek jest jasny, jeżeli chcemy pić smaczne i przystępne cenowo wina wybierajmy te pochodzące z krajów bałkańskich: Rumunii, Bułgarii, Mołdawii.

Inne funkcje pakietu dplyr

Opisałam główne funkcje pakietu dplyr, ale to jeszcze nie jest wszystko. Zwłaszcza na uwagę zasługują dwie grupy funkcji:

… all, if, at

Oprócz standardowych funkcji filter(), select(), rename(), mutate(), group_by() i summarise() występują jeszcze ich wersje z końcówką _all, _if, _at. Do czego służą?

  • _all pozwala zastosować funkcję do wszystkich zmiennych
  • _if pozwala zastosować funkcję tylko do zmiennych spełniających określone kryterium
  • _at pozwala zastosować funkcję do wybranych zmiennych

Przykładowo zamienimy zmienne country, taster_name i variety na factor:

mutate_at(wines, vars(country, taster_name, variety), as.factor)
## # A tibble: 129,971 x 15
##       X1 country  description   designation points price province region_1
##    <int> <fct>    <chr>         <chr>        <int> <dbl> <chr>    <chr>   
##  1     0 Italy    Aromas inclu~ Vulka Bian~     87   NA  Sicily ~ Etna    
##  2     1 Portugal This is ripe~ Avidagos        87   15. Douro    <NA>    
##  3     2 US       Tart and sna~ <NA>            87   14. Oregon   Willame~
##  4     3 US       Pineapple ri~ Reserve La~     87   13. Michigan Lake Mi~
##  5     4 US       Much like th~ Vintner's ~     87   65. Oregon   Willame~
##  6     5 Spain    Blackberry a~ Ars In Vit~     87   15. Norther~ Navarra 
##  7     6 Italy    Here's a bri~ Belsito         87   16. Sicily ~ Vittoria
##  8     7 France   This dry and~ <NA>            87   24. Alsace   Alsace  
##  9     8 Germany  Savory dried~ Shine           87   12. Rheinhe~ <NA>    
## 10     9 France   This has gre~ Les Natures     87   27. Alsace   Alsace  
## # ... with 129,961 more rows, and 7 more variables: region_2 <chr>,
## #   taster_name <fct>, taster_twitter_handle <chr>, title <chr>,
## #   variety <fct>, winery <chr>, price_pln <dbl>

W drugim przykładzie skorzystamy z funkcji str_to_title() z pakietu stringr, aby zmienić kapitalizację we wszystkich nazwach zmiennych z całych zmiennych pisanych małą literą do nazw zaczynających się od wielkiej litery:

rename_all(wines, stringr::str_to_title)
## # A tibble: 129,971 x 15
##       X1 Country  Description   Designation Points Price Province Region_1
##    <int> <chr>    <chr>         <chr>        <int> <dbl> <chr>    <chr>   
##  1     0 Italy    Aromas inclu~ Vulka Bian~     87   NA  Sicily ~ Etna    
##  2     1 Portugal This is ripe~ Avidagos        87   15. Douro    <NA>    
##  3     2 US       Tart and sna~ <NA>            87   14. Oregon   Willame~
##  4     3 US       Pineapple ri~ Reserve La~     87   13. Michigan Lake Mi~
##  5     4 US       Much like th~ Vintner's ~     87   65. Oregon   Willame~
##  6     5 Spain    Blackberry a~ Ars In Vit~     87   15. Norther~ Navarra 
##  7     6 Italy    Here's a bri~ Belsito         87   16. Sicily ~ Vittoria
##  8     7 France   This dry and~ <NA>            87   24. Alsace   Alsace  
##  9     8 Germany  Savory dried~ Shine           87   12. Rheinhe~ <NA>    
## 10     9 France   This has gre~ Les Natures     87   27. Alsace   Alsace  
## # ... with 129,961 more rows, and 7 more variables: Region_2 <chr>,
## #   Taster_name <chr>, Taster_twitter_handle <chr>, Title <chr>,
## #   Variety <chr>, Winery <chr>, Price_pln <dbl>

Joiny

Dplyr oferuje szereg funkcji podonych do SQL-owych joinów, które pozwalają na łączenie ze sobą zbiorów danych. Te funkcje to m.in. left_join(), right_join(), inner_join(), full_join(), union(), intersect(), bind_rows(), ale o tym innym razem.

Cheatsheet

RStudio dplyr cheatsheet

Dplyr oferuje wiele ciekawych funkcji, jednak zapamiętanie ich wszystkich, zwłaszcza na początku może być problemem. Oprócz zawsze przydatnej pomocy w R, przeszukiwania internetu oraz stacka warto sięgnąć po ściągawki, tak zwane cheatsheets, przygotowane przez RStudio i dostępne na ich stronie internetowej:
https://www.rstudio.com/resources/cheatsheets/
Cheatsheet do dplyr:
https://github.com/rstudio/cheatsheets/raw/master/data-transformation.pdf

Najczęściej używane ściągawki warto wydrukować i powiesić przy biurku, a wtedy analizy i przygotowanie danych będzie prawdziwą przyjemnością.

Kolejne kroki

Jak utrwalić uzyskane informacje? Jeszcze nikt nie nauczył się programować i analizować dane od czytania cudzych kodów. Potrzebna jest praktyka, dlatego polecam samodzielne przejście przez kody z poradnika, a następnie własne analizy. Możesz na przykład spróbować samodzielnie odpowiedzieć na poniższe pytania:

  • Ile jest w danych Francuskich win droższych niż $100?
  • Który szczep wingoron (variety) jest najbardziej popularny?
  • Który kraj ma najwięcej win typu “Mavrud”
  • Ile kosztuje najlepiej ocenione Prosecco?
  • Mając budżet $8 po wino jakiego szczepu (variety) najlepiej sięgnąć? Odrzuć szczepy dla których jest mniej niż 20 obserwacji

Postaram się kontynuowac poradnik, tak aby pokazać inne pakiety i funkcje wchodzące w skład tidyverse (np. ggplot2 służący do wizualizacji danych). W przygotowaniu również analogiczny poradnik ale dla pakietu pandas w Pythonie.

Nikt jeszcze nie dodał komentarza, możesz być pierwszy!

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *


Zapytaj o szkolenie

Jestem zainteresowany/a

Podaj wynik działania:


 

Zapytaj o szkolenie zamknięte

Jestem zainteresowany/a

Podaj wynik działania:


 

Zapytaj o szkolenie otwarte
 

Jestem zainteresowany/a

Podaj wynik działania:


 

Zapytaj o ścieżkę szkoleniową
 

Rodzaj ścieżki:

Preferowany tryb szkolenia:

DziennyPopołudniowyWeekendowy

Podaj wynik działania:


 
Szybki kontakt