R symbole i operatory data.table, które powinieneś znać

Kod R data.table staje się bardziej wydajny - i elegancki - gdy wykorzystuje się jego specjalne symbole i funkcje. Mając to na uwadze, przyjrzymy się specjalnym sposobom podzbioru, liczenia i tworzenia nowych kolumn.

W tym pokazie wykorzystam dane z ankiety dla programistów Stack Overflow 2019, z około 90000 odpowiedziami. Jeśli chcesz kontynuować, możesz pobrać dane ze Stack Overflow.

Jeśli pakiet data.table nie jest zainstalowany w twoim systemie, zainstaluj go z CRAN, a następnie załaduj jak zwykle z library(data.table). Na początek możesz przeczytać tylko kilka pierwszych wierszy zestawu danych, aby ułatwić zbadanie struktury danych. Możesz to zrobić za pomocą fread()funkcji data.table i nrowsargumentu. Przeczytam w 10 wierszach:

data_sample <- fread ("data / survey_results_public.csv", nrows = 10)

Jak zobaczysz, do zbadania jest 85 kolumn. (Jeśli chcesz wiedzieć, co oznaczają wszystkie kolumny, do pobrania są pliki ze schematem danych i plikiem PDF oryginalnej ankiety). 

Aby wczytać wszystkie dane, użyję:

mydt <- fread ("data / survey_results_public.csv")

Następnie utworzę nową tabelę data.table z zaledwie kilkoma kolumnami, aby ułatwić pracę i przeglądanie wyników. Przypomnienie, że data.table używa następującej podstawowej składni: 

mydt [i, j, by]

We wprowadzeniu do pakietu data.table czytamy to jako „weź dt, podzbiór lub zmień kolejność wierszy przy użyciu i, oblicz j, pogrupuj według”. Pamiętaj, że i i j są podobne do kolejności w nawiasach podstawy R: najpierw wiersze, potem kolumny. Więc i jest dla operacji wykonywanych na wierszach (wybieranie wierszy na podstawie numerów wierszy lub warunków); j jest tym, co zrobiłbyś z kolumnami (wybierz kolumny lub utwórz nowe kolumny na podstawie obliczeń). Należy jednak zauważyć, że wewnątrz nawiasów data.table można zrobić o wiele więcej niż podstawowa ramka danych R. Sekcja „by” jest nowością w data.table.

Ponieważ wybieram kolumny, ten kod jest umieszczany w miejscu „j”, co oznacza, że ​​nawiasy wymagają najpierw przecinka, aby miejsce „i” było puste:

mydt [, j]

Wybierz kolumny data.table

Jedną z rzeczy, które lubię w data.table jest to, że łatwo jest wybrać kolumny z cudzysłowami lub bez . Brak cudzysłowu jest często wygodniejszy (zwykle jest to uporządkowany sposób). Jednak cytowanie jest przydatne, jeśli używasz data.table we własnych funkcjach lub jeśli chcesz przekazać wektor utworzony w innym miejscu w kodzie.

Kolumny data.table można wybierać w typowy podstawowy sposób R, z konwencjonalnym wektorem nazw kolumn w cudzysłowach. Na przykład: 

dt1 <- mydt [, c ("LanguageWorkedWith", "LanguageDesireNextYear",

„OpenSourcer”, „CurrencySymbol”, „ConvertedComp”,

„Hobbysta”)]

Jeśli chcesz używać ich bez cudzysłowów, utwórz listę zamiast wektora i możesz przekazać niecytowane nazwy. 

dt1 <- mydt [, list (LanguageWorkedWith, LanguageDesireNextYear,

OpenSourcer, CurrencySymbol, ConvertedComp,

Hobbysta)]

A teraz dochodzimy do naszego pierwszego specjalnego symbolu. Zamiast pisać list(), możesz po prostu użyć kropki:

dt1 <- mydt [,. (LanguageWorkedWith, LanguageDesireNextYear,

OpenSourcer, CurrencySymbol, ConvertedComp,

Hobbysta)]

To .()jest skrót do list()wewnętrznych nawiasów data.table.

A co, jeśli chcesz użyć już istniejącego wektora nazw kolumn? Umieszczenie nazwy obiektu wektorowego w nawiasach data.table nie zadziała. Jeśli utworzę wektor z nazwami kolumn w cudzysłowach, na przykład: 

mycols <- c ("LanguageWorkedWith", "LanguageDesireNextYear",

„OpenSourcer”, „CurrencySymbol”, „ConvertedComp”, „Hobbyist”)

Wtedy ten kod  nie zadziała: 

dt1 <- mydt [, mykole]

Zamiast tego musisz umieścić .. (to dwie kropki) przed nazwą obiektu wektorowego:

dt1 <- mydt [, ..mycols]

