R Language
Funzione Split
Ricerca…
Utilizzo di base di split
split
consente di dividere un vettore o un data.frame in bucket per quanto riguarda le variabili di un fattore / gruppo. Questa ventilazione nei secchi assume la forma di un elenco, che può essere quindi utilizzato per applicare il calcolo a gruppi ( for
loop o lapply
/ sapply
).
Il primo esempio mostra l'uso della split
su un vettore:
Considera il seguente vettore di lettere:
testdata <- c("e", "o", "r", "g", "a", "y", "w", "q", "i", "s", "b", "v", "x", "h", "u")
L'obiettivo è separare tali lettere in voyels
e consonants
, ovvero dividerle in base al tipo di lettera.
Creiamo prima un vettore di raggruppamento:
vowels <- c('a','e','i','o','u','y')
letter_type <- ifelse(testdata %in% vowels, "vowels", "consonants")
Si noti che letter_type
ha la stessa lunghezza del nostro vettore testdata
. Ora possiamo split
questi dati di test nei due gruppi, vowels
e consonants
:
split(testdata, letter_type)
#$consonants
#[1] "r" "g" "w" "q" "s" "b" "v" "x" "h"
#$vowels
#[1] "e" "o" "a" "y" "i" "u"
Quindi, il risultato è un elenco di nomi che provengono dal nostro vettore di raggruppamento / fattore letter_type
.
split
ha anche un metodo per gestire data.frames.
Si consideri, ad esempio, i dati iris
:
data(iris)
Utilizzando split
, è possibile creare un elenco contenente un data.frame per specie di iris (variabile: Specie):
> 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
(contiene solo i dati per il gruppo setosa).
Un'operazione di esempio sarebbe quella di calcolare la matrice di correlazione per specie di iris; uno avrebbe quindi usato 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
Quindi possiamo recuperare per gruppo la migliore coppia di variabili correlate: (la matrice di correlazione viene rimodellata / fusa, la diagonale viene filtrata e viene selezionata la registrazione migliore)
> 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
Si noti che i calcoli vengono eseguiti a livello di gruppo, uno può essere interessato a impilare i risultati, che può essere fatto con:
> (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
Usando lo split nel paradigma split-apply-combine
Una forma popolare di analisi dei dati è split-apply-combine , in cui si suddividono i dati in gruppi, si applica una sorta di elaborazione su ciascun gruppo e quindi si combinano i risultati.
Consideriamo un'analisi dei dati in cui vogliamo ottenere le due auto con le migliori miglia per gallone (mpg) per ogni numero di cilindri (cyl) nel set di dati mtcars integrato. Per prima cosa, abbiamo diviso il mtcars
dati mtcars
per il conteggio dei cilindri:
(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
# ...
Questo ha restituito un elenco di frame di dati, uno per ogni numero di cilindri. Come indicato dall'output, potremmo ottenere i frame di dati rilevanti con spl$`4`
, spl$`6`
, e spl$`8`
(alcuni potrebbero trovare più visivamente accattivante usare spl$"4"
o spl[["4"]]
invece).
Ora, possiamo usare lapply
per scorrere questa lista, applicando la nostra funzione che estrae le auto con i migliori 2 valori mpg da ciascuno degli elementi della lista:
(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
Infine, possiamo combinare tutto insieme usando rbind
. Vogliamo chiamare rbind(best2[["4"]], best2[["6"]], best2[["8"]])
, ma questo sarebbe noioso se avessimo una lista enorme. Di conseguenza, usiamo:
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
Ciò restituisce il risultato di rbind
(argomento 1, una funzione) con tutti gli elementi di best2
(argomento 2, una lista) passati come argomenti.
Con analisi semplici come questa, può essere più compatto (e possibilmente molto meno leggibile!) Fare l'intera combinazione split-apply in un'unica riga di codice:
do.call(rbind, lapply(split(mtcars, mtcars$cyl), function(x) tail(x[order(x$mpg),], 2)))
Vale anche la pena notare che la lapply(split(x,f), FUN)
può essere alternativamente incorniciata usando la funzione ?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)))