(Acest articol a fost publicat pentru prima dată pe Statforbiologieși cu amabilitate a contribuit la R-bloggeri). (Puteți raporta problema legată de conținutul acestei pagini aici)
Doriți să vă distribuiți conținutul pe R-bloggeri? dați clic aici dacă aveți un blog, sau aici dacă nu aveți.
Este important să știm cum să remodelăm un cadru de date într-o formă care ar putea fi mai potrivită pentru analizele pe care intenționăm să le efectuăm. Pentru mine, este, de asemenea, important să știu cum să fac asta cu baza R, fără a folosi alte pachete. Da, știu că alte pachete, cum ar fi dplyr şi tidyrsunt mult mai bune… Cu toate acestea, a avea abilitățile necesare pentru a ne îndeplini majoritatea sarcinilor zilnice cu baza R poate fi o idee bună. În special, există cel puțin patru sarcini de rutină pe care trebuie să le putem îndeplini:
- subconjunctura
- triere
- turnare
- topire
Subsetarea înseamnă selectarea înregistrărilor (rândurilor) sau a variabilelor (coloanelor) care îndeplinesc anumite criterii. În baza R, putem folosi subset() funcţie.
Să luăm în considerare students setul de date, care este disponibil în statforbiology pachet. Reprezintă o colecție de examene susținute de studenții de la universitatea mea la diferite materii. Să-l încărcăm folosind getAgroData() funcția de la statforbiology pachet.
library(statforbiology)
students <- getAgroData("students")
head(students)
## Id Subject Date Mark Year HighSchool
## 1 1 AGRONOMY 10/06/2002 30 2001 HUMANITIES
## 2 2 AGRONOMY 08/07/2002 24 2001 AGRICULTURE
## 3 3 AGRONOMY 24/06/2002 30 2001 AGRICULTURE
## 4 4 AGRONOMY 24/06/2002 26 2001 HUMANITIES
## 5 5 AGRONOMY 23/01/2003 30 2001 HUMANITIES
## 6 6 AGRONOMY 09/09/2002 28 2001 AGRICULTURE
Să presupunem că vrem un nou set de date care să conțină doar înregistrările în care nota a fost egală sau mai mare de 28 (rețineți că, în Italia, un examen este promovat cu nota minimă de 18, în timp ce nota maximă este 30).
subData <- subset(students, Mark >= 28) head(subData) ## Id Subject Date Mark Year HighSchool ## 1 1 AGRONOMY 10/06/2002 30 2001 HUMANITIES ## 3 3 AGRONOMY 24/06/2002 30 2001 AGRICULTURE ## 5 5 AGRONOMY 23/01/2003 30 2001 HUMANITIES ## 6 6 AGRONOMY 09/09/2002 28 2001 AGRICULTURE ## 11 11 AGRONOMY 09/09/2002 28 2001 SCIENTIFIC ## 17 17 AGRONOMY 10/06/2002 30 2001 HUMANITIES
Să facem totul mai dificil și să extragem înregistrările în care nota variază de la 26 la 28 (marjele incluse). Uită-te la clauza AND, care este exprimată prin utilizarea & operator:
subData <- subset(students, Mark <= 28 & Mark >= 26) head(subData) ## Id Subject Date Mark Year HighSchool ## 4 4 AGRONOMY 24/06/2002 26 2001 HUMANITIES ## 6 6 AGRONOMY 09/09/2002 28 2001 AGRICULTURE ## 7 7 AGRONOMY 24/02/2003 26 2001 HUMANITIES ## 8 8 AGRONOMY 09/09/2002 26 2001 SCIENTIFIC ## 10 10 AGRONOMY 08/07/2002 27 2001 HUMANITIES ## 11 11 AGRONOMY 09/09/2002 28 2001 SCIENTIFIC
Acum suntem interesați de acei studenți care au obținut o notă cuprinsă între 26 și 28 la MATEMATE (vă rugăm să rețineți operatorul de egalitate, scris ca ==):
subData <- subset(students, Mark <= 28 & Mark >= 26 &
Subject == "MATHS")
head(subData)
## Id Subject Date Mark Year HighSchool
## 115 115 MATHS 15/07/2002 26 2001 AGRICULTURE
## 124 124 MATHS 16/09/2002 26 2001 SCIENTIFIC
## 138 138 MATHS 04/02/2002 27 2001 HUMANITIES
## 144 144 MATHS 10/02/2003 27 2001 HUMANITIES
## 145 145 MATHS 04/07/2003 27 2002 HUMANITIES
## 146 146 MATHS 28/02/2002 28 2001 AGRICULTURE
Să căutăm studenți buni care au obținut o notă cuprinsă între 26 și 28 fie la MATEMATE, fie la CHIMIE (propoziție SAU; rețineți că | operator):
subData <- subset(students, Mark <= 28 & Mark >= 26 &
(Subject == "MATHS" |
Subject == "CHEMISTRY"))
head(subData)
## Id Subject Date Mark Year HighSchool
## 68 68 CHEMISTRY 04/06/2002 28 2001 OTHER SCHOOL
## 70 70 CHEMISTRY 04/06/2002 26 2001 ACCOUNTING
## 71 71 CHEMISTRY 04/06/2002 27 2001 AGRICULTURE
## 72 72 CHEMISTRY 23/01/2003 27 2001 SCIENTIFIC
## 75 75 CHEMISTRY 10/07/2002 27 2001 AGRICULTURE
## 81 81 CHEMISTRY 23/01/2003 28 2001 AGRICULTURE
De asemenea, putem selecta coloane; de exemplu, este posibil să dorim să afișăm numai Subject, Markși HighSchool coloane:
subData <- subset(students, Mark <= 28 & Mark >= 26 &
(Subject == "MATHS" |
Subject == "CHEMISTRY"),
select = c(Subject, Mark, HighSchool))
head(subData)
## Subject Mark HighSchool
## 68 CHEMISTRY 28 OTHER SCHOOL
## 70 CHEMISTRY 26 ACCOUNTING
## 71 CHEMISTRY 27 AGRICULTURE
## 72 CHEMISTRY 27 SCIENTIFIC
## 75 CHEMISTRY 27 AGRICULTURE
## 81 CHEMISTRY 28 AGRICULTURE
De asemenea, putem elimina coloanele nedorite:
subData <- subset(students, Mark <= 28 & Mark >= 26 &
(Subject == "MATHS" |
Subject == "CHEMISTRY"),
select = c(-Id,
-Date,
-Year))
head(subData)
## Subject Mark HighSchool
## 68 CHEMISTRY 28 OTHER SCHOOL
## 70 CHEMISTRY 26 ACCOUNTING
## 71 CHEMISTRY 27 AGRICULTURE
## 72 CHEMISTRY 27 SCIENTIFIC
## 75 CHEMISTRY 27 AGRICULTURE
## 81 CHEMISTRY 28 AGRICULTURE
The subset() funcția este foarte ușor de utilizat. Cu toate acestea, am putea avea o flexibilitate mai mare prin utilizarea indicilor pentru subsetare. Știm deja că notația dataframe(i, j) returnează elementul din al-lea rând și j-a coloană a unui cadru de date. Putem, desigur, înlocui i şi j cu unele reguli de subsetare. De exemplu, selectarea examenelor la care nota este între 25 și 29 se face după cum urmează:
subData <- students((students$Mark <= 29 & students$Mark >= 25),) head(subData) ## Id Subject Date Mark Year HighSchool ## 4 4 AGRONOMY 24/06/2002 26 2001 HUMANITIES ## 6 6 AGRONOMY 09/09/2002 28 2001 AGRICULTURE ## 7 7 AGRONOMY 24/02/2003 26 2001 HUMANITIES ## 8 8 AGRONOMY 09/09/2002 26 2001 SCIENTIFIC ## 10 10 AGRONOMY 08/07/2002 27 2001 HUMANITIES ## 11 11 AGRONOMY 09/09/2002 28 2001 SCIENTIFIC
Acest lucru este util pentru editarea rapidă a datelor. De exemplu, dacă vrem să înlocuim toate semnele de la 25 la 29 cu NAs (valori lipsă), putem face pur și simplu:
subData <- students subData((subData$Mark <= 29 & subData$Mark >= 25), "Mark") <- NA head(subData) ## Id Subject Date Mark Year HighSchool ## 1 1 AGRONOMY 10/06/2002 30 2001 HUMANITIES ## 2 2 AGRONOMY 08/07/2002 24 2001 AGRICULTURE ## 3 3 AGRONOMY 24/06/2002 30 2001 AGRICULTURE ## 4 4 AGRONOMY 24/06/2002 NA 2001 HUMANITIES ## 5 5 AGRONOMY 23/01/2003 30 2001 HUMANITIES ## 6 6 AGRONOMY 09/09/2002 NA 2001 AGRICULTURE
Vă rugăm să rețineți că am creat un nou set de date pentru a face înlocuirea, pentru a nu modifica setul de date original. Desigur, pot folosi is.na() pentru a găsi valorile lipsă și pentru a le edita.
subData(is.na(subData$Mark), "Mark") <- 0 head(subData) ## Id Subject Date Mark Year HighSchool ## 1 1 AGRONOMY 10/06/2002 30 2001 HUMANITIES ## 2 2 AGRONOMY 08/07/2002 24 2001 AGRICULTURE ## 3 3 AGRONOMY 24/06/2002 30 2001 AGRICULTURE ## 4 4 AGRONOMY 24/06/2002 0 2001 HUMANITIES ## 5 5 AGRONOMY 23/01/2003 30 2001 HUMANITIES ## 6 6 AGRONOMY 09/09/2002 0 2001 AGRICULTURE
Sortarea este foarte asemănătoare cu subsetarea prin indexare. Trebuie doar să folosim order() funcţie. De exemplu, să sortăm students set de date după marca:
sortedData <- students(order(students$Mark), ) head(sortedData) ## Id Subject Date Mark Year HighSchool ## 51 51 BIOLOGY 01/03/2002 18 2001 HUMANITIES ## 67 67 CHEMISTRY 20/02/2003 18 2002 AGRICULTURE ## 76 76 CHEMISTRY 24/02/2003 18 2002 OTHER SCHOOL ## 79 79 CHEMISTRY 18/06/2003 18 2002 AGRICULTURE ## 82 82 CHEMISTRY 18/07/2002 18 2001 AGRICULTURE ## 83 83 CHEMISTRY 23/01/2003 18 2001 SCIENTIFIC
De asemenea, putem sorta în ordine descrescătoare:
sortedData <- students(order(-students$Mark), ) head(sortedData) ## Id Subject Date Mark Year HighSchool ## 1 1 AGRONOMY 10/06/2002 30 2001 HUMANITIES ## 3 3 AGRONOMY 24/06/2002 30 2001 AGRICULTURE ## 5 5 AGRONOMY 23/01/2003 30 2001 HUMANITIES ## 17 17 AGRONOMY 10/06/2002 30 2001 HUMANITIES ## 18 18 AGRONOMY 10/06/2002 30 2001 AGRICULTURE ## 19 19 AGRONOMY 09/09/2002 30 2001 AGRICULTURE
Putem folosi, evident, mai multe chei. De exemplu, să sortăm după marcaj și, în cadrul fiecărui marcaj, după subiect:
sortedData <- students(order(-students$Mark, students$Subject), ) head(sortedData) ## Id Subject Date Mark Year HighSchool ## 1 1 AGRONOMY 10/06/2002 30 2001 HUMANITIES ## 3 3 AGRONOMY 24/06/2002 30 2001 AGRICULTURE ## 5 5 AGRONOMY 23/01/2003 30 2001 HUMANITIES ## 17 17 AGRONOMY 10/06/2002 30 2001 HUMANITIES ## 18 18 AGRONOMY 10/06/2002 30 2001 AGRICULTURE ## 19 19 AGRONOMY 09/09/2002 30 2001 AGRICULTURE
Dacă vreau să sortez o variabilă caracter (cum ar fi Subject) în ordine descrescătoare, trebuie să folosesc funcția de ajutor xtfrm():
sortedData <- students(order(-students$Mark, -xtfrm(students$Subject)), ) head(sortedData) ## Id Subject Date Mark Year HighSchool ## 116 116 MATHS 01/07/2002 30 2001 OTHER SCHOOL ## 117 117 MATHS 18/06/2002 30 2001 ACCOUNTING ## 118 118 MATHS 09/07/2002 30 2001 AGRICULTURE ## 121 121 MATHS 18/06/2002 30 2001 ACCOUNTING ## 123 123 MATHS 09/07/2002 30 2001 HUMANITIES ## 130 130 MATHS 07/02/2002 30 2001 SCIENTIFIC
Acestea sunt două operații pe care le putem efectua pe întregul cadru de date, pentru a-l remodela din:
- format LUNG spre LARGE (casting)
- Format LARGE până la LUNG (topire)
În baza R, folosim aceeași funcție și anume reshape()care a fost inițial adaptat nevoilor de gestionare a datelor longitudinale. Deși terminologia provine din acest cadru conceptual original (care este destul de confuz la început), puteți utiliza această funcție pentru orice tip de date care trebuie remodelate de la LUNG la LAT sau invers.
S-ar putea să fim familiarizați cu funcția „tabel pivot” din Excel, care remodelează un set de date din formatul LONG în formatul WIDE. De exemplu, să luăm rimsulfuron setul de date în statforbiology pachet, care conține rezultatele unui experiment în blocuri conceput pentru a compara 16 erbicide pentru combaterea buruienilor la porumb. Setul de date este în format LONG, cu un rând pentru fiecare diagramă și observațiile făcute în fiecare diagramă enumerate în coloane diferite.
rimsulfuron <- getAgroData("rimsulfuron")
head(rimsulfuron)
## Herbicide Plot Code Block Column WeedCover Yield
## 1 Rimsulfuron (40) 1 1 1 1 27.8 85.91
## 2 Rimsulfuron (45) 2 2 1 1 27.8 93.03
## 3 Rimsulfuron (50) 3 3 1 1 23.0 86.93
## 4 Rimsulfuron (60) 4 4 1 1 42.8 52.99
## 5 Rimsulfuron (50+30 split) 5 5 1 1 15.1 71.36
## 6 Rimsulfuron + thyfensulfuron 6 6 1 1 22.9 75.28
Să punem acest cadru de date în format WIDE, astfel încât să avem cele 16 erbicide pe rânduri diferite, iar observațiile pentru fiecare erbicid sunt enumerate în coloane diferite, cu o coloană separată pentru fiecare bloc (cu condiția să avem o singură observație per erbicid în fiecare bloc, ceea ce este cazul aici). În baza R, putem folosi reshape() functioneaza cu direction = "wide". Practic, trebuie să specificăm ce variabilă ar trebui să identifice rândurile (în cazul nostru, idvar = "Herbicide") și care variabilă identifică diferitele seturi de observații (în cazul nostru, timevar = "Block"). Numele timevar arată că această funcție a fost inițial adaptată nevoilor de date longitudinale. Inițial, trebuie să subsetăm cadrul de date pentru a reține doar coloanele pe care trebuie să le afișam în tabelul final, deși putem folosi și drop argument pentru a exclude variabilele pe care nu intenționăm să le folosim.
castData <- reshape(
rimsulfuron(, c("Herbicide", "Block", "Yield")),
direction = "wide",
idvar = "Herbicide",
timevar = "Block"
)
castData
## Herbicide Yield.1 Yield.2 Yield.3 Yield.4
## 1 Rimsulfuron (40) 85.91 91.09 111.42 93.15
## 2 Rimsulfuron (45) 93.03 105.00 89.19 79.04
## 3 Rimsulfuron (50) 86.93 105.82 110.02 89.10
## 4 Rimsulfuron (60) 52.99 102.86 100.62 97.04
## 5 Rimsulfuron (50+30 split) 71.36 77.57 115.91 92.16
## 6 Rimsulfuron + thyfensulfuron 75.28 82.59 94.96 85.85
## 7 Rimsulfuron + hoeing 73.22 86.06 118.01 98.32
## 8 Pendimethalin (pre) + rimsulfuron (post) 65.51 88.72 95.52 82.39
## 9 Pendimethalin (post) + rimsuulfuron (post) 94.82 87.72 102.05 101.94
## 10 Rimsulfuron + Atred 94.11 89.86 104.34 99.63
## 11 Thifensulfuron 78.47 42.32 62.52 24.34
## 12 Metolachlor + terbuthylazine (pre) 51.77 52.10 49.46 34.67
## 13 Alachlor + terbuthylazine 12.06 49.58 41.34 16.37
## 14 Hand-Weeded 77.58 92.08 86.59 99.63
## 15 Unweeded 1 10.88 31.77 23.92 20.85
## 16 Unweeded 2 27.58 51.55 25.13 38.61
The reshape() funcția poate fi folosită și pentru a transforma un set de date din formatul WIDE în LONG prin setarea direction = "long" argument. Pentru această sarcină, să folosim WeedPop setul de date în statforbiology pachet, care raportează rezultatele unui studiu de buruieni care a implicat șase specii în nouă condiții (literele de la A la I din Code variabilă). Unitatea experimentală este starea și, pentru fiecare condiție, acoperirea solului celor șase specii este raportată în coloane diferite.
Acum, dorim să remodelăm acest cadru de date astfel încât să avem un rând pentru fiecare combinație de specii și condiție, cu acoperirea solului listată într-o singură coloană. Pentru a utiliza reshape() funcție, trebuie să ne gândim la acest tabel ca și cum ar reprezenta date longitudinale, cu măsurători repetate luate în momente diferite pe același subiect (id). Astfel, valorile care se modifică odată cu „timpul” (the varying variabile) sunt cele conținute în setul de date original în coloanele 2 până la 7. Aceste variabile vor fi combinate într-o singură coloană în setul de date nou creat, pe care îl vom denumi WeedCover (v.names = "WeedCover").
Acum, trebuie să adăugăm cel puțin alte două variabile la acest set de date nou creat. Primul reprezintă subiectele (idvar) și trebuie să conțină codurile conținute în WeedPop$Code coloana (ids = WeedPop$Code). Vom numi această variabilă Code (idvar = "Code").
A doua variabilă trebuie să conțină numele variabilelor originale (times = colnames(WeedPop(2:7))) corespunzătoare observaţiilor luate pentru fiecare subiect. Putem atribui un nume acestei variabile nou create folosind timevar = "Weed name".
WeedPop <- getAgroData("WeedPop")
WeedPop
## Code POLLA CHEPO ECHCG AMARE XANST POLAV
## 1 A 0.1 33 11 0 0.1 0.1
## 2 B 0.1 3 3 0 0.1 0.0
## 3 C 7.0 19 19 4 7.0 1.0
## 4 D 18.0 3 28 19 12.0 6.0
## 5 E 5.0 7 28 3 10.0 1.0
## 6 F 11.0 9 33 7 10.0 6.0
## 7 G 8.0 13 33 6 15.0 15.0
## 8 H 18.0 5 33 4 19.0 12.0
## 9 I 6.0 6 38 3 10.0 6.0
mdati <- reshape(
WeedPop,
direction = "long",
varying = colnames(WeedPop(2:7)),
v.names = "WeedCover",
times = colnames(WeedPop(2:7)),
timevar = "Weed name",
ids = WeedPop$Code,
idvar = "Code",
)
head(mdati)
## Code Weed name WeedCover
## A.POLLA A POLLA 0.1
## B.POLLA B POLLA 0.1
## C.POLLA C POLLA 7.0
## D.POLLA D POLLA 18.0
## E.POLLA E POLLA 5.0
## F.POLLA F POLLA 11.0
Trebuie să recunosc că aceste funcții nu sunt deosebit de intuitive de utilizat și funcțiile corespunzătoare din pachetele ‘dplyr’ și ‘tidyr’ pot fi mai ușor de utilizat. Cu toate acestea, îmi place ca studenții mei să cunoască bine baza R înainte de a trece la alte dialecte
Distrează-te lucrând cu aceste funcții! Dacă aveți comentarii, vă rog să-mi trimiteți o notă la adresa de mai jos.
Și… nu uitați să verificați noua mea carte!
prof. Andrea Onofri
Departamentul de Științe Agricole, Alimentare și de Mediu
Universitatea din Perugia (Italia)
Trimite comentarii la: (e-mail protejat)

Această postare a fost publicată inițial pe 2019-03-27