Dlaczego dwie kropki? Wydawało mi się to przypadkowe, dopóki nie przeczytałem wyjaśnienia. Pomyśl o tym jak o dwóch kropkach w Unixowym terminalu wiersza poleceń, które przenoszą cię o jeden katalog w górę. Tutaj przesuwasz się w górę o jedną przestrzeń nazw , od środowiska wewnątrz nawiasów data.table do środowiska globalnego. (To naprawdę pomaga mi to zapamiętać!)

Policz wiersze data.table

Przejdźmy do następnego symbolu. Aby liczyć według grup, możesz użyć .Nsymbolu data.table , gdzie  .Noznacza „liczbę wierszy”. Może to być łączna liczba wierszy lub liczba wierszy na grupę, jeśli agregujesz w sekcji „według”. 

To wyrażenie zwraca całkowitą liczbę wierszy w data.table: 

mydt [, .N]

Poniższy przykład oblicza liczbę wierszy pogrupowanych według jednej zmiennej: czy osoby w ankiecie również kodują jako hobby ( Hobbyistzmienna).

mydt [, .N, hobbysta]

# zwroty:

Hobbysta N 1: Tak 71257 2: Nie 17626

Możesz użyć zwykłej nazwy kolumny w nawiasach data.table, jeśli jest tylko jedna zmienna. Jeśli chcesz pogrupować według dwóch lub więcej zmiennych, użyj .symbolu. Na przykład:

mydt [, .N,. (Hobbysta, OpenSourcer)]

Aby uporządkować wyniki od najwyższego do najniższego, możesz dodać drugi zestaw nawiasów po pierwszym. .NSymbol automatycznie generuje kolumnę o nazwie N (oczywiście można ją zmienić, jeśli chcesz), więc zamawianie przez liczbę wierszy może wyglądać mniej więcej tak:

mydt [, .N,. (Hobbyist, OpenSourcer)] [order (Hobbist, -N)]

Gdy uczę się kodu data.table, pomocne jest czytanie go krok po kroku. Więc przeczytałem to jako „Dla wszystkich wierszy w mydt (ponieważ nie ma nic w miejscu„ I ”), policz liczbę wierszy, grupując według Hobbyist i OpenSourcer. Następnie uporządkuj najpierw według Hobbyist, a następnie liczbę wierszy malejąco. ” 

To odpowiednik tego kodu dplyr:

mydf%>%

count (hobbysta, OpenSourcer)%>%

zamówienie (hobbysta, -n)

Jeśli uznasz, że konwencjonalne podejście wieloliniowe tidyverse jest bardziej czytelne, ten kod data.table również działa:

mydt [, .N,

. (Hobbysta, OpenSourcer)] [

zamówienie (hobbysta, -N)

]

Dodaj kolumny do data.table

Następnie chciałbym dodać kolumny, aby zobaczyć, czy każdy respondent używa języka R, czy używa Pythona, czy używa obu, czy też żadnego. LanguageWorkedWithKolumna ma informacji o językach używanych, a kilka rzędów tych danych wygląda następująco:

Sharon Machlis

Każda odpowiedź to pojedynczy ciąg znaków. Większość ma wiele języków oddzielonych średnikiem.

Jak to często bywa, łatwiej jest szukać Pythona niż R, ponieważ nie można po prostu wyszukać „R” w łańcuchu (Ruby i Rust również zawierają duże R) tak, jak można wyszukiwać „Python”. To jest prostszy kod do tworzenia wektora TRUE / FALSE, który sprawdza, czy każdy ciąg w LanguageWorkedWithzawiera Pythona:

ifelse (LanguageWorkedWith% jak% "Python", TRUE, FALSE)

Jeśli znasz SQL, rozpoznasz składnię „lubienia”. Cóż, podoba mi %like%. się to przyjemny, usprawniony sposób sprawdzania dopasowania wzorców. Dokumentacja funkcji mówi, że ma być używana w nawiasach data.table, ale w rzeczywistości możesz jej użyć w dowolnym kodzie, nie tylko z danymi.tables. Sprawdziłem u twórcy data.table Matta Dowle'a, który powiedział, że rada używania go w nawiasach jest taka, że ​​zachodzi tam dodatkowa optymalizacja wydajności.

Dalej, oto kod dodający kolumnę o nazwie PythonUser do data.table:

dt1 [, PythonUser: = ifelse (LanguageWorkedWith% jak% "Python", TRUE, FALSE)]

Zwróć uwagę na :=operatora. Python też ma taki operator i odkąd usłyszałem, że nazywa się „operatorem morsa”, tak to nazywam. Myślę, że oficjalnie jest to „zadanie przez odniesienie”. Dzieje się tak, ponieważ powyższy kod zmienił istniejący obiekt dt1 data.table, dodając nową kolumnę - bez konieczności zapisywania go w nowej zmiennej .

