Programmering

R data.table symboler og operatorer, du bør kende

R data.table-kode bliver mere effektiv - og elegant - når du drager fordel af dens specielle symboler og funktioner. Med det i tankerne vil vi se på nogle specielle måder at undergruppe, tælle og oprette nye kolonner på.

Til denne demo skal jeg bruge data fra 2019 Stack Overflow-udviklerundersøgelsen med omkring 90.000 svar. Hvis du vil følge med, kan du downloade dataene fra Stack Overflow.

Hvis data.table-pakken ikke er installeret på dit system, skal du installere den fra CRAN og derefter indlæse den som normalt med bibliotek (data.table). For at starte kan det være en god idé at læse i de første par rækker af datasættet for at gøre det lettere at undersøge datastrukturen. Du kan gøre det med data.table's fread () funktion og nrows argument. Jeg læser i 10 rækker:

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

Som du vil se, er der 85 kolonner at undersøge. (Hvis du vil vide, hvad alle kolonnerne betyder, er der filer i download med dataskema og en PDF af den oprindelige undersøgelse.)

For at læse alle data ind bruger jeg:

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

Derefter opretter jeg en ny data.tabel med kun et par kolonner for at gøre det lettere at arbejde med og se resultater. En påmindelse om, at data.table bruger denne grundlæggende syntaks:

mydt [i, j, by]

Data.table-pakkeintroduktionen siger at læse dette som "tag dt, delmængde eller omarranger rækker ved hjælp af i, beregne j, grupperet efter." Husk, at i og j svarer til rækkefølgen af ​​base R's parentes: række først, kolonner anden. Så jeg er til operationer, du vil udføre på rækker (vælge rækker baseret på række numre eller betingelser); j er hvad du ville gøre med kolonner (vælg kolonner eller opret nye kolonner ud fra beregninger). Bemærk dog også, at du kan gøre meget mere inden for data.table-parenteser end en base R-dataramme. Og afsnittet "ved" er nyt for data.table.

Siden jeg er vælge kolonner, denne kode går i "j" stedet, hvilket betyder, at parenteserne først har brug for et komma for at lade "i" stedet være tomt:

mydt [, j]

Vælg datatabelkolonner

En af de ting, jeg kan lide ved data.table, er, at det er let at vælge kolonner enten citeret eller ikke citeret. Ikke citeret er ofte mere praktisk (det er normalt den tidyverse måde). Men citeret er nyttigt, hvis du bruger data.table i dine egne funktioner, eller hvis du vil passere i en vektor, du oprettede et andet sted i din kode.

Du kan vælge datatabelkolonner den typiske basis-R-måde med en konventionel vektor af citerede kolonnenavne. For eksempel:

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

"OpenSourcer", "CurrencySymbol", "ConvertedComp",

"Hobbyist")]

Hvis du vil bruge dem unciteret, opret en liste i stedet for en vektor og du kan videregive de ikke-citerede navne.

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

OpenSourcer, CurrencySymbol, ConvertedComp,

Hobbyist)]

Og nu kommer vi til vores første specielle symbol. I stedet for at skrive ud liste(), kan du bare bruge en prik:

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

OpenSourcer, CurrencySymbol, ConvertedComp,

Hobbyist)]

At .() er en genvej til liste() indvendige data. tabel parenteser.

Hvad hvis du vil bruge en allerede eksisterende vektor med kolonnenavne? At sætte vektorobjektnavnet i data.table-parenteser fungerer ikke. Hvis jeg opretter en vektor med citerede kolonnenavne, sådan:

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

"OpenSourcer", "CurrencySymbol", "ConvertedComp", "Hobbyist")

Så vil denne kodeikke arbejde:

dt1 <- mydt [, mycols]

I stedet skal du sætte .. (det er to prikker) foran vektorobjektnavnet:

dt1 <- mydt [, ..mycols]

