-
Notifications
You must be signed in to change notification settings - Fork 0
Przekształcanie danych w R
Poniżej zapoznamy się ze sposobami przekształcania danych w R, takimi jak:
- wybieranie wierszy
- wybieranie zmiennych
- zmiana nazw zmiennych
- modyfikowanie / tworzenie nowych zmiennych
- agregacja
- sortowanie
- złączanie kilku zbiorów danych
- przekształcanie między postaciami długą i szeroką
Ćwiczenia będziemy wykonywać na danych prostych grupach danych z bazy IBE - testy oraz wskażniki.
Z tego powodu zaczniemy od:
- załadowania pakietu ZPD
- nawiązania połączenia z bazą danych IBE
- pobrania z bazy grup danych testy oraz wskaźniki
library(ZPD)
src = polacz()
testy = pobierz_testy(src) %>% collect()
wskazniki = pobierz_wskazniki(src) %>% collect()
Dokładne opisy omawianych operacji wraz z przykładami można znaleźć pod tutaj.
Operacje można wykonywać pojedynczo:
mojeDane = operacja1(mojeDane)
mojeDane = operacja2(mojeDane)
Można też łączyć je ze sobą w ciągi używając operatora %>%
:
mojeDane = operacja1(mojeDane) %>%
operacja2()
Tak naprawdę operator %>%
powoduje przekazanie tego, co zastanie po lewej stronie jako pierwszy argument funkcji, którą ma po prawej stronie.
Podczas warsztatów konsekwentnie stosować będziemy składnię z operatorem %>%
.
filter(warunek1, ...)
- warunków może być dowolnie wiele
- łączą się ze sobą przez koniunkcję
- chcąc uzyskać alternatywę łączymy ze sobą warunki operatorem
|
(pojedynczej pionowej kreski) i całość otaczamy nawiasami
- chcąc uzyskać alternatywę łączymy ze sobą warunki operatorem
- dostępne operatory:
-
%in%
zawieranie się w ciągu wartości (braki danych nie spełniają warunku) -
==
tożsamość (uwaga! braki danych spełniają warunek) -
<, >, <=, >=
(uwaga! braki danych spełniają warunek) -
is.na()
- czy brak danych -
grepl(wyrażenie, zmienna)
dopasowanie do wyrażenia regularnego -
!
negacja
-
- stałe logiczne:
-
T
,TRUE
- prawda -
F
,FALSE
- fałsz
-
# wybierzmy tylko testy egzaminacyjne (wyświetli się tylko pierwszych 10):
testy %>% filter(czy_egzamin == TRUE)
## Source: local data frame [297 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu
## 1 572 FALSE S-A1-021 sprawdzian
## 2 573 TRUE S-A1-021 sprawdzian
## 3 579 FALSE S-A1-032 sprawdzian
## 4 580 TRUE S-A1-032 sprawdzian
## 5 586 FALSE S-A1-042 sprawdzian
## 6 587 TRUE S-A1-042 sprawdzian
## 7 593 FALSE S-A1-052 sprawdzian
## 8 594 TRUE S-A1-052 sprawdzian
## 9 1491 FALSE MMA-P1A1P-104 matura poprawkowa
## 10 1567 TRUE GH-A1-042 egzamin gimnazjalny
## .. ... ... ... ...
## Variables not shown: czesc_egzaminu (chr), rok (dbl), data_testu (date),
## czy_egzamin (lgl), opis_testu (chr)
# wybierzmy tylko testy sprawdzianu z 2013 roku:
testy %>% filter(rodzaj_egzaminu == 'sprawdzian', rok == 2013, czy_egzamin == TRUE)
## Source: local data frame [2 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu czesc_egzaminu rok
## 1 1459 FALSE S-A1-132 sprawdzian 2013
## 2 1460 FALSE S-B1-132 sprawdzian 2013
## Variables not shown: data_testu (date), czy_egzamin (lgl), opis_testu
## (chr)
# wybierzmy tylko testy sprawdzianu z lat 2010, 2012
testy %>% filter(rodzaj_egzaminu == 'sprawdzian', rok %in% c(2010, 2012), czy_egzamin == TRUE)
## Source: local data frame [10 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu czesc_egzaminu rok
## 1 634 FALSE S-A1-102 sprawdzian 2010
## 2 635 FALSE S-B1-102 sprawdzian 2010
## 3 636 TRUE S-A1-102 sprawdzian 2010
## 4 637 TRUE S-B1-102 sprawdzian 2010
## 5 652 FALSE S-A1-122 sprawdzian 2012
## 6 653 FALSE S-B1-122 sprawdzian 2012
## 7 654 TRUE S-A1-122 sprawdzian 2012
## 8 655 TRUE S-B1-122 sprawdzian 2012
## 9 1267 TRUE S-?-102 sprawdzian 2010
## 10 1269 TRUE S-?-122 sprawdzian 2012
## Variables not shown: data_testu (date), czy_egzamin (lgl), opis_testu
## (chr)
# wybierzmy tylko testy sprawdzianu po 2013 lub przed 2003 rokiem
testy %>% filter(rodzaj_egzaminu == 'sprawdzian', (rok < 2003 | rok > 2013), czy_egzamin == TRUE)
## Source: local data frame [4 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu czesc_egzaminu rok
## 1 572 FALSE S-A1-021 sprawdzian 2002
## 2 573 TRUE S-A1-021 sprawdzian 2002
## 3 1590 TRUE S-A1-142 sprawdzian 2014
## 4 1591 TRUE S-B1-142 sprawdzian 2014
## Variables not shown: data_testu (date), czy_egzamin (lgl), opis_testu
## (chr)
slice(numery_wierszy)
# wybieramy wiersze od 1 do 5
testy %>% slice(1:5)
## Source: local data frame [5 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu czesc_egzaminu rok
## 1 572 FALSE S-A1-021 sprawdzian 2002
## 2 573 TRUE S-A1-021 sprawdzian 2002
## 3 579 FALSE S-A1-032 sprawdzian 2003
## 4 580 TRUE S-A1-032 sprawdzian 2003
## 5 586 FALSE S-A1-042 sprawdzian 2004
## Variables not shown: data_testu (date), czy_egzamin (lgl), opis_testu
## (chr)
semi_join(zbiórDanych1, zbiórDanych2)
Pozostawione zostaną tylko te wiersze z pierwszego zbioru danych, które występują w drugim.
Porównanie dokonywane jest na podstawie wartości zmiennych istniejących w obydwu zbiorach danych.
# tworzymy zbiór danych, który posłuży nam do odfiltrowania
mojFiltr = data_frame(
arkusz = c('S-A1-102', 'S-B1-102'),
inna_kolumna = c( 1, 2)
)
# i odfiltrowujemy testy za jego pomocą
# (zwróćmy uwagę na komunikat mówiący o tym, na podstawie jakich kolumn dokonano filtrowania)
testy %>% semi_join(mojFiltr)
## Joining by: "arkusz"
## Source: local data frame [4 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu czesc_egzaminu rok
## 1 634 FALSE S-A1-102 sprawdzian 2010
## 2 636 TRUE S-A1-102 sprawdzian 2010
## 3 635 FALSE S-B1-102 sprawdzian 2010
## 4 637 TRUE S-B1-102 sprawdzian 2010
## Variables not shown: data_testu (date), czy_egzamin (lgl), opis_testu
## (chr)
select(kolumna1, ...)
# wybieramy tylko zmienne rodzaj_egzaminu i rok
testy %>% select(rodzaj_egzaminu, rok)
## Source: local data frame [480 x 2]
##
## rodzaj_egzaminu rok
## 1 sprawdzian 2002
## 2 sprawdzian 2002
## 3 sprawdzian 2003
## 4 sprawdzian 2003
## 5 sprawdzian 2004
## 6 sprawdzian 2004
## 7 sprawdzian 2005
## 8 sprawdzian 2005
## 9 matura poprawkowa 2010
## 10 egzamin gimnazjalny 2004
## .. ... ...
rename(nowaNazwa = staraNazwa, ...)
# zmieniamy nazwę kolumny "arkusz" na "arkusz_egzaminacyjny"
# (i wyświetlamy tylko 3 pierwsze wiersze)
testy %>%
rename(arkusz_egzaminacyjny = arkusz) %>%
slice(1:3)
## Source: local data frame [3 x 9]
##
## id_testu dane_ewd arkusz_egzaminacyjny rodzaj_egzaminu czesc_egzaminu
## 1 572 FALSE S-A1-021 sprawdzian
## 2 573 TRUE S-A1-021 sprawdzian
## 3 579 FALSE S-A1-032 sprawdzian
## Variables not shown: rok (dbl), data_testu (date), czy_egzamin (lgl),
## opis_testu (chr)
mutate(nazwaZmiennej1 = definicjaZmiennej1, ...)
W definicji możemy stosować:
- operatory arytmetyczne (
+, -, *, /, ^
) - funkcje operujące na liczbach, np.
mean()
,min()
,max())
,median()
- aby pomijać przy obliczaniu braki danych, należy wywoływać je z parametrem
na.rm = TRUE
- aby pomijać przy obliczaniu braki danych, należy wywoływać je z parametrem
- funkcje operujące na łańcuchach znaków, np.:
-
paste0(zmiennaLubStala1, ...)
- złączanie tekstów -
gsub(wyrazenieRegularne, zamiana, zmienna)
- znajdź i zamień
-
# tworzymy nową zmienną, która przechowuje początkowy rok okresu obejmowanego przez dany wskaźnik
# (i ograniczamy się do wyświetlenia zmiennych wskaznik, okres, rok_od i rok_do)
wskazniki %>%
mutate(rok_od = rok_do - okres + 1) %>%
select(wskaznik, okres, rok_od, rok_do)
## Source: local data frame [210 x 4]
##
## wskaznik okres rok_od rok_do
## 1 paou_gh 1 2013 2013
## 2 paou_gh 1 2012 2012
## 3 paou_gh 1 2010 2010
## 4 paou_gh 1 2009 2009
## 5 paou_gh 1 2008 2008
## 6 paou_gh 1 2007 2007
## 7 paou_gh 1 2006 2006
## 8 paou_gh 1 2005 2005
## 9 paou_gh 1 2004 2004
## 10 paou_gh 1 2003 2003
## .. ... ... ... ...
Jeśli tworzona zmienna będzie się nazywać tak, jak zmienna już istniejąca, wtedy istniejąca zmienna zostanie nadpisana nowymi wartościami (zmodyfikowana).
arrange(zmienna1, ...)
# sortujemy testy po roku
# (ograniczając się do testów egzaminacyjnych)
testy %>%
arrange(rok) %>%
filter(czy_egzamin == TRUE)
## Source: local data frame [297 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu
## 1 572 FALSE S-A1-021 sprawdzian
## 2 573 TRUE S-A1-021 sprawdzian
## 3 716 FALSE GH-A1-021 egzamin gimnazjalny
## 4 717 FALSE GM-A1-021 egzamin gimnazjalny
## 5 579 FALSE S-A1-032 sprawdzian
## 6 580 TRUE S-A1-032 sprawdzian
## 7 718 FALSE GH-A1-031 egzamin gimnazjalny
## 8 719 FALSE GM-A1-031 egzamin gimnazjalny
## 9 586 FALSE S-A1-042 sprawdzian
## 10 587 TRUE S-A1-042 sprawdzian
## .. ... ... ... ...
## Variables not shown: czesc_egzaminu (chr), rok (dbl), data_testu (date),
## czy_egzamin (lgl), opis_testu (chr)
# tak samo, tylko malejąco
testy %>%
arrange(desc(rok)) %>%
filter(czy_egzamin == TRUE)
## Source: local data frame [297 x 9]
##
## id_testu dane_ewd arkusz rodzaj_egzaminu czesc_egzaminu
## 1 1600 TRUE MBI-P1A1P-142 matura biologia podstawowa
## 2 1601 TRUE MBI-R1A1P-142 matura biologia rozszerzona
## 3 1602 TRUE MCH-P1A1P-142 matura chemia podstawowa
## 4 1603 TRUE MCH-R1A1P-142 matura chemia rozszerzona
## 5 1604 TRUE MFA-P1A1P-142 matura fizyka podstawowa
## 6 1605 TRUE MFA-R1A1P-142 matura fizyka rozszerzona
## 7 1606 TRUE MGE-P1A1P-142 matura geografia podstawowa
## 8 1607 TRUE MGE-R1A1P-142 matura geografia rozszerzona
## 9 1608 TRUE MHI-P1A1P-142 matura historia podstawowa
## 10 1590 TRUE S-A1-142 sprawdzian
## .. ... ... ... ... ...
## Variables not shown: rok (dbl), data_testu (date), czy_egzamin (lgl),
## opis_testu (chr)
group_by(zmienna1, ...)
Grupuje zbiór danych wg wartości zadanych zmiennych.
summarize(nazwaZmiennej1 = definicjaZmiennej1)
Tworzy nowy zbiór danych, który:
- będzie zawierać tylko zmienne, wg których dokonano agregacji oraz zmienne zdefiniowane w funkcji
summarize()
- będzie zawierać tylko po jednym wierszu dla każdej grupy.
Definiując nowe zmienne można użyć specjalnej funkcji n()
, która zwraca liczbę obserwacji w danej grupie.
# obliczmy liczbę testów, datę realizacji pierwszego z nich oraz datę realizacji ostatniego
# w podziale na to, czy jest to test egzaminacyjny i rok
testy %>%
group_by(czy_egzamin, rok) %>%
summarize(liczba = n(), pierwszy = min(data_testu), ostatni = max(data_testu))
## Source: local data frame [19 x 5]
## Groups: czy_egzamin
##
## czy_egzamin rok liczba pierwszy ostatni
## 1 FALSE 1900 5 1900-01-01 1900-01-01
## 2 FALSE 2011 44 2011-03-01 2011-03-01
## 3 FALSE 2012 32 2012-03-01 2012-04-25
## 4 FALSE 2013 28 2013-03-01 2013-04-24
## 5 FALSE 2014 54 2014-01-01 2014-11-20
## 6 FALSE 2015 20 2015-02-19 2015-02-20
## 7 TRUE 2002 4 2002-04-10 2002-05-15
## 8 TRUE 2003 4 2003-04-08 2003-05-09
## 9 TRUE 2004 14 2004-04-01 2004-05-06
## 10 TRUE 2005 16 2005-04-05 2005-04-27
## 11 TRUE 2006 16 2006-04-04 2006-04-27
## 12 TRUE 2007 19 2007-04-12 2007-04-25
## 13 TRUE 2008 19 2008-04-08 2008-04-23
## 14 TRUE 2009 19 2009-04-02 2009-04-23
## 15 TRUE 2010 36 2010-04-08 2010-08-01
## 16 TRUE 2011 36 2011-04-05 2011-08-01
## 17 TRUE 2012 42 2012-04-03 2012-08-01
## 18 TRUE 2013 35 2013-04-04 2013-08-01
## 19 TRUE 2014 37 2014-04-01 2014-08-28
Istnieje wiele rodzajów złączeń - patrz http://zpd.ibe.edu.pl/?id=
Złączenia pomiędzy zbiorami danych następują na podstawie wartości zmiennych o tych samych nazwach. Jeśli zmienne w zbiorach danych nazywają się tak samo, ale nie chcemy złączać na podstawie ich wartości, trzeba je przed złączeniem przezwać (np. mamy wyniki dwóch części egzaminu w oddzielnych zbiorach danych, a w każdej z nich w zmienną wynik - przed ich złączeniem należałoby zmienić nazwę przynajmniej jednej ze zmiennych wynik).
Do złączania zbiorów danych służą funkcje:
inner_join(zbiórDanych1, zbiórDanych2)
left_join(zbiórDanych1, zbiórDanych2)
full_join(zbiórDanych1, zbiórDanych2)
Aby pokazać złączanie danych będzie nam potrzebny trochę bardziej złożony przykład. Załóżmy, że mamy dwa zbiory danych - jeden opisuje szkoły, a drugi wyniki uczniów w tych szkołach:
wyniki = data.frame(
id_szkoly = c( 10, 10, 11, 13),
rok = c(2014, 2014, 2014, 2014),
id_obserwacji = c( 100, 101, 102, 103),
id_testu = c( 1, 1, 2, 2),
wynik = c( 13, 15, 9, 8)
)
wyniki
## id_szkoly rok id_obserwacji id_testu wynik
## 1 10 2014 100 1 13
## 2 10 2014 101 1 15
## 3 11 2014 102 2 9
## 4 13 2014 103 2 8
szkoly = data.frame(
id_szkoly = c( 10, 11, 12),
rok = c( 2014, 2014, 2014),
nazwa = c( 'SP nr 1', 'SP nr 2', 'SP nr 3'),
adres = c('Szkolna 10', 'Kopernika 3', 'Konopnickiej 1')
)
szkoly
## id_szkoly rok nazwa adres
## 1 10 2014 SP nr 1 Szkolna 10
## 2 11 2014 SP nr 2 Kopernika 3
## 3 12 2014 SP nr 3 Konopnickiej 1
Jeśli złączymy ze sobą te dwa zbiory danych, złączenie nastąpi na podstawie zmiennych występujących w obydwu zbiorach: id_szkoły oraz rok.
Wynikami tych złączeń będzie:
# uczeń o id_obserwacji 103 został pominięty, bo w danych szkół nie ma szkoły o id_szkoly równym 15
inner_join(wyniki, szkoly)
## id_szkoly rok id_obserwacji id_testu wynik nazwa adres
## 1 10 2014 100 1 13 SP nr 1 Szkolna 10
## 2 10 2014 101 1 15 SP nr 1 Szkolna 10
## 3 11 2014 102 2 9 SP nr 2 Kopernika 3
# uczeń o id_onserwacji 103 pozostał w zbiorze i ma braki danych ze zbioru danych opisujących szkołę
left_join(wyniki, szkoly)
## id_szkoly rok id_obserwacji id_testu wynik nazwa adres
## 1 10 2014 100 1 13 SP nr 1 Szkolna 10
## 2 10 2014 101 1 15 SP nr 1 Szkolna 10
## 3 11 2014 102 2 9 SP nr 2 Kopernika 3
## 4 13 2014 103 2 8 <NA> <NA>
# pojawił się dodatkowo wiersz opisujacy szkołę, która nie posiada uczniów
full_join(wyniki, szkoly)
## id_szkoly rok id_obserwacji id_testu wynik nazwa adres
## 1 10 2014 100 1 13 SP nr 1 Szkolna 10
## 2 10 2014 101 1 15 SP nr 1 Szkolna 10
## 3 11 2014 102 2 9 SP nr 2 Kopernika 3
## 4 13 2014 103 2 8 <NA> <NA>
## 5 12 2014 NA NA NA SP nr 3 Konopnickiej 1
Czasami może się okazać, że niektóre informacje, które w danej chwili przechowywane są w wierszach chcielibyśmy przenieść w kolumny (utworzyć z nich nowe zmienne) lub odwrotnie. Operacje takie nazywamy przekształcaniem danych z postaci długiej do szerokiej oraz z szerokiej do długiej.
Najłatwiej będzie zapoznać się z tym zagadnieniem na przykładach
reshape2::dcast(zbiór_danych, formuła)
Formuła definiuje, wartości których zmiennych przepisane zostaną w nowe zmienne. Ma ona postać:
zmiennaWiersza1 + ... ~ zmiennaWkolumny1 + ...
Np. chcemy obliczyliśmy liczbę wskaźników EWD i PWE w poszczególnych latach:
liczWsk = wskazniki %>%
group_by(rok_do, rodzaj_wsk) %>%
summarize(liczba = n())
liczWsk
## Source: local data frame [19 x 3]
## Groups: rok_do
##
## rok_do rodzaj_wsk liczba
## 1 2002 pwe 3
## 2 2003 pwe 3
## 3 2004 pwe 3
## 4 2005 pwe 3
## 5 2006 pwe 3
## 6 2007 pwe 3
## 7 2008 ewd 2
## 8 2008 pwe 3
## 9 2009 ewd 2
## 10 2009 pwe 3
## 11 2010 ewd 2
## 12 2010 pwe 3
## 13 2011 ewd 2
## 14 2011 pwe 3
## 15 2012 ewd 54
## 16 2012 pwe 3
## 17 2013 ewd 54
## 18 2013 pwe 3
## 19 2014 ewd 58
ale teraz chcielibyśmy, aby poszczególne lata utworzyły nowe zmienne (kolumny), a wiersze wyznaczały jedynie rodzaj wskaźnika.
W tym celu musimy dokonać konwersji z postaci długiej do szerokiej:
liczWsk = reshape2::dcast(liczWsk, rodzaj_wsk ~ rok_do)
## Using liczba as value column: use value.var to override.
liczWsk
## rodzaj_wsk 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
## 1 ewd NA NA NA NA NA NA 2 2 2 2 54 54
## 2 pwe 3 3 3 3 3 3 3 3 3 3 3 3
## 2014
## 1 58
## 2 NA
reshape2::melt(zbiórDanych, id.vars = nazwy_zmiennych_do_pozostawienia, variable.name = nazwaZmiennejNazwy, value.name = nazwaZmiennejWartosci)
Załóżmy teraz, że z jakichś powodów chcemy przywrócić poprzednią postać naszych danych, tzn. przepisać zmienne odpowiadające poszczególnym rocznikom w wiersze jednej zmiennej rok:
liczWsk = reshape2::melt(liczWsk, id.vars = c('rodzaj_wsk'), variable.name = 'rok_do', value.name = 'liczba')
liczWsk
## rodzaj_wsk rok_do liczba
## 1 ewd 2002 NA
## 2 pwe 2002 3
## 3 ewd 2003 NA
## 4 pwe 2003 3
## 5 ewd 2004 NA
## 6 pwe 2004 3
## 7 ewd 2005 NA
## 8 pwe 2005 3
## 9 ewd 2006 NA
## 10 pwe 2006 3
## 11 ewd 2007 NA
## 12 pwe 2007 3
## 13 ewd 2008 2
## 14 pwe 2008 3
## 15 ewd 2009 2
## 16 pwe 2009 3
## 17 ewd 2010 2
## 18 pwe 2010 3
## 19 ewd 2011 2
## 20 pwe 2011 3
## 21 ewd 2012 54
## 22 pwe 2012 3
## 23 ewd 2013 54
## 24 pwe 2013 3
## 25 ewd 2014 58
## 26 pwe 2014 NA