R Language
Funkcja podziału
Szukaj…
Podstawowe użycie podziału
split
pozwala podzielić wektor lub ramkę danych na segmenty ze względu na zmienne czynnik / grupa. Ta wentylacja do segmentów ma postać listy, którą można następnie zastosować do obliczeń grupowych ( for
pętli lub lapply
/ sapply
).
Pierwszy przykład pokazuje użycie split
na wektorze:
Rozważ następujący wektor liter:
testdata <- c("e", "o", "r", "g", "a", "y", "w", "q", "i", "s", "b", "v", "x", "h", "u")
Celem jest rozdzielenie tych liter na voyels
i consonants
, tj. voyels
ich odpowiednio do rodzaju litery.
Utwórzmy najpierw wektor grupowania:
vowels <- c('a','e','i','o','u','y')
letter_type <- ifelse(testdata %in% vowels, "vowels", "consonants")
Zauważ, że letter_type
ma taką samą długość jak nasze wektorowe dane testdata
. Teraz możemy split
te dane testowe na dwie grupy, vowels
i consonants
:
split(testdata, letter_type)
#$consonants
#[1] "r" "g" "w" "q" "s" "b" "v" "x" "h"
#$vowels
#[1] "e" "o" "a" "y" "i" "u"
Stąd wynik jest listą, których nazwy pochodzą z naszego wektora grupującego / czynnika letter_type
.
split
ma również metodę radzenia sobie z data.frames.
Rozważmy na przykład dane iris
:
data(iris)
Za pomocą split
można utworzyć listę zawierającą jedną ramkę data.frame dla gatunku tęczówki (zmienna: Gatunki):
> liris <- split(iris, iris$Species)
> names(liris)
[1] "setosa" "versicolor" "virginica"
> head(liris$setosa)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
(zawiera tylko dane dla grupy setosa).
Jedną przykładową operacją byłoby obliczenie macierzy korelacji dla gatunku tęczówki; lapply
wtedy lapply
:
> (lcor <- lapply(liris, FUN=function(df) cor(df[,1:4])))
$setosa
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 1.0000000 0.7425467 0.2671758 0.2780984
Sepal.Width 0.7425467 1.0000000 0.1777000 0.2327520
Petal.Length 0.2671758 0.1777000 1.0000000 0.3316300
Petal.Width 0.2780984 0.2327520 0.3316300 1.0000000
$versicolor
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 1.0000000 0.5259107 0.7540490 0.5464611
Sepal.Width 0.5259107 1.0000000 0.5605221 0.6639987
Petal.Length 0.7540490 0.5605221 1.0000000 0.7866681
Petal.Width 0.5464611 0.6639987 0.7866681 1.0000000
$virginica
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 1.0000000 0.4572278 0.8642247 0.2811077
Sepal.Width 0.4572278 1.0000000 0.4010446 0.5377280
Petal.Length 0.8642247 0.4010446 1.0000000 0.3221082
Petal.Width 0.2811077 0.5377280 0.3221082 1.0000000
Następnie możemy pobrać dla każdej grupy najlepszą parę skorelowanych zmiennych: (macierz korelacji zostaje przekształcona / stopiona, przekątna jest filtrowana i wybierany jest najlepszy zapis)
> library(reshape)
> (topcor <- lapply(lcor, FUN=function(cormat){
correlations <- melt(cormat,variable_name="correlatio);
filtered <- correlations[correlations$X1 != correlations$X2,];
filtered[which.max(filtered$correlation),]
}))
$setosa
X1 X2 correlation
2 Sepal.Width Sepal.Length 0.7425467
$versicolor
X1 X2 correlation
12 Petal.Width Petal.Length 0.7866681
$virginica
X1 X2 correlation
3 Petal.Length Sepal.Length 0.8642247
Zauważ, że jedno obliczenia są wykonywane na takim poziomie grupowym, można być zainteresowanym zestawieniem wyników, co można zrobić za pomocą:
> (result <- do.call("rbind", topcor))
X1 X2 correlation
setosa Sepal.Width Sepal.Length 0.7425467
versicolor Petal.Width Petal.Length 0.7866681
virginica Petal.Length Sepal.Length 0.8642247
Korzystanie z podziału w paradygmacie podziel-zastosuj-połącz
Popularną formą analizy danych jest podziel-zastosuj-połącz , w której dzielisz dane na grupy, stosujesz pewien rodzaj przetwarzania dla każdej grupy, a następnie łączysz wyniki.
Rozważmy analizę danych, w której chcemy uzyskać dwa samochody o najlepszych milach na galon (mpg) dla każdej liczby cylindrów (cyl) we wbudowanym zestawie danych mtcars. Najpierw podzieliliśmy mtcars
danych mtcars
według liczby cylindrów:
(spl <- split(mtcars, mtcars$cyl))
# $`4`
# mpg cyl disp hp drat wt qsec vs am gear carb
# Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
# Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
# Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
# Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
# ...
#
# $`6`
# mpg cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
# Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
# ...
#
# $`8`
# mpg cyl disp hp drat wt qsec vs am gear carb
# Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
# Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
# Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
# ...
Zwróciło to listę ramek danych, po jednej dla każdej liczby cylindrów. Jak wynika z danych wyjściowych, możemy uzyskać odpowiednie ramki danych ze spl$`4`
, spl$`6`
i spl$`8`
(niektórzy mogą uznać za bardziej atrakcyjne wizualnie użycie spl$"4"
lub spl[["4"]]
zamiast tego).
Teraz możemy użyć lapply
do przeglądania tej listy, stosując naszą funkcję, która wyodrębnia samochody z najlepszymi 2 wartościami mpg z każdego z elementów listy:
(best2 <- lapply(spl, function(x) tail(x[order(x$mpg),], 2)))
# $`4`
# mpg cyl disp hp drat wt qsec vs am gear carb
# Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
# Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
#
# $`6`
# mpg cyl disp hp drat wt qsec vs am gear carb
# Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
# Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
#
# $`8`
# mpg cyl disp hp drat wt qsec vs am gear carb
# Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
# Pontiac Firebird 19.2 8 400 175 3.08 3.845 17.05 0 0 3 2
Wreszcie możemy połączyć wszystko za pomocą rbind
. Chcemy wywołać rbind(best2[["4"]], best2[["6"]], best2[["8"]])
, ale byłoby to nudne, gdybyśmy mieli ogromną listę. W rezultacie używamy:
do.call(rbind, best2)
# mpg cyl disp hp drat wt qsec vs am gear carb
# 4.Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
# 4.Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
# 6.Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
# 6.Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
# 8.Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
# 8.Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
Zwraca wynik rbind
(argument 1, funkcja) ze wszystkimi elementami best2
(argument 2, lista) przekazanymi jako argumenty.
Dzięki prostym analizom takim jak ta, może być bardziej zwarta (i być może znacznie mniej czytelna!), Aby wykonać cały split-Apply-Combine w jednym wierszu kodu:
do.call(rbind, lapply(split(mtcars, mtcars$cyl), function(x) tail(x[order(x$mpg),], 2)))
Warto również zauważyć, że lapply(split(x,f), FUN)
może być alternatywnie obramowana za pomocą funkcji ?by
lapply(split(x,f), FUN)
:
by(mtcars, mtcars$cyl, function(x) tail(x[order(x$mpg),], 2))
do.call(rbind, by(mtcars, mtcars$cyl, function(x) tail(x[order(x$mpg),], 2)))