Hvorfor to prikker? Det virkede lidt tilfældigt for mig, indtil jeg læste forklaringen. Tænk på det som de to prikker i en Unix kommandolinjeterminal, der flytter dig op ad en mappe. Her rykker du op en navneområde, fra miljøet inde i data.table parenteser til det globale miljø. (Det hjælper mig virkelig med at huske det!)

Tæl data.tabelrækker

Gå til næste symbol. For at tælle efter gruppe kan du bruge data.table's .N symbol, hvor.N står for "antal rækker". Det kan være det samlede antal rækker eller antallet af rækker pr. gruppe hvis du aggregerer i afsnittet "efter".

Dette udtryk returnerer det samlede antal rækker i data.table:

mydt [, .N]

Følgende eksempel beregner antallet af rækker grupperet efter en variabel: om folk i undersøgelsen også koder som en hobby ( Hobbyist variabel).

mydt [, .N, hobbyist]

# vender tilbage:

Hobbyist N 1: Ja 71257 2: Nej 17626

Du kan bruge det almindelige kolonnenavn inden for data.table-parenteser, hvis der kun er en variabel. Hvis du vil gruppere efter to eller flere variabler, skal du bruge . symbol. For eksempel:

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

For at bestille resultater fra højeste til laveste kan du tilføje et andet sæt parentes efter den første. Det .N symbol genererer automatisk en kolonne med navnet N (selvfølgelig kan du omdøbe det, hvis du vil), så rækkefølge efter antallet af rækker kan se sådan ud:

mydt [, .N,. (Hobbyist, OpenSourcer)] [ordre (Hobbyist, -N)]

Når jeg lærer data.table-kode, finder jeg det nyttigt at læse det trin for trin. Så jeg læste dette som "For alle rækker i mydt (da der ikke er noget i "I" stedet), tæller antallet af rækker, grupperet efter Hobbyist og OpenSourcer. Bestil derefter først af hobbyist og derefter antallet af rækker nedad. ”

Det svarer til denne dplyr-kode:

mydf%>%

antal (Hobbyist, OpenSourcer)%>%

ordre (hobbyist, -n)

Hvis du finder den tidyverse konventionelle multi-line tilgang mere læsbar, fungerer denne data.table kode også:

mydt [, .N,

. (Hobbyist, OpenSourcer)] [

ordre (hobbyist, -N)

]

Føj kolonner til en datatabel

Dernæst vil jeg tilføje kolonner for at se, om hver respondent bruger R, hvis de bruger Python, hvis de bruger begge, eller hvis de bruger ingen af ​​dem. Det SprogWorkedWith kolonne har oplysninger om anvendte sprog, og et par rækker af disse data ser sådan ud:

Sharon Machlis

Hvert svar er en enkelt tegnstreng. De fleste har flere sprog adskilt af et semikolon.

Som det ofte er tilfældet, er det lettere at søge efter Python end R, da du ikke bare kan søge efter "R" i strengen (Ruby og Rust indeholder også en stor R), som du kan søge efter "Python". Dette er den enklere kode til at oprette en SAND / FALSK vektor, der kontrollerer, om hver streng er i SprogWorkedWith indeholder Python:

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

Hvis du kender SQL, vil du genkende den "ligesom" syntaks. Jeg kan godt lide %synes godt om%. Det er en flot strømlinet måde at kontrollere, om mønster matcher. Funktionsdokumentationen siger, at det er beregnet til at blive brugt inde i data.table-parenteser, men faktisk kan du bruge det i en hvilken som helst af din kode, ikke kun med data.tables. Jeg tjekkede med data.table-skaberen Matt Dowle, der sagde, at rådet til at bruge det inden for parenteserne er, fordi der sker en ekstra ydelsesoptimering der.

Herefter er her kode for at tilføje en kolonne kaldet PythonUser til data.table:

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

Læg mærke til := operatør. Python har også en sådan operatør, og lige siden jeg hørte det kaldes "hvalrosoperatør", kalder jeg det. Jeg synes, det er officielt "opgave med reference." Det skyldes, at koden ovenfor ændrede det eksisterende objekt dt1-data. Tabel ved at tilføje den nye kolonne - uden har brug for at gemme det i en ny variabel.

