diff --git a/warsztat 2016.10.10/warsztat_2016.10.10.Rmd b/warsztat 2016.10.10/warsztat_2016.10.10.Rmd index 071d625..7780391 100644 --- a/warsztat 2016.10.10/warsztat_2016.10.10.Rmd +++ b/warsztat 2016.10.10/warsztat_2016.10.10.Rmd @@ -263,244 +263,6 @@ setdiff(x, y) setdiff(y, x) ``` -# Pętla for() - -Pętla `for` w R działa zupełnie inaczej, niż w języku C (i pochodnych) oraz językach o podobnej do C składni (np. Javie)! Działa jednak bardzo podobnie do tego, jak w Pythonie. W wywołaniu pętli wskazujemy nazwę zmiennej, której kolejno (w kolejnych obiegach pętli) nadawane będą wartości kolejnych elementów zadanego wektora. Pętla zostanie (co do zasady) wykonana zostanie więc tyle razy, ile elementów ma podany wektor. Przykładowo: - -```{r comment="", prompt=TRUE, collapse=TRUE} -for (i in 1:5) { - print(i) -} -``` - -W każdym obiegu pętli zmienna `i` była jednoelementowym wektorem - kolejnymi wartościami z sekwencji `1:5`. Aby wyświetlić na konsoli jej wartości musieliśmy w tym przypadku użyć funkcji `print()` - pętla sama z siebie nie zwraca nic na konsolę. - -W ramach pętli możemy też oczywiście wykorzystać inne zmiene, zdefiniowane poza pętlą. Poniższy kod oblicza sumę wartości wektora `x` (dla weryfikacji poprawności porównamy efekt działania pętli z wartością zwracaną przez funkcję `sum()`). - -```{r comment="", prompt=TRUE, collapse=TRUE} -x = 10:20 -xSuma = 0 -for (i in x) { - xSuma = xSuma + i -} -xSuma -sum(x) -``` - ---- - -# Funkcje - -Jeśli jakiś fragment kodu będziemy chcieli wykonywać wielokrotnie, użyteczne jest *opakowanie* go w funkcję. Pozwoli to zaoszczędzić nam wiele pisania (albo kopiowania), uczyni nasz kod bez porównania bardziej przejrzystym i mniej podatnym na błędy. Podzas tego kursu będziemy zajmować się pisaniem jedynie bardzo prostych funkcji, nie martwiąc się ani ich dokumentowaniem, ani czynieniem ich odpornymi na potencjalne próby niewłaściwego użycia. - -Aby zdefiniować w R funkcję używa się składni: - -```{r eval = FALSE, comment="", prompt=TRUE, collapse=TRUE} -nazwa_funkcji = function (argument1, argument2) { - tu_jakiś_kod_który_robi_to_co_trzeba - - return(zwracanyObiekt) -} -``` - -Jeśli wykonamy w konsoli kod zawierający taką definicję funkcji, będziemy mogli jej potem używać w dalszej części naszego kodu. - -Przykłady bardzo prostych funkcji: - -```{r comment="", prompt=TRUE, collapse=TRUE} -# funkcja, która zwraca dokładnie to, co podano jej jako argument -ToSamo = function(x) { - return(x) -} -ToSamo(1:5) - -# "opakujmy" w funkcję naszą pętlę obliczającą sumę elementów wektora -SumujElementy = function(x) { - xSuma = 0 - for (i in x) { - xSuma = xSuma + i - } - return(xSuma) -} -SumujElementy(1:20) -sum(1:20) -``` - ---- - -#### Konwencja nazewnicza: - -Pisząc kod dobrze jest stosować konwencje nazewnicze, czyli reguły nadawania obiektom nazw w zależności od ich rodzaju i przeznaczenia (np. [Google's R Style Guide](https://google.github.io/styleguide/Rguide.xml)). W szczególności dobrze jest móc łatwo stwierdzić na podstawie nazwy obiektu, czy jest on zmienną (np. wektorem) czy funkcją. - -Niestety dobry zwyczaj stosowania konwencji nazewniczych jest wynalazkiem typowo informatycznym i w przeszłości raczej nie był praktykowany przez statystyków - efektem jest przerażający brak spójności w zakresie sposobu nazywania funkcji w ramach podstawowego zestawu pakietów R. Tworząc własny kod nie kultywujmy tej niechlubnej tradycji! - -**Na naszych zajęciach będziemy stosować następującą konwencję nazywania obiektów:** - - 1. Nie używamy polskich znaków. - 2. Nazwy wszystkich obiektów piszemy w konwencji *camel case*. - 3. Nazwy zmiennych zaczynamy małą literą, np. `x`, `mojaZmiena`, `innaMojaZmienna`. - 4. Nazwy funkcji zaczynamy wielką literą, np. `Funkcja`, `JakasFunkcja`, `JeszczeInnaFunkcja`. - ---- - -# Konstrukcje warunkowe - -Czasem chcemy aby w zależności od tego, jaką wartość logiczną przyjmie warunek określony w odniesieniu do pewnej zmiennej, wykonany został inny fragment kodu. Służy do tego konstrukcja `if ()`. Funkcja poniżej wykorzystuje tego typu konstrukcję, aby zwrócić orientacyjny stan jajka na podstawie liczby minut, przez które jajko było gotowane. - -```{r comment="", prompt=TRUE, collapse=TRUE} -# funkcja, która zwraca dokładnie to, co podano jej jako argument -GotujeJajko = function(liczbaMinut) { - if (liczbaMinut < 4) { - stan = "niedogotowane" - } else if (liczbaMinut < 6 ) { - stan = "na miękko" - } else if (liczbaMinut < 8.5) { - stan = "półtwarde" - } else { - stan = "na twardo" - } - return(stan) -} -GotujeJajko(7) -``` - -# Parametry rozkładu zmiennej - -Poniżej przypomnimy sobie definicje podstaowywch parametrów opisujących poziom oraz zróżnicowanie wartości zmienych statystycznych. Twoim zadaniem będzie zaimplementowanie obliczania tych parametrów w postaci funkcji. Możesz przy tym korzystać tylko z funkcji, które zostały wspomniane w tekście powyżej (w szczególności `sort()` i `length()`), pętli *for* oraz konstrukcji warunkowych *if-else*. - -## Parametry poziomu wartości - -### Minimum i maksimum - -W bloku kodu poniżej zdefiniuj funkcję "Minimum", która zwróci najmniejszą wartość przyjmowaną przez elementy wektora, przekazanego jej jako argument. Wiersze poniżej pozwalają przetestować poprawność działania Twojej funkcji, porównując wyniki, jakie zwraca dla trzech przykładowych wektorów z wynikami zaimplementowanej w R funkcji `min()`. - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -Minimum = function(x) { - # to jest miejsce na Twój kod -} -x = c(2, 3, 2, 2, 1) -y = c(97, 3, 4, 3, 3, 1) -z = c(10, 2, 4, 2, 1, 5) -Minimum(x) == min(x) # 1 -Minimum(y) == min(y) # 1 -Minimum(z) == min(z) # 1 -``` - -W podobny sposób zdefiniuj funkcję "Maksimum". - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -Maksimum = function(x) { - # to jest miejsce na Twój kod -} -Maksimum(x) == max(x) # 3 -Maksimum(y) == max(y) # 97 -Maksimum(z) == max(z) # 10 -``` - -### Średnia arytmetyczna - -Średnią arytmetyczną możemy obliczyć sumując wartości elementów wektora i następnie dzieląc uzyskaną sumę przez liczbę elementów. Zaimplementuj ten sposób obliczania średniej w funkcji o nazwie "Srednia". - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -Srednia = function(x) { - # to jest miejsce na Twój kod -} -Srednia(x) == mean(x) # 2 -Srednia(y) == mean(y) # 18.5 -Srednia(z) == mean(z) # 4 -``` - -### Mediana - -Mediana to taka wartość, że co najmniej połowa analizowanych jednostek ma wartość nie wyższą od niej i jednocześnie co najmniej połowa analizowanych jednostek ma wartość nie mniejszą od niej. Okazuje się, że wartości spełniające ten dosyć skomplikowany warunek dosyć łatwo jest określić. - - - W sytuacji, gdy liczba analizowanych jednostek jest nieparzysta, jest to wartość, którą przyjmuje *środkowa* jednostka, jeśli ustawimy je w kolejności według wartości danej zmiennej. - - W sytuacji, gdy liczba analizowanych jednostek jest parzysta, medianą jest każda wartość (liczba rzeczywista) z przedziału, którego granice wyznaczają wartości tych dwóch obserwacji, które, jeśli ustawimy je w kolejności według wartości danej zmiennej, stoją *obok środka*. - - Oznacza to, że jeśli te dwie jednostki mają różne wartości analizowanej zmiennej, to wartości będących medianą jest nieskończenie wiele. W praktyce chcemy jednak zwykle wybrać jedną z nich - typowo stosowaną regułą takiego ujednoznacznienia jest zwracanie jako mediany średniej z wartości wyznaczających granice przedziału (taka reguła jest też zaimplementowana w dostęnej w R funkcji `median()`). - -W bloku kodu poniżej zdefiniuj funkcję "Mediana" zwracającą wartość mediany zadanego wektora, wykorzystując opisane powyżej reguły (w tym sposób ustalenia jednej wartości, która zostanie zwrócona w sytuacji, gdy medianą rozkładu jest wiele wartości) i strukturę warunkową `if() {} else {}`. - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -Mediana = function(x) { - # to jest miejsce na Twój kod -} -Mediana(x) == median(x) # 2 -Mediana(y) == median(y) # 3 -Mediana(z) == median(z) # 3 -``` - -## Parametry rozproszenia - -### Rozstęp - -Rozstęp to różnica pomiędzy maksimum a minimum. W bloku kodu poniżej zdefiniuj funkcję "Rozstęp", która wykorzystując napisane przez Ciebie wcześniej funkcje `Maksimum()` i `Minimum()` obliczy i zwróci wartość rozstępu dla wektora przekazanego jej jako argument. - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -Rozstep = function(x) { - # to jest miejsce na Twój kod -} -Rozstep(x) == 2 -Rozstep(y) == 96 -Rozstep(z) == 9 -``` - -### Wariancja i odchylenie standardowe - -Wariancja i odchylenie standardowe to najczęściej wykorzystywane parametry opisujące zróżnicowanir wartości zmiennych mierzonych na skalach przedziałowych (lub mocniejszych). Odgrywają też centralną rolę w wielu technikach analizy zależności pomiędzy zmiennymi (analiza wariancji, korelacja liniowa, regresja). Wariancję obliczamy jako średnią kwadratów różnic pomiędzy wartością zmiennej dla danej jednostki obserwacji a średnią danego rozkładu. - -Odchylenie standardowe to pierwiastek kwadratowy z wariancji. Posługiwanie się nim jest o tyle użyteczne, że jest ono wyrażone w tej samej jednostce, co mierzona zmienna (wariancja jest mianowana w jednostce mierzonej zmiennej podniesinej do kwadratu). - -Wykorzystując zdefiniowaną wcześniej przez siebie funkcje `Srednia()` zaimplementuj poniżej funkcję "Wariancja" zwracającą wartość wariancji dla wektora podanego jako jej argument. Następnie, wykorzystując ją zdefiniuj też funkcję "OdchylenieStandardowe". - -Uwaga! Typowo dostępne w programach (i ogólniej bibliotekach) statystycznych funkcje służące obliczaniu wariancji zwracają nie opisany powyżej parametr opisowy, ale nieobciążony estymator wariancji populacyjnej obliczany przy założeniu, że zadane przez nas wartości są prostą próbą losową! Tak też zachowują się dostępne w R funkcje `var()` i `sd()`. Stąd aby wykorzystać je do weryfikacji poprawności działania naszej funkcji, musimy wcześniej przekształcić zwracane przez nie wyniki. - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -Wariancja = function(x) { - # to jest miejsce na Twój kod -} -Wariancja(x) == (var(x) * (length(x) - 1) / length(x)) # 0.4 -Wariancja(y) == (var(y) * (length(y) - 1) / length(y)) # 1233.25 -Wariancja(z) == (var(z) * (length(z) - 1) / length(z)) # 9 - -OdchylenieStandardowe = function(x) { - # to jest miejsce na Twój kod -} -``` - -### Współczynnik zmienności - -W przypadku niektórych zmiennych (dokładnie: tych mierzonych na skalach ilorazowych) bardziej użyteczną praktycznie miarą zróżnicowania jest współczynnik zmienności, którego wartość otzrymujemy dzieląc odchylenia standardowe przez średnią danego rozkładu. W efekcie uzyskujemy współczynnik niemianowany (bez jednostki), którego wartości można porównywać nawet pomiędzy zmiennymi mierzonymi w różnych jednostkach. Jednakże aby obliczanie współczynnika zmienności miało sens, mierzona zmienna musi być mierzona na skali olorazowej i nie może przyjmować wartości ujemnych. - -Zaimplementuj poniżej funkcję "WspolczynnikZmiennosci" zwracającą wartość współczynnika zmieności dla wektora podanego jako jej argument. Wykorzystaj zdefiniowane wcześniej przez siebie funkcje `Srednia()` i `OdchylenieStandardowe()`. - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -WspolczynnikZmiennosci = function(x) { - # to jest miejsce na Twój kod -} -round(WspolczynnikZmiennosci(x), 6) == 0.353553 -round(WspolczynnikZmiennosci(y), 6) == 2.079431 -round(WspolczynnikZmiennosci(z), 6) == 0.821584 -``` - -### Odchylenia przeciętne (od mediany) - -Odchylenie przeciętne (od mediany) obliczane jest jako średnia modułów różnic pomiędzy wartością zmiennej dla danej jednostki obserwacji a medianą. Zaimplementuj poniżej funkcję "OdchyleniePrzecietne" zwracającą wartość odchylenia przeciętnego dla wektora podanego jako jej argument. Wykorzystaj zdefiniowaną wcześniej przez siebie funkcję `Srednia()`. - -```{r eval=FALSE, comment="", prompt=TRUE, collapse=TRUE} -OdchyleniePrzecietne = function(x) { - # to jest miejsce na Twój kod -} -OdchyleniePrzecietne(x) == 0.4 -OdchyleniePrzecietne(y) == (16 + 1/6) -OdchyleniePrzecietne(z) == (2 + 1/3) -``` - -# Na następne zajęcia - -## Praca domowa - -Jeśli w czasie zajęć nie udało Ci się zaimplementować wpostaci funkcji wszystkich opisanych wyżej parametrów, dokończ to w domu. **Plik *.Rmd zawierający skończone ćwiczenie prześlij na adres zoltakt@is.uw.edu.pl** (zrób to również, jeśli udało Ci się skończyć w trakcie zajęć). - ## Do przeczytania na następne zajęcia [G. Lissowski, J. Haman i M. Jasiński. (2011). Podstawy statystyki dla socjologów. Wyd. II poprawione. Warszawa: Wydawnictwo Naukowe SCHOLAR.](http://libra.ibuk.pl/book/145985) - Rozdział 2. (w serwisie IBUK Libra dostępna za pośrednictwem konta czytelnika BUW). diff --git a/warsztat 2016.10.10/warsztat_2016.10.10.html b/warsztat 2016.10.10/warsztat_2016.10.10.html index 3bee291..415ba87 100644 --- a/warsztat 2016.10.10/warsztat_2016.10.10.html +++ b/warsztat 2016.10.10/warsztat_2016.10.10.html @@ -133,25 +133,6 @@
Pętla for
w R działa zupełnie inaczej, niż w języku C (i pochodnych) oraz językach o podobnej do C składni (np. Javie)! Działa jednak bardzo podobnie do tego, jak w Pythonie. W wywołaniu pętli wskazujemy nazwę zmiennej, której kolejno (w kolejnych obiegach pętli) nadawane będą wartości kolejnych elementów zadanego wektora. Pętla zostanie (co do zasady) wykonana zostanie więc tyle razy, ile elementów ma podany wektor. Przykładowo:
> for (i in 1:5) {
-+ print(i)
-+ }
-[1] 1
-[1] 2
-[1] 3
-[1] 4
-[1] 5
-W każdym obiegu pętli zmienna i
była jednoelementowym wektorem - kolejnymi wartościami z sekwencji 1:5
. Aby wyświetlić na konsoli jej wartości musieliśmy w tym przypadku użyć funkcji print()
- pętla sama z siebie nie zwraca nic na konsolę.
W ramach pętli możemy też oczywiście wykorzystać inne zmiene, zdefiniowane poza pętlą. Poniższy kod oblicza sumę wartości wektora x
(dla weryfikacji poprawności porównamy efekt działania pętli z wartością zwracaną przez funkcję sum()
).
> x = 10:20
-> xSuma = 0
-> for (i in x) {
-+ xSuma = xSuma + i
-+ }
-> xSuma
-[1] 165
-> sum(x)
-[1] 165
-Jeśli jakiś fragment kodu będziemy chcieli wykonywać wielokrotnie, użyteczne jest opakowanie go w funkcję. Pozwoli to zaoszczędzić nam wiele pisania (albo kopiowania), uczyni nasz kod bez porównania bardziej przejrzystym i mniej podatnym na błędy. Podzas tego kursu będziemy zajmować się pisaniem jedynie bardzo prostych funkcji, nie martwiąc się ani ich dokumentowaniem, ani czynieniem ich odpornymi na potencjalne próby niewłaściwego użycia.
-Aby zdefiniować w R funkcję używa się składni:
-> nazwa_funkcji = function (argument1, argument2) {
-+ tu_jakiś_kod_który_robi_to_co_trzeba
-+
-+ return(zwracanyObiekt)
-+ }
-Jeśli wykonamy w konsoli kod zawierający taką definicję funkcji, będziemy mogli jej potem używać w dalszej części naszego kodu.
-Przykłady bardzo prostych funkcji:
-> # funkcja, która zwraca dokładnie to, co podano jej jako argument
-> ToSamo = function(x) {
-+ return(x)
-+ }
-> ToSamo(1:5)
-[1] 1 2 3 4 5
->
-> # "opakujmy" w funkcję naszą pętlę obliczającą sumę elementów wektora
-> SumujElementy = function(x) {
-+ xSuma = 0
-+ for (i in x) {
-+ xSuma = xSuma + i
-+ }
-+ return(xSuma)
-+ }
-> SumujElementy(1:20)
-[1] 210
-> sum(1:20)
-[1] 210
-Pisząc kod dobrze jest stosować konwencje nazewnicze, czyli reguły nadawania obiektom nazw w zależności od ich rodzaju i przeznaczenia (np. Google’s R Style Guide). W szczególności dobrze jest móc łatwo stwierdzić na podstawie nazwy obiektu, czy jest on zmienną (np. wektorem) czy funkcją.
-Niestety dobry zwyczaj stosowania konwencji nazewniczych jest wynalazkiem typowo informatycznym i w przeszłości raczej nie był praktykowany przez statystyków - efektem jest przerażający brak spójności w zakresie sposobu nazywania funkcji w ramach podstawowego zestawu pakietów R. Tworząc własny kod nie kultywujmy tej niechlubnej tradycji!
-Na naszych zajęciach będziemy stosować następującą konwencję nazywania obiektów:
-x
, mojaZmiena
, innaMojaZmienna
.Funkcja
, JakasFunkcja
, JeszczeInnaFunkcja
.Czasem chcemy aby w zależności od tego, jaką wartość logiczną przyjmie warunek określony w odniesieniu do pewnej zmiennej, wykonany został inny fragment kodu. Służy do tego konstrukcja if ()
. Funkcja poniżej wykorzystuje tego typu konstrukcję, aby zwrócić orientacyjny stan jajka na podstawie liczby minut, przez które jajko było gotowane.
> # funkcja, która zwraca dokładnie to, co podano jej jako argument
-> GotujeJajko = function(liczbaMinut) {
-+ if (liczbaMinut < 4) {
-+ stan = "niedogotowane"
-+ } else if (liczbaMinut < 6 ) {
-+ stan = "na miękko"
-+ } else if (liczbaMinut < 8.5) {
-+ stan = "półtwarde"
-+ } else {
-+ stan = "na twardo"
-+ }
-+ return(stan)
-+ }
-> GotujeJajko(7)
-[1] "półtwarde"
-Poniżej przypomnimy sobie definicje podstaowywch parametrów opisujących poziom oraz zróżnicowanie wartości zmienych statystycznych. Twoim zadaniem będzie zaimplementowanie obliczania tych parametrów w postaci funkcji. Możesz przy tym korzystać tylko z funkcji, które zostały wspomniane w tekście powyżej (w szczególności sort()
i length()
), pętli for oraz konstrukcji warunkowych if-else.
W bloku kodu poniżej zdefiniuj funkcję “Minimum”, która zwróci najmniejszą wartość przyjmowaną przez elementy wektora, przekazanego jej jako argument. Wiersze poniżej pozwalają przetestować poprawność działania Twojej funkcji, porównując wyniki, jakie zwraca dla trzech przykładowych wektorów z wynikami zaimplementowanej w R funkcji min()
.
> Minimum = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> x = c(2, 3, 2, 2, 1)
-> y = c(97, 3, 4, 3, 3, 1)
-> z = c(10, 2, 4, 2, 1, 5)
-> Minimum(x) == min(x) # 1
-> Minimum(y) == min(y) # 1
-> Minimum(z) == min(z) # 1
-W podobny sposób zdefiniuj funkcję “Maksimum”.
-> Maksimum = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> Maksimum(x) == max(x) # 3
-> Maksimum(y) == max(y) # 97
-> Maksimum(z) == max(z) # 10
-Średnią arytmetyczną możemy obliczyć sumując wartości elementów wektora i następnie dzieląc uzyskaną sumę przez liczbę elementów. Zaimplementuj ten sposób obliczania średniej w funkcji o nazwie “Srednia”.
-> Srednia = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> Srednia(x) == mean(x) # 2
-> Srednia(y) == mean(y) # 18.5
-> Srednia(z) == mean(z) # 4
-Mediana to taka wartość, że co najmniej połowa analizowanych jednostek ma wartość nie wyższą od niej i jednocześnie co najmniej połowa analizowanych jednostek ma wartość nie mniejszą od niej. Okazuje się, że wartości spełniające ten dosyć skomplikowany warunek dosyć łatwo jest określić.
-median()
).W bloku kodu poniżej zdefiniuj funkcję “Mediana” zwracającą wartość mediany zadanego wektora, wykorzystując opisane powyżej reguły (w tym sposób ustalenia jednej wartości, która zostanie zwrócona w sytuacji, gdy medianą rozkładu jest wiele wartości) i strukturę warunkową if() {} else {}
.
> Mediana = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> Mediana(x) == median(x) # 2
-> Mediana(y) == median(y) # 3
-> Mediana(z) == median(z) # 3
-Rozstęp to różnica pomiędzy maksimum a minimum. W bloku kodu poniżej zdefiniuj funkcję “Rozstęp”, która wykorzystując napisane przez Ciebie wcześniej funkcje Maksimum()
i Minimum()
obliczy i zwróci wartość rozstępu dla wektora przekazanego jej jako argument.
> Rozstep = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> Rozstep(x) == 2
-> Rozstep(y) == 96
-> Rozstep(z) == 9
-Wariancja i odchylenie standardowe to najczęściej wykorzystywane parametry opisujące zróżnicowanir wartości zmiennych mierzonych na skalach przedziałowych (lub mocniejszych). Odgrywają też centralną rolę w wielu technikach analizy zależności pomiędzy zmiennymi (analiza wariancji, korelacja liniowa, regresja). Wariancję obliczamy jako średnią kwadratów różnic pomiędzy wartością zmiennej dla danej jednostki obserwacji a średnią danego rozkładu.
-Odchylenie standardowe to pierwiastek kwadratowy z wariancji. Posługiwanie się nim jest o tyle użyteczne, że jest ono wyrażone w tej samej jednostce, co mierzona zmienna (wariancja jest mianowana w jednostce mierzonej zmiennej podniesinej do kwadratu).
-Wykorzystując zdefiniowaną wcześniej przez siebie funkcje Srednia()
zaimplementuj poniżej funkcję “Wariancja” zwracającą wartość wariancji dla wektora podanego jako jej argument. Następnie, wykorzystując ją zdefiniuj też funkcję “OdchylenieStandardowe”.
Uwaga! Typowo dostępne w programach (i ogólniej bibliotekach) statystycznych funkcje służące obliczaniu wariancji zwracają nie opisany powyżej parametr opisowy, ale nieobciążony estymator wariancji populacyjnej obliczany przy założeniu, że zadane przez nas wartości są prostą próbą losową! Tak też zachowują się dostępne w R funkcje var()
i sd()
. Stąd aby wykorzystać je do weryfikacji poprawności działania naszej funkcji, musimy wcześniej przekształcić zwracane przez nie wyniki.
> Wariancja = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> Wariancja(x) == (var(x) * (length(x) - 1) / length(x)) # 0.4
-> Wariancja(y) == (var(y) * (length(y) - 1) / length(y)) # 1233.25
-> Wariancja(z) == (var(z) * (length(z) - 1) / length(z)) # 9
->
-> OdchylenieStandardowe = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-W przypadku niektórych zmiennych (dokładnie: tych mierzonych na skalach ilorazowych) bardziej użyteczną praktycznie miarą zróżnicowania jest współczynnik zmienności, którego wartość otzrymujemy dzieląc odchylenia standardowe przez średnią danego rozkładu. W efekcie uzyskujemy współczynnik niemianowany (bez jednostki), którego wartości można porównywać nawet pomiędzy zmiennymi mierzonymi w różnych jednostkach. Jednakże aby obliczanie współczynnika zmienności miało sens, mierzona zmienna musi być mierzona na skali olorazowej i nie może przyjmować wartości ujemnych.
-Zaimplementuj poniżej funkcję “WspolczynnikZmiennosci” zwracającą wartość współczynnika zmieności dla wektora podanego jako jej argument. Wykorzystaj zdefiniowane wcześniej przez siebie funkcje Srednia()
i OdchylenieStandardowe()
.
> WspolczynnikZmiennosci = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> round(WspolczynnikZmiennosci(x), 6) == 0.353553
-> round(WspolczynnikZmiennosci(y), 6) == 2.079431
-> round(WspolczynnikZmiennosci(z), 6) == 0.821584
-Odchylenie przeciętne (od mediany) obliczane jest jako średnia modułów różnic pomiędzy wartością zmiennej dla danej jednostki obserwacji a medianą. Zaimplementuj poniżej funkcję “OdchyleniePrzecietne” zwracającą wartość odchylenia przeciętnego dla wektora podanego jako jej argument. Wykorzystaj zdefiniowaną wcześniej przez siebie funkcję Srednia()
.
> OdchyleniePrzecietne = function(x) {
-+ # to jest miejsce na Twój kod
-+ }
-> OdchyleniePrzecietne(x) == 0.4
-> OdchyleniePrzecietne(y) == (16 + 1/6)
-> OdchyleniePrzecietne(z) == (2 + 1/3)
-Jeśli w czasie zajęć nie udało Ci się zaimplementować wpostaci funkcji wszystkich opisanych wyżej parametrów, dokończ to w domu. **Plik .Rmd zawierający skończone ćwiczenie prześlij na adres zoltakt@is.uw.edu.pl* (zrób to również, jeśli udało Ci się skończyć w trakcie zajęć).
-G. Lissowski, J. Haman i M. Jasiński. (2011). Podstawy statystyki dla socjologów. Wyd. II poprawione. Warszawa: Wydawnictwo Naukowe SCHOLAR. - Rozdział 2. (w serwisie IBUK Libra dostępna za pośrednictwem konta czytelnika BUW).
diff --git a/warsztat 2016.10.17/dane_2016.10.17.RData b/warsztat 2016.10.17/dane_2016.10.17.RData new file mode 100644 index 0000000..13f988c Binary files /dev/null and b/warsztat 2016.10.17/dane_2016.10.17.RData differ diff --git a/warsztat 2016.10.17/warsztat_2016.10.17.Rmd b/warsztat 2016.10.17/warsztat_2016.10.17.Rmd new file mode 100644 index 0000000..1b35fde --- /dev/null +++ b/warsztat 2016.10.17/warsztat_2016.10.17.Rmd @@ -0,0 +1,487 @@ +--- +title: "Statystyka I z RNa dzisiejszych zajęciach zapoznamy się z używaniem macierzy. Poznamy też funkcję table()
, przy pomocy której będziemy tworzyć rozkłady zmiennych. Poznamy też sposób tworzenia prostych tabel w Rmarkdown i wizualizowania (dyskretnych) rozkładów zmiennych.
Macierze to dwuwymiarowe struktury danych składające się z elementów tego samego typu. Możemy wykorzystywać je m. in. do reprezentowania macierzy danych, rozkładów łączynych lub rodzin rozkładów warunkowych.
+Macierz możemy utworzyć korzystając z funkcji matrix()
, która jako pierwszy argument przyjmuje wektor wartości, którymi chcemy wypełnić macierz. Liczbę wierszy i kolumn macierzy podajemy korzystając z argumentów odpowiednio nrow
i ncol
.
> x = matrix(1:16, nrow = 4)
+> x
+ [,1] [,2] [,3] [,4]
+[1,] 1 5 9 13
+[2,] 2 6 10 14
+[3,] 3 7 11 15
+[4,] 4 8 12 16
+> str(x)
+ int [1:4, 1:4] 1 2 3 4 5 6 7 8 9 10 ...
+> matrix(1:16, nrow = 2)
+ [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
+[1,] 1 3 5 7 9 11 13 15
+[2,] 2 4 6 8 10 12 14 16
+> matrix(1:16, ncol = 2)
+ [,1] [,2]
+[1,] 1 9
+[2,] 2 10
+[3,] 3 11
+[4,] 4 12
+[5,] 5 13
+[6,] 6 14
+[7,] 7 15
+[8,] 8 16
+Zwróćmy uwagę, że macierz wypełniana jest kolejno kolumnami. Gdybyśmy z jakichś powodów chcieli wypełniać ją wierszami, możemy wykorzystać argument byrow
.
> matrix(letters[1:16], nrow = 2)
+ [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
+[1,] "a" "c" "e" "g" "i" "k" "m" "o"
+[2,] "b" "d" "f" "h" "j" "l" "n" "p"
+> matrix(letters[1:16], nrow = 2, byrow = TRUE)
+ [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
+[1,] "a" "b" "c" "d" "e" "f" "g" "h"
+[2,] "i" "j" "k" "l" "m" "n" "o" "p"
+Jeśli chcemy całą macierz wypełnić tą samą wartością, wystarczy, że jako pierwszy argument podamy tą pojedynczą wartość (wektor jedoelementowy). O ile nie chcemy uzyskać macierzy 1x1, musimy oczywiście w takim przypadku podać zarówno argument nrow
jak i ncol
.
> matrix(10, nrow = 2, ncol = 3)
+ [,1] [,2] [,3]
+[1,] 10 10 10
+[2,] 10 10 10
+> matrix(FALSE, nrow = 5, ncol = 3)
+ [,1] [,2] [,3]
+[1,] FALSE FALSE FALSE
+[2,] FALSE FALSE FALSE
+[3,] FALSE FALSE FALSE
+[4,] FALSE FALSE FALSE
+[5,] FALSE FALSE FALSE
+Wierszom i kolumnom macierzy możemy nadać nazwy, korzystając z funkcji rownames()
i colnames()
(możemy też zrobić to w ramach funkcji matrix()
, ale nie będziemy teraz o tym mówić, jako że wymagałoby to użycia struktury danych, której jeszcze nie poznaliśmy - listy). Wykorzystuje się przy tym nieco dziwaczną składnię:
> x = matrix(1:15, nrow = 5)
+> x
+ [,1] [,2] [,3]
+[1,] 1 6 11
+[2,] 2 7 12
+[3,] 3 8 13
+[4,] 4 9 14
+[5,] 5 10 15
+> # póki co wiersze ani kolumny macierzy 'x' nie mają żadnych nazw
+> rownames(x)
+NULL
+> colnames(x)
+NULL
+> # nadajmy im nazwy
+> rownames(x) = paste("w", 1:nrow(x), sep = "")
+> colnames(x) = paste("k", 1:ncol(x), sep = "")
+> # tak wygląda nasza macierz z nazwami wierszy i kolumn
+> x
+ k1 k2 k3
+w1 1 6 11
+w2 2 7 12
+w3 3 8 13
+w4 4 9 14
+w5 5 10 15
+> rownames(x)
+[1] "w1" "w2" "w3" "w4" "w5"
+> colnames(x)
+[1] "k1" "k2" "k3"
+Jeśli chcemy wybrać z macierzy pewne elementy, możemy to zrobić analogicznymi metodami jak w przypadku wektorów, tyle że:
+Do wybierania służy nam operator []
, z tym że w przypadku macierzy przyjmuje on dwa argumenty, oddzielone przecinkiem: [wektor_wskazujący_które_wybrać, wektor_wskazujący_które_kolumny_wybrać]
.
> x = matrix(1:30, nrow = 5)
+> rownames(x) = paste("w", 1:nrow(x), sep = "")
+> colnames(x) = paste("k", 1:ncol(x), sep = "")
+> x
+ k1 k2 k3 k4 k5 k6
+w1 1 6 11 16 21 26
+w2 2 7 12 17 22 27
+w3 3 8 13 18 23 28
+w4 4 9 14 19 24 29
+w5 5 10 15 20 25 30
+> # możemy wybrać tylko niektóre wiersze i/lub kolumny macierzy
+> x[2:4, 4:6]
+ k4 k5 k6
+w2 17 22 27
+w3 18 23 28
+w4 19 24 29
+> x[-c(1, 3, 5), c(TRUE, TRUE, FALSE, TRUE, FALSE, TRUE)]
+ k1 k2 k4 k6
+w2 2 7 17 27
+w4 4 9 19 29
+> x[c(5, 1, 2, 4, 3), -5]
+ k1 k2 k3 k4 k6
+w5 5 10 15 20 30
+w1 1 6 11 16 26
+w2 2 7 12 17 27
+w4 4 9 14 19 29
+w3 3 8 13 18 28
+> # możemy też oczywiście chcieć wybrać konkretny element
+> x[1, 4]
+[1] 16
+Jeśli chcemy wybrać całe rzędy lub całe kolumny, możemy po prostu nie podawać nic jako odpowiedni argumentu operatora []
:
> # całe rzędy
+> x[2:4, ]
+ k1 k2 k3 k4 k5 k6
+w2 2 7 12 17 22 27
+w3 3 8 13 18 23 28
+w4 4 9 14 19 24 29
+> x[(x[, 6] %% 2) == 0, ]
+ k1 k2 k3 k4 k5 k6
+w1 1 6 11 16 21 26
+w3 3 8 13 18 23 28
+w5 5 10 15 20 25 30
+> # całe kolumny
+> x[, 5:4]
+ k5 k4
+w1 21 16
+w2 22 17
+w3 23 18
+w4 24 19
+w5 25 20
+> x[, x[1, ] > 11]
+ k4 k5 k6
+w1 16 21 26
+w2 17 22 27
+w3 18 23 28
+w4 19 24 29
+w5 20 25 30
+W przypadku macierzy kwadratowych (mających taką samą liczbę wierszy i kolumn) mamy dostępnych kilka funkcji, które pozwalają nam uzyskać łatwy dostęp do pewnych ich fragmentów. Ponieważ fregmenty te nie mają prostokątnego kształtu, w efekcie otrzymamy wektory wartości.
+diag()
.lower.tri()
i upper.tri()
.> y = matrix(1:16, nrow = 4)
+> y
+ [,1] [,2] [,3] [,4]
+[1,] 1 5 9 13
+[2,] 2 6 10 14
+[3,] 3 7 11 15
+[4,] 4 8 12 16
+> diag(y)
+[1] 1 6 11 16
+> y[lower.tri(y)]
+[1] 2 3 4 7 8 12
+> y[upper.tri(y)]
+[1] 5 9 10 13 14 15
+Póki co funkcje te nie będą mieć dla nas znaczenia.
+Wartości macierzy możemy zmieniać, wskazując, o które elementy nam chodzi i podając wartości, które mają im zostać przypisane.
+> x
+ k1 k2 k3 k4 k5 k6
+w1 1 6 11 16 21 26
+w2 2 7 12 17 22 27
+w3 3 8 13 18 23 28
+w4 4 9 14 19 24 29
+w5 5 10 15 20 25 30
+> x[1, 1] = 100
+> x
+ k1 k2 k3 k4 k5 k6
+w1 100 6 11 16 21 26
+w2 2 7 12 17 22 27
+w3 3 8 13 18 23 28
+w4 4 9 14 19 24 29
+w5 5 10 15 20 25 30
+> x[, 2] = 101:105
+> x
+ k1 k2 k3 k4 k5 k6
+w1 100 101 11 16 21 26
+w2 2 102 12 17 22 27
+w3 3 103 13 18 23 28
+w4 4 104 14 19 24 29
+w5 5 105 15 20 25 30
+> x[2:3, 3:5] = -1:-6
+> x
+ k1 k2 k3 k4 k5 k6
+w1 100 101 11 16 21 26
+w2 2 102 -1 -3 -5 27
+w3 3 103 -2 -4 -6 28
+w4 4 104 14 19 24 29
+w5 5 105 15 20 25 30
+Podobnie jak w przypadku wektorów, wykonanie operacji w rodzaju dodania/odjęcia/pomnożenia/podzielenia przez stałą wykonywane jest w odniesieniu do wszystkich elementów macierzy.
+> y = matrix(1, nrow = 3, ncol = 4)
+> y
+ [,1] [,2] [,3] [,4]
+[1,] 1 1 1 1
+[2,] 1 1 1 1
+[3,] 1 1 1 1
+> y - 1
+ [,1] [,2] [,3] [,4]
+[1,] 0 0 0 0
+[2,] 0 0 0 0
+[3,] 0 0 0 0
+> (2 * y)^2
+ [,1] [,2] [,3] [,4]
+[1,] 4 4 4 4
+[2,] 4 4 4 4
+[3,] 4 4 4 4
+Również analogicznie do wektorów, jeśli dokonamy tego typu operacji na dwóch macierzach o równej sobie liczbie wierszy i równej sobie liczbie kolumn, operacja zostanie wykonana parami na odpowiadających sobie elementach macierzy.
+> x = matrix(1, nrow = 3, ncol = 4)
+> y = matrix(rep(0:11, 4), nrow = 3, ncol = 4)
+> x
+ [,1] [,2] [,3] [,4]
+[1,] 1 1 1 1
+[2,] 1 1 1 1
+[3,] 1 1 1 1
+> y
+ [,1] [,2] [,3] [,4]
+[1,] 0 3 6 9
+[2,] 1 4 7 10
+[3,] 2 5 8 11
+> x + y
+ [,1] [,2] [,3] [,4]
+[1,] 1 4 7 10
+[2,] 2 5 8 11
+[3,] 3 6 9 12
+Dwie najbardziej typowe operacje, które wykonuje się na całych wierszach i/lub kolumnach macierzy to obliczenie sumy lub średniej elementów wiersza/kolumny. Pozwalają na to funkcje rowSums()
, colSums()
, rowMeans()
i colMeans()
.
> x = matrix(rep(1:5, 6), nrow = 5)
+> x
+ [,1] [,2] [,3] [,4] [,5] [,6]
+[1,] 1 1 1 1 1 1
+[2,] 2 2 2 2 2 2
+[3,] 3 3 3 3 3 3
+[4,] 4 4 4 4 4 4
+[5,] 5 5 5 5 5 5
+> rowSums(x)
+[1] 6 12 18 24 30
+> rowMeans(x)
+[1] 1 2 3 4 5
+> colSums(x)
+[1] 15 15 15 15 15 15
+> colMeans(x)
+[1] 3 3 3 3 3 3
+Macierze mające taką samą liczbę kolumn możemy połączyć dostawiając drugą poniżej pierwszej przy pomocy funkcji rbind()
. Macierze o takiej samej liczbie wierszy możemy z kolei połączyć dostawiając drugą po prawej stronie pierwszej przy pomocy funkcji cbind()
. Drugim argumentem tych funkcji może też być wektor, o liczbie elementów równej odpowiednio liczbie kolumn lub liczbie wierszy macierzy będącej pierwszym argumentem.
> x = matrix(0, nrow = 2, ncol = 3)
+> y = matrix(1, nrow = 3, ncol = 3)
+> z = matrix(2, nrow = 2, ncol = 2)
+> x
+ [,1] [,2] [,3]
+[1,] 0 0 0
+[2,] 0 0 0
+> y
+ [,1] [,2] [,3]
+[1,] 1 1 1
+[2,] 1 1 1
+[3,] 1 1 1
+> z
+ [,1] [,2]
+[1,] 2 2
+[2,] 2 2
+> rbind(x, y)
+ [,1] [,2] [,3]
+[1,] 0 0 0
+[2,] 0 0 0
+[3,] 1 1 1
+[4,] 1 1 1
+[5,] 1 1 1
+> cbind(x, z)
+ [,1] [,2] [,3] [,4] [,5]
+[1,] 0 0 0 2 2
+[2,] 0 0 0 2 2
+> rbind(y, colSums(y))
+ [,1] [,2] [,3]
+[1,] 1 1 1
+[2,] 1 1 1
+[3,] 1 1 1
+[4,] 3 3 3
+> cbind(z, rowSums(z))
+ [,1] [,2] [,3]
+[1,] 2 2 4
+[2,] 2 2 4
+R posiada też oczywiście zestaw funkcji pozwalających nam wykonać podstawowe operacje algebry macierzy:
+t()
,%*%
,solve()
.Podczas tego kursu raczej nie będziemy ich jednak wykorzystywać.
+Zacznijmy od wczytania danych, na których będziemy dalej pracować. Funkcja load()
pozwala wczytać obiekty R zapisane w natywnym formacie R-a, czyli .RData (linijka wcześniej służy upewnieniu się, że bęziemy próbowali wczytać dane z odpowiedniego folderu). Funkcja load()
zwraca nazwy wczytanych obiektów - w tym przypadku jest to 11 wektorów. Wektor o nazwie etykiety opisuje znaczenie pozostałych wektorów, które zawierają dane - zmienne z badania Polski Generalny Sondaż Społeczny (uwzględniono tylko wybrane edycje i tylko respondentów pomiędzy 20 a 29 rokiem życia).
> try(setwd("warsztat 2016.10.17"), silent = TRUE)
+> nazwyObiektow = load("dane_2016.10.17.RData")
+> nazwyObiektow
+ [1] "etykiety" "Y" "X" "Z" "W" "V1"
+ [7] "V2" "V3" "V4" "V5" "V6" "V7"
+> etykiety
+ Y
+ "Rok badania PGSS"
+ X
+ "Wielkość miejscowości zamieszkania"
+ Z
+ "Liczba osób w gospodarstwie domowym"
+ W
+ "Wiek respondenta"
+ V1
+ "Zadowolenie z miejsca zamieszkania"
+ V2
+ "Zadowolenie z czasu wolnego i wypoczynku"
+ V3
+ "Zadowolenie z życia rodzinnego"
+ V4
+ "Zadowolenie z przyjaźni"
+ V5
+ "Zadowolenie ze stanu zdrowia"
+ V6
+"Zadowolenie ze swoich warunków mieszkaniowych"
+ V7
+ "Zadowolenie z własnego wykształcenia"
+> summary(cbind(Y, X, Z, W, V1, V2, V3, V4, V5, V6, V7))
+ Y X Z W
+ 1992:198 1 Wieś :436 1 JEDNA : 67 21 :134
+ 1995:221 2 M do 25 tys :197 2 DWIE :135 20 :131
+ 1999:354 3 M 25-99,9 tys :198 3 TRZY :323 25 :127
+ 2005:204 4 M 100-499,9 tys:214 4 CZTERY :291 27 :124
+ 2010:218 5 M 500+ tys :150 5 PIĘĆ :167 28 :123
+ 6 SZEŚĆ :122 26 :120
+ 7 SIEDEM I WIĘCEJ: 90 (Other):436
+ V1 V2
+ 1 Bardzo zadowolony :228 1 Bardzo zadowolony :139
+ 2 Zadowolony :535 2 Zadowolony :436
+ 3 Raczej zadowolony :286 3 Raczej zadowolony :309
+ 4 Raczej niezadowolony: 79 4 Raczej niezadowolony:182
+ 5 Niezadowolony : 52 5 Niezadowolony : 99
+ 6 Bardzo niezadowolony: 15 6 Bardzo niezadowolony: 30
+
+ V3 V4
+ 1 Bardzo zadowolony :344 1 Bardzo zadowolony :290
+ 2 Zadowolony :598 2 Zadowolony :624
+ 3 Raczej zadowolony :192 3 Raczej zadowolony :228
+ 4 Raczej niezadowolony: 37 4 Raczej niezadowolony: 34
+ 5 Niezadowolony : 13 5 Niezadowolony : 18
+ 6 Bardzo niezadowolony: 11 6 Bardzo niezadowolony: 1
+
+ V5 V6
+ 1 Bardzo zadowolony :272 1 Bardzo zadowolony :149
+ 2 Zadowolony :609 2 Zadowolony :450
+ 3 Raczej zadowolony :199 3 Raczej zadowolony :287
+ 4 Raczej niezadowolony: 78 4 Raczej niezadowolony:128
+ 5 Niezadowolony : 28 5 Niezadowolony :120
+ 6 Bardzo niezadowolony: 9 6 Bardzo niezadowolony: 61
+
+ V7
+ 1 Bardzo zadowolony :162
+ 2 Zadowolony :520
+ 3 Raczej zadowolony :239
+ 4 Raczej niezadowolony:161
+ 5 Niezadowolony : 95
+ 6 Bardzo niezadowolony: 18
+
+Aby uzyskać rozkład liczebności, najprościej posłużyć się funkcją table()
. Możemy wywołać ją z jednym argumentem, uzyskując rozkład brzegowy danej zmiennej.
> # rozkład wielkości miejscowości zamieszkania w analizowanej zbiorowości
+> nX = table(X)
+> nX
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 436 197 198 214
+ 5 M 500+ tys
+ 150
+> str(nX)
+ 'table' int [1:5(1d)] 436 197 198 214 150
+ - attr(*, "dimnames")=List of 1
+ ..$ X: chr [1:5] "1 Wieś" "2 M do 25 tys" "3 M 25-99,9 tys" "4 M 100-499,9 tys" ...
+Zwrócony obiekt jest typu table, ale w pratyce możemy postępować z nim analogicznie jak z wektorem, którego elementom zostały przypisane nazwy.
+> nX
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 436 197 198 214
+ 5 M 500+ tys
+ 150
+> names(nX)
+[1] "1 Wieś" "2 M do 25 tys" "3 M 25-99,9 tys"
+[4] "4 M 100-499,9 tys" "5 M 500+ tys"
+> nX[2:4]
+X
+ 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 197 198 214
+> nX[names(nX) == "2 M do 25 tys"]
+2 M do 25 tys
+ 197
+> nX * 2
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 872 394 396 428
+ 5 M 500+ tys
+ 300
+Aby obejrzeć rozkład w formie, do jakiej jesteśmy nieco bardziej przyzwyczajeni, możemy użyć funkcji as.matrix()
.
> mNX = as.matrix(nX)
+> colnames(mNX) = "N(X = X_i)"
+> mNX
+ N(X = X_i)
+1 Wieś 436
+2 M do 25 tys 197
+3 M 25-99,9 tys 198
+4 M 100-499,9 tys 214
+5 M 500+ tys 150
+W stosunku do tego, jak przywykliśmy opisywać rozkłady w tabelach brakuje jeszcze jednego elementu - sumy wszystkich obserwacji. Możemy ją dodać na dwa sposoby - ręcznie, lub przy pomocy funkcji addmargins()
.
> # "ręcznie"
+> c(nX, "suma" = sum(nX))
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 436 197 198 214
+ 5 M 500+ tys suma
+ 150 1195
+> ## analogicznie do rozkładu w formie macierzy
+> rbind(mNX, "suma" = sum(mNX))
+ N(X = X_i)
+1 Wieś 436
+2 M do 25 tys 197
+3 M 25-99,9 tys 198
+4 M 100-499,9 tys 214
+5 M 500+ tys 150
+suma 1195
+> # przy pomocy funkcji addmargins()
+> addmargins(nX)
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 436 197 198 214
+ 5 M 500+ tys Sum
+ 150 1195
+> ## w przypadku macierzy musimy podać dodatkowy argument, wskazujący, w którą
+> ## stronę ma zostać dokonane zliczanie (1 - w pionie, 2 - w poziomie)
+> addmargins(mNX, 1)
+ N(X = X_i)
+1 Wieś 436
+2 M do 25 tys 197
+3 M 25-99,9 tys 198
+4 M 100-499,9 tys 214
+5 M 500+ tys 150
+Sum 1195
+Aby uzyskać rozkład częstości, musimy podzielić liczebności w poszczególnych komórkach przez liczbę wszystkich obserwacji. Podobnie jak w przypadku dodawania komórki z sumą wszystkich obserwacji, możemy to zrobić ręcznie, lub korzystając z gotowej funkcji - w tym przypadku prop.table()
(uwaga - jej argumentem jest wynik działania funkcji table()
, a nie surowe dane).
> # "ręcznie"
+> nX
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 436 197 198 214
+ 5 M 500+ tys
+ 150
+> pX = nX / sum(nX)
+> pX
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 0.3648536 0.1648536 0.1656904 0.1790795
+ 5 M 500+ tys
+ 0.1255230
+> # przy pomocy funkcji prop.table()
+> pX = prop.table(nX)
+> pX
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 0.3648536 0.1648536 0.1656904 0.1790795
+ 5 M 500+ tys
+ 0.1255230
+> # dalej możemy nadać rozkładowi nieco ładniejszy wygląd
+> mPX = as.matrix(c(pX, "suma" = sum(pX)))
+> colnames(mPX) = "P(X = x_i)"
+> mPX
+ P(X = x_i)
+1 Wieś 0.3648536
+2 M do 25 tys 0.1648536
+3 M 25-99,9 tys 0.1656904
+4 M 100-499,9 tys 0.1790795
+5 M 500+ tys 0.1255230
+suma 1.0000000
+Uwaga, jeśli w obiekcie mamy rozkład z dopisanym elementem sumy, musimy oczywiście dzielić przez wartość tego elementu (względnie wartość wszystkich komórek rozkładu poza tą opisującą sumę).
+> nXS = c(nX, "suma" = sum(nX))
+> nXS
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 436 197 198 214
+ 5 M 500+ tys suma
+ 150 1195
+> # "ręcznie" (w tym przypadku to nawet prościej!)
+> pXS = nXS / nXS[length(nXS)]
+> pXS
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 0.3648536 0.1648536 0.1656904 0.1790795
+ 5 M 500+ tys suma
+ 0.1255230 1.0000000
+> # przy pomocy funkcji prop.table()
+> pXS = prop.table(nXS[-length(nXS)])
+> pXS = c(pXS, "suma" = sum(pXS))
+> pXS
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 0.3648536 0.1648536 0.1656904 0.1790795
+ 5 M 500+ tys suma
+ 0.1255230 1.0000000
+> # !!! źle !!!
+> nXS / sum(nXS) # !!! źle !!!
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 0.18242678 0.08242678 0.08284519 0.08953975
+ 5 M 500+ tys suma
+ 0.06276151 0.50000000
+> prop.table(nXS) # !!! źle !!!
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 0.18242678 0.08242678 0.08284519 0.08953975
+ 5 M 500+ tys suma
+ 0.06276151 0.50000000
+> # !!! źle !!!
+Aby obliczyć skumulowany rozkład brzegowy liczebności, najprościej posłużyć się funkcją cumsum()
. Przyjmuje ona jako argument wektor i zwraca wektor tej samej długości, którego kolejne elementy przyjmują wartości równe sumie wartości elementów wektora wejściowego, od pierwszego do danego.
> rbind("x" = 0:6, "cumsum(x)" = cumsum(0:6))
+ [,1] [,2] [,3] [,4] [,5] [,6] [,7]
+x 0 1 2 3 4 5 6
+cumsum(x) 0 1 3 6 10 15 21
+Dysponując brzegowym rozkładem liczebności zmiennej X, zapisanym w obiekcie nX
oblicz skumulowany rozkład liczebności zmiennej X i przypisz go do obiektu sNX
, a następnie skumulowany rozkład częstości tej samej zmiennej i przypisz go do obiektu sPX
.
> nX = table(X)
+> nX
+X
+ 1 Wieś 2 M do 25 tys 3 M 25-99,9 tys 4 M 100-499,9 tys
+ 436 197 198 214
+ 5 M 500+ tys
+ 150
+> # to jest miejsce na Twój kod
+>
+>
+>
+Funkcja table()
pozwala też łatwo uzyskać łączny rozkład liczebności dwóch zmiennych - wystarczy podać jej jako drugi argument inny wektor (o tej samej liczbie elementów, co ten, który podajemy jako pierwszy argument).
> # łączny rozkład liczebności zadowolenia z własnego wykształcenia
+> # i roku przeprowadzenia badania PGSS
+> nV7Y = table(V7, Y)
+> nV7Y
+ Y
+V7 1992 1995 1999 2005 2010
+ 1 Bardzo zadowolony 15 18 34 38 57
+ 2 Zadowolony 97 96 149 79 99
+ 3 Raczej zadowolony 40 40 79 44 36
+ 4 Raczej niezadowolony 27 34 58 25 17
+ 5 Niezadowolony 17 27 29 14 8
+ 6 Bardzo niezadowolony 2 6 5 4 1
+Zwrócony obiekt, jak w przypadku jednowymiarowym, jest typu table, ale tym razem ma dwa wymiary i możemy go traktować podobnie jak macierz.
+> str(nV7Y)
+ 'table' int [1:6, 1:5] 15 97 40 27 17 2 18 96 40 34 ...
+ - attr(*, "dimnames")=List of 2
+ ..$ V7: chr [1:6] "1 Bardzo zadowolony" "2 Zadowolony" "3 Raczej zadowolony" "4 Raczej niezadowolony" ...
+ ..$ Y : chr [1:5] "1992" "1995" "1999" "2005" ...
+> colnames(nV7Y)
+[1] "1992" "1995" "1999" "2005" "2010"
+> rownames(nV7Y)
+[1] "1 Bardzo zadowolony" "2 Zadowolony"
+[3] "3 Raczej zadowolony" "4 Raczej niezadowolony"
+[5] "5 Niezadowolony" "6 Bardzo niezadowolony"
+> nV7Y[3:4, 2:3]
+ Y
+V7 1995 1999
+ 3 Raczej zadowolony 40 79
+ 4 Raczej niezadowolony 34 58
+Do uzyskanego rozkładu możemy też dodać rozkłady brzegowe, przy pomocy poznanej już wcześniej funkcji addmargins()
. Wywołanie jej bez podania drugiego parametru spowoduje dodanie wszystkich możliwych (tu: dwóch) rozkładów brzegowych. Możemy też zrobić to na piechotę, korzystając z funkcji rowSums()
, colSums()
, rbind()
i cbind()
.
> # przy pomocy funkcji addmargins()
+> addmargins(nV7Y)
+ Y
+V7 1992 1995 1999 2005 2010 Sum
+ 1 Bardzo zadowolony 15 18 34 38 57 162
+ 2 Zadowolony 97 96 149 79 99 520
+ 3 Raczej zadowolony 40 40 79 44 36 239
+ 4 Raczej niezadowolony 27 34 58 25 17 161
+ 5 Niezadowolony 17 27 29 14 8 95
+ 6 Bardzo niezadowolony 2 6 5 4 1 18
+ Sum 198 221 354 204 218 1195
+> # "na piechotę"
+> nBV7Y = rbind(nV7Y, "suma" = colSums(nV7Y))
+> nBV7Y = cbind(nBV7Y, "suma" = rowSums(nBV7Y))
+> nBV7Y
+ 1992 1995 1999 2005 2010 suma
+1 Bardzo zadowolony 15 18 34 38 57 162
+2 Zadowolony 97 96 149 79 99 520
+3 Raczej zadowolony 40 40 79 44 36 239
+4 Raczej niezadowolony 27 34 58 25 17 161
+5 Niezadowolony 17 27 29 14 8 95
+6 Bardzo niezadowolony 2 6 5 4 1 18
+suma 198 221 354 204 218 1195
+Dysponując łącznym rozkładem liczebności zmiennych V7 i Y, zapisanym w obiekcie nV7Y
oblicz łączny rozkład częstości tych zmiennych i przypisz go do obiektu pV7Y
. Pokaż ten rozkład w konsoli z wartościami zaokrąglonymi do trzeciego miejsca po przecinku, używając polecenia round(pV7Y, 3)
.
> # to jest miejsce na Twój kod
+>
+>
+>
+>
+Warunkowe rozkłady liczebności w istocie możemy traktować po prostu jako wycinki z łącznego rozkładu liczebności.
+> # warunkowy rozkład liczebności zadowolenia z własnego wykształcenia
+> # dla roku badania PGSS równego 1995
+> nV7Y[, colnames(nV7Y) == "1995"]
+ 1 Bardzo zadowolony 2 Zadowolony 3 Raczej zadowolony
+ 18 96 40
+4 Raczej niezadowolony 5 Niezadowolony 6 Bardzo niezadowolony
+ 34 27 6
+> # warunkowy rozkład liczebności zadowolenia z własnego wykształcenia
+> # dla roku badania PGSS mniejszego niż 2000
+> temp = nV7Y[, as.numeric(colnames(nV7Y)) < 2000]
+> temp
+ Y
+V7 1992 1995 1999
+ 1 Bardzo zadowolony 15 18 34
+ 2 Zadowolony 97 96 149
+ 3 Raczej zadowolony 40 40 79
+ 4 Raczej niezadowolony 27 34 58
+ 5 Niezadowolony 17 27 29
+ 6 Bardzo niezadowolony 2 6 5
+> rowSums(temp)
+ 1 Bardzo zadowolony 2 Zadowolony 3 Raczej zadowolony
+ 67 342 159
+4 Raczej niezadowolony 5 Niezadowolony 6 Bardzo niezadowolony
+ 119 73 13
+Rodzina warunkowych rozkładów liczebności jest z kolei właściwie tożsama, z łącznym rozkładem liczebności, z którego obcięto rozkład brzegowy jednej zmiennej.
+> # łączny rozkład liczebności zadowolenia z własnego wykształcenia
+> # i roku badania PGSS
+> addmargins(nV7Y)
+ Y
+V7 1992 1995 1999 2005 2010 Sum
+ 1 Bardzo zadowolony 15 18 34 38 57 162
+ 2 Zadowolony 97 96 149 79 99 520
+ 3 Raczej zadowolony 40 40 79 44 36 239
+ 4 Raczej niezadowolony 27 34 58 25 17 161
+ 5 Niezadowolony 17 27 29 14 8 95
+ 6 Bardzo niezadowolony 2 6 5 4 1 18
+ Sum 198 221 354 204 218 1195
+> # rodzina warunkowych rozkładów liczebności zadowolenia z własnego wykształcenia
+> # pod warunkiem roku badania PGSS
+> addmargins(nV7Y)[, -(ncol(nV7Y) + 1)]
+ Y
+V7 1992 1995 1999 2005 2010
+ 1 Bardzo zadowolony 15 18 34 38 57
+ 2 Zadowolony 97 96 149 79 99
+ 3 Raczej zadowolony 40 40 79 44 36
+ 4 Raczej niezadowolony 27 34 58 25 17
+ 5 Niezadowolony 17 27 29 14 8
+ 6 Bardzo niezadowolony 2 6 5 4 1
+ Sum 198 221 354 204 218
+> # lub równoważnie (a nawet prościej)
+> addmargins(nV7Y, 1)
+ Y
+V7 1992 1995 1999 2005 2010
+ 1 Bardzo zadowolony 15 18 34 38 57
+ 2 Zadowolony 97 96 149 79 99
+ 3 Raczej zadowolony 40 40 79 44 36
+ 4 Raczej niezadowolony 27 34 58 25 17
+ 5 Niezadowolony 17 27 29 14 8
+ 6 Bardzo niezadowolony 2 6 5 4 1
+ Sum 198 221 354 204 218
+Pojedynczy warunkowy rozkład częstości możemy uzyskać na podstawie odpowiedniego warunkowego rozkładu liczebności w analogiczny sposób, jak brzegowy rozkład częstości na podstawie brzegowego rozkładu liczebności.
+> # jakiś rozkład warunkowy
+> nWarunkowyV7Y1995 = nV7Y[, colnames(nV7Y) == "1995"]
+> nWarunkowyV7Y1995
+ 1 Bardzo zadowolony 2 Zadowolony 3 Raczej zadowolony
+ 18 96 40
+4 Raczej niezadowolony 5 Niezadowolony 6 Bardzo niezadowolony
+ 34 27 6
+> # "ręcznie"
+> pWarunkowyV7Y1995 = nWarunkowyV7Y1995 / sum(nWarunkowyV7Y1995)
+> pWarunkowyV7Y1995
+ 1 Bardzo zadowolony 2 Zadowolony 3 Raczej zadowolony
+ 0.08144796 0.43438914 0.18099548
+4 Raczej niezadowolony 5 Niezadowolony 6 Bardzo niezadowolony
+ 0.15384615 0.12217195 0.02714932
+> # przy pomocy funkcji prop.table
+> prop.table(nWarunkowyV7Y1995)
+ 1 Bardzo zadowolony 2 Zadowolony 3 Raczej zadowolony
+ 0.08144796 0.43438914 0.18099548
+4 Raczej niezadowolony 5 Niezadowolony 6 Bardzo niezadowolony
+ 0.15384615 0.12217195 0.02714932
+Pamiętamy oczywiście o tym, że w sytuacji, gdy do nasz rozkład łączny już wcześniej uzupełniliśmy o rozkłady brzegowe, musielibyśmy obliczyć to nieco inaczej!
+Rodzinę warunkowych rozkładów częstości również możemy uzyskać przy pomocy funkcji prop.table()
, podając jej drugi (opcjonalny), argument. Podobnie jak w przypadku funkcji addmargins()
wskazuje on, w którą stronę ma być wykonana operacja (tu: procentowania). Żeby sprawy nie były zbyt proste, wartości tego drugiego argumentu mają inne znaczenie w ramach funkcji prop.table()
, niż w ramach funkcji addmargins()
:
prop.table()
: 1 - procentuj w wierszach, 2 - procentuj w kolumnach;addmargins()
: 1 - dodaj rozkład brzegowy pierwszej zmiennej (dla dwóch zmiennych: ten na dole, tzn. sumuj w kolumnach), 2 - dodaj rozkład brzegowy drugiej zmienej (dla dwóch zmiennych: ten po prawej, tzn. sumuj w wierszach).> # rodzina warunkowych rozkładów częstości zadowolenia z własnego wykształcenia
+> # w zależności od roku badania PGSS
+> rWRPV7Y = addmargins(prop.table(nV7Y, 2), 1)
+> rWRPV7Y
+ Y
+V7 1992 1995 1999 2005
+ 1 Bardzo zadowolony 0.075757576 0.081447964 0.096045198 0.186274510
+ 2 Zadowolony 0.489898990 0.434389140 0.420903955 0.387254902
+ 3 Raczej zadowolony 0.202020202 0.180995475 0.223163842 0.215686275
+ 4 Raczej niezadowolony 0.136363636 0.153846154 0.163841808 0.122549020
+ 5 Niezadowolony 0.085858586 0.122171946 0.081920904 0.068627451
+ 6 Bardzo niezadowolony 0.010101010 0.027149321 0.014124294 0.019607843
+ Sum 1.000000000 1.000000000 1.000000000 1.000000000
+ Y
+V7 2010
+ 1 Bardzo zadowolony 0.261467890
+ 2 Zadowolony 0.454128440
+ 3 Raczej zadowolony 0.165137615
+ 4 Raczej niezadowolony 0.077981651
+ 5 Niezadowolony 0.036697248
+ 6 Bardzo niezadowolony 0.004587156
+ Sum 1.000000000
+> round(rWRPV7Y, 3)
+ Y
+V7 1992 1995 1999 2005 2010
+ 1 Bardzo zadowolony 0.076 0.081 0.096 0.186 0.261
+ 2 Zadowolony 0.490 0.434 0.421 0.387 0.454
+ 3 Raczej zadowolony 0.202 0.181 0.223 0.216 0.165
+ 4 Raczej niezadowolony 0.136 0.154 0.164 0.123 0.078
+ 5 Niezadowolony 0.086 0.122 0.082 0.069 0.037
+ 6 Bardzo niezadowolony 0.010 0.027 0.014 0.020 0.005
+ Sum 1.000 1.000 1.000 1.000 1.000
+Wykres słupkowy obrazujący rozkład jednej zmiennej możemy uzyskać korzystając z funkcji barplot
, której jako argument podajemy rozkład danej zmiennej (uwaga, bez ew. elementu z sumą).
> nX = table(X)
+> pX = prop.table(nX)
+> barplot(nX)
+> barplot(pX)
+Funkcja ma też dużą liczbę dodatkowych argumentów, które pozwalają nam zarządzać jego wyglądem i uzupełnić o dodatkowe elmenty (np. tytuł, czy etykiety osi). Funkcji grid()
możemy użyć, aby dodać linie siatki.
> barplot(pX, col = 3,
++ main = "Wielkość miejscowości zamieszkania w analizowane zbiorowości",
++ ylab = "czestość")
+> grid(col = grey(0.3), nx = NA, ny = NULL)
+Czasem bardziej użyteczne byłoby pokazanie wykresu w postaci skumulowanej - słupków reprezentujących częstość (względnie liczebność) poszczególnych słupków nałożonych jeden na drugim. Możemy to łatwo uzyskać, konwertując nasz rozkład na macierz przed przekazaniem funkcji barplot()
.
> barplot(as.matrix(nX))
+> # nawet mając macierz możemy wrócić do poprzedniego wyglądu
+> barplot(as.matrix(nX), beside = TRUE)
+> # żeby móc coś zrozumieć, warto dodać legendę
+> barplot(as.matrix(pX),
++ main = "Wielkość miejscowości zamieszkania w analizowane zbiorowości",
++ legend.text = TRUE, args.legend = list(x = "right"), xlim = c(0, 1.8))
+Niestety kwestia pozycjonowania legendy nie jest tu rozwiązana w niezawodny sposób.
+Opisane poniżej rozwiązania można oczywiście zastosować do różnych typów rozkładów łącznych i rodzin rozkładów warunkowych, ale prowadząc analizy zwykle skupiamy się na porównywania ze sobą rozkładów w ramach rodziny warunkowych rozkładów częstości. Stąd przykład odnosi się właśnie do takiej rodziny rozkładów.
+> # rodzina warunkowych rozkładów częstości zadowolenia z własnego wykształcenia
+> # w zależności od roku badania PGSS
+> rWRPV7Y = prop.table(nV7Y, 2)
+> barplot(rWRPV7Y)
+Bez legendy, tytułu i etykiet osi trochę trudno się zorientować, o co chodzi.
+> barplot(rWRPV7Y,
++ main = "Zadowolenie z własnego wykształcenia\nw różnych rundach badania PGSS",
++ xlab = "rok badania PGSS",
++ ylab = "częstość",
++ legend.text = TRUE, args.legend = list(x = "right"), xlim = c(0, 10))
+Możemy też uzyskać wykres w postaci słupków zestawionych obok siebie - choć w tym przypadku jest on raczej mniej użyteczny analitycznie.
+> barplot(rWRPV7Y, beside = TRUE,
++ main = "Zadowolenie z własnego wykształcenia\nw różnych rundach badania PGSS",
++ xlab = "rok badania PGSS",
++ ylab = "częstość",
++ legend.text = TRUE, args.legend = list(x = "topright"), ylim = c(0, 0.9))
+Wejdź dziś wieczorem na stronę projektu na GitHubie z materiałami z tego warsztatu i zobacz, co pojawiło się w tym miejscu.
+G. Lissowski, J. Haman i M. Jasiński. (2011). Podstawy statystyki dla socjologów. Wyd. II poprawione. Warszawa: Wydawnictwo Naukowe SCHOLAR. - Rozdziały: 1.1.-1.2., 3.5.-3.6., 4.1.-4.2. oraz 4.5. w zakresie, w jakim odnosi się do parametrów omówionych w 4.1. i 4.2.
+