Aby wyszukać R, użyję wyrażenia regularnego, "\\bR\\b"które mówi: „Znajdź wzorzec zaczynający się od granicy słowa - the \\b, następnie an R, a następnie zakończony inną granicą słowa. (Nie mogę po prostu szukać „R;”, ponieważ ostatni element w każdym ciągu nie ma średnika). 

To dodaje kolumnę RUser do dt1:

dt1 [, RUser: = ifelse (LanguageWorkedWith% like% "\\ bR \\ b", TRUE, FALSE)]

Jeśli chciałbyś dodać obie kolumny jednocześnie :=, musiałbyś zamienić ten operator morsa w funkcję, umieszczając ją w cudzysłowie, na przykład:

dt1 [, `: =` (

PythonUser = ifelse (LanguageWorkedWith% jak% "Python", TRUE, FALSE),

RUser = ifelse (LanguageWorkedWith% jak% "\\ bR \\ b", TRUE, FALSE)

)]

Bardziej przydatne operatory data.table

Jest kilka innych operatorów tabeli data.table, o których warto wiedzieć. %between% Operator ma składnię:

myvector% między% c (dolna_wartość, górna_wartość)

Jeśli więc chcę odfiltrować wszystkie odpowiedzi, w których odszkodowanie wynosiło od 50 000 do 100 000 w dolarach amerykańskich, ten kod działa:

comp_50_100k <- dt1 [CurrencySymbol == "USD" &

ConvertedComp% między% c (50000, 100000)]

Druga linia powyżej to warunek pośredni. Zwróć uwagę, że %between%podczas sprawdzania operator uwzględnia zarówno dolną, jak i górną wartość.

Innym użytecznym operatorem jest %chin%. Działa jak podstawowe R, %in%ale jest zoptymalizowany pod kątem szybkości i jest przeznaczony tylko dla wektorów znaków . Tak więc, jeśli chcę filtrować dla wszystkich wierszy, w których kolumna OpenSourcer była „Nigdy” lub „Rzadziej niż raz w roku”, ten kod działa:

rzadkie <- dt1 [OpenSourcer% chin% c ("Nigdy", "Rzadziej niż raz w roku")]

Jest to bardzo podobne do podstawy R, z tym wyjątkiem, że podstawa R musi określać nazwę ramki danych wewnątrz nawiasu, a także wymaga przecinka po wyrażeniu filtru:

rzadkos_df <- df1 [df1 $ OpenSourcer% in% c ("Nigdy", "Rzadziej niż raz w roku"),]

Nowa funkcja fcase ()

Na potrzeby tego końcowego demo zacznę od utworzenia nowej tabeli data.table zawierającej tylko osoby, które zgłosiły wynagrodzenie w dolarach amerykańskich:

usd <- dt1 [CurrencySymbol == "USD" &! is.na (ConvertedComp)]

Następnie utworzę nową kolumnę o nazwie, Languageaby sprawdzić, czy ktoś używa tylko R, tylko Pythona, obu, czy żadnego. I użyję nowej fcase()funkcji. W momencie publikacji tego artykułu był fcase()dostępny tylko w wersji rozwojowej data.table. Jeśli masz już zainstalowany data.table, możesz zaktualizować program do najnowszej wersji za pomocą tego polecenia: 

data.table :: update.dev.pkg ()

Funkcja fcase () jest podobna do instrukcji SQL CASE WHENi case_when()funkcji dplyr . Podstawowa składnia to  fcase(condition1, "value1", condition2, "value2")i tak dalej. Za pomocą można dodać domyślną wartość „wszystkiego innego” default = value.

Oto kod do utworzenia nowej kolumny Język:

usd [, Język: = fcase (

RUser &! PythonUser, "R",

PythonUser &! RUser, "Python",

PythonUser & RUser, "Both",

! PythonUser &! RUser, „Ani”

)]

Każdy warunek umieściłem w osobnym wierszu, ponieważ jest dla mnie łatwiejszy do odczytania, ale nie musisz.

Przestroga: jeśli używasz RStudio, struktura data.table nie jest automatycznie aktualizowana w prawym górnym okienku RStudio po utworzeniu nowej kolumny z operatorem morsa. Aby zobaczyć zmiany w liczbie kolumn, musisz ręcznie kliknąć ikonę odświeżania.

Jest kilka innych symboli, których nie omówię w tym artykule. Możesz znaleźć ich listę w pliku pomocy data.table „symboli specjalnych”, uruchamiając help("special-symbols"). Jeden z najbardziej użytecznych, .SD, ma już własny artykuł „Do More With R” i film „Jak używać .SD w pakiecie R data.table”.

Aby uzyskać więcej wskazówek dotyczących języka R, przejdź na stronę „Zrób więcej z R” lub sprawdź listę odtwarzania YouTube „Zrób więcej z R”.