For at søge efter R bruger jeg det regulære udtryk "\ bR \ b" der siger: ”Find et mønster, der starter med en ordgrænse - \ b, derefter en R, og slut derefter med en anden ordgrænse. (Jeg kan ikke bare kigge efter "R", fordi det sidste element i hver streng ikke har et semikolon.)

Dette tilføjer en RUser-kolonne til dt1:

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

Hvis du vil tilføje begge kolonner på én gang med := du bliver nødt til at omdanne den hvalrossoperator til en funktion ved at tilbagestille den på denne måde:

dt1 [, `:=`(

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

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

)]

Mere nyttige data.table-operatører

Der er flere andre data.table-operatører, der er værd at vide. Det%mellem% operatør har denne syntaks:

myvector% mellem% c (nedre værdi, øvre værdi)

Så hvis jeg vil filtrere efter alle svar, hvor kompensationen var mellem 50.000 og 100.000 betalt i amerikanske dollars, fungerer denne kode:

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

ConvertedComp% mellem% c (50000, 100000)]

Den anden linje ovenfor er tilstanden mellem. Bemærk, at %mellem% operatøren inkluderer både den nedre og den øvre værdi, når den kontrollerer.

En anden nyttig operatør er %hage%. Det fungerer som base R'er %i% men er optimeret til hastighed og er til kun tegnvektorer. Så hvis jeg vil filtrere efter alle rækker, hvor OpenSourcer-kolonnen enten var "Aldrig" eller "Mindre end en gang om året" fungerer denne kode:

rareos <- dt1 [OpenSourcer% chin% c ("Aldrig", "Mindre end en gang om året")]

Dette svarer stort set til base R, bortset fra at base R skal angive datarammenavnet inde i beslaget og også kræver et komma efter filterudtrykket:

rareos_df <- df1 [df1 $ OpenSourcer% i% c ("Aldrig", "Mindre end en gang om året"),]

Den nye fcase () funktion

Til denne sidste demo begynder jeg med at oprette en ny data.tabel med kun personer, der rapporterede kompensation i amerikanske dollars:

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

Derefter opretter jeg en ny kolonne kaldet Sprog for om nogen bruger bare R, bare Python, begge eller ingen af ​​dem. Og jeg bruger det nye fcase () fungere. På det tidspunkt, hvor denne artikel blev offentliggjort, fcase () var kun tilgængelig i data.tables udviklingsversion. Hvis du allerede har data.table installeret, kan du opdatere til den seneste dev-version med denne kommando:

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

Funktionen fcase () svarer til SQL'er SAG NÅR erklæring og dplyr's case_when () fungere. Den grundlæggende syntaks erfcase (betingelse1, "værdi1", betingelse2, "værdi2") og så videre. En standardværdi for "alt andet" kan tilføjes med standard = værdi.

Her er kode for at oprette den nye sprogkolonne:

usd [, sprog: = fcase (

RUser &! PythonUser, "R",

PythonUser &! RUser, "Python",

PythonUser & RUser, "Begge",

! PythonUser &! RUser, "hverken"

)]

Jeg sætter hver betingelse på en separat linje, fordi jeg finder det lettere at læse, men det behøver du ikke.

En advarsel: Hvis du bruger RStudio, opdateres data.table-strukturen ikke automatisk i øverste højre RStudio-rude, når du opretter en ny kolonne med hvalrosoperatøren. Du skal manuelt klikke på opdateringsikonet for at se ændringer i antallet af kolonner.

Der er et par andre symboler, som jeg ikke vil dække i denne artikel. Du kan finde en liste over dem i "specialsymboler" data.table hjælpefilen ved at køre hjælp ("special-symboler"). En af de mest nyttige .SD har allerede sin egen Do More With R-artikel og video, "Sådan bruges .SD i R data.table-pakken."

For flere R-tip, gå til siden "Gør mere med R" på eller tjek YouTube-playlisten "Gør mere med R".