Domanda

Voglio ordinare un data.frame per più colonne.Ad esempio, con data.frame di seguito vorrei ordinare per colonna z (discendente) quindi per colonna b (ascendente):

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
dd
    b x y z
1  Hi A 8 1
2 Med D 3 1
3  Hi A 9 1
4 Low C 9 2
È stato utile?

Soluzione

È possibile utilizzare il order() funzione direttamente senza ricorrere a strumenti aggiuntivi - vedere questa risposta più semplice che utilizza un proprio trucco dalla parte superiore del codice example(order):

R> dd[with(dd, order(-z, b)), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

modificare alcuni 2+ anni dopo: è stato solo chiesto come fare questo in base all'indice di colonna. La risposta è passare semplicemente la colonna di ordinamento desiderato (s) alla funzione order():

R> dd[order(-dd[,4], dd[,1]), ]
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1
R> 

, piuttosto che utilizzare il nome della colonna (e with() per / accesso diretto più facile).

Altri suggerimenti

Le scelte

  • order da base
  • arrange da dplyr
  • setorder e setorderv da data.table
  • arrange da plyr
  • sort da taRifx
  • orderBy da doBy
  • sortData da Deducer

La maggior parte del tempo si consiglia di utilizzare le soluzioni dplyr o data.table, a meno che non avendo-dipendenze è importante, in questo caso l'uso base::order.


Recentemente ho aggiunto sort.data.frame a un pacchetto CRAN, rendendo compatibile è di classe come discusso qui: modo migliore per creare generico / metodo di coerenza per l'ordinamento .data.frame?

Pertanto, data la dd data.frame, è possibile ordinare i seguenti:

dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
library(taRifx)
sort(dd, f= ~ -z + b )

Se siete uno degli autori originali di questa funzione, si prega di contattare me. Discussione da domaininess pubblico è qui: http://chat.stackoverflow.com/transcript/message/1094290#1094290


È anche possibile utilizzare la funzione arrange() da plyr come Hadley ha sottolineato nel thread di cui sopra:

library(plyr)
arrange(dd,desc(z),b)

Benchmark: Si noti che ho caricato ogni pacchetto in una nuova sessione di R dato che c'erano un sacco di conflitti. In particolare il carico confezione DOBY provoca sort to return "Il seguente oggetto (s) sono mascherati da 'x (posizione 17)': b, x, y, z", e caricando il pacchetto Deducer sovrascrive sort.data.frame da Kevin Wright o taRifx pacchetto.

#Load each time
dd <- data.frame(b = factor(c("Hi", "Med", "Hi", "Low"), 
      levels = c("Low", "Med", "Hi"), ordered = TRUE),
      x = c("A", "D", "A", "C"), y = c(8, 3, 9, 9),
      z = c(1, 1, 1, 2))
library(microbenchmark)

# Reload R between benchmarks
microbenchmark(dd[with(dd, order(-z, b)), ] ,
    dd[order(-dd$z, dd$b),],
    times=1000
)

mediani volte:

dd[with(dd, order(-z, b)), ] 778

dd[order(-dd$z, dd$b),] 788

library(taRifx)
microbenchmark(sort(dd, f= ~-z+b ),times=1000)

Il tempo mediano: 1567

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=1000)

Il tempo mediano: 862

library(doBy)
microbenchmark(orderBy(~-z+b, data=dd),times=1000)

Il tempo mediano: 1694

Si noti che DOBY prende un bel po 'di tempo per caricare il pacchetto.

library(Deducer)
microbenchmark(sortData(dd,c("z","b"),increasing= c(FALSE,TRUE)),times=1000)

Impossibile fare carico Deducer. Ha bisogno console JGR.

esort <- function(x, sortvar, ...) {
attach(x)
x <- x[with(x,order(sortvar,...)),]
return(x)
detach(x)
}

microbenchmark(esort(dd, -z, b),times=1000)

Non sembra essere compatibile con microbenchmark a causa della / scollegamento allegare.


m <- microbenchmark(
  arrange(dd,desc(z),b),
  sort(dd, f= ~-z+b ),
  dd[with(dd, order(-z, b)), ] ,
  dd[order(-dd$z, dd$b),],
  times=1000
  )

uq <- function(x) { fivenum(x)[4]}  
lq <- function(x) { fivenum(x)[2]}

y_min <- 0 # min(by(m$time,m$expr,lq))
y_max <- max(by(m$time,m$expr,uq)) * 1.05

p <- ggplot(m,aes(x=expr,y=time)) + coord_cartesian(ylim = c( y_min , y_max )) 
p + stat_summary(fun.y=median,fun.ymin = lq, fun.ymax = uq, aes(fill=expr))

 complotto microbenchmark

(linee si estendono da quartile inferiore a quartile superiore, dot è la mediana)


Alla luce di questi risultati e del peso di semplicità vs. velocità, avrei dovuto dare il via libera a arrange nel pacchetto plyr . Ha una sintassi semplice e tuttavia è quasi altrettanto rapida come la base di R comandi con le loro macchinazioni contorti. In genere brillante lavoro Hadley Wickham. La mia unica lamentela con essa è che si rompe la nomenclatura R standard in cui gli oggetti di smistamento vengono chiamati da sort(object), ma capisco perché Hadley ha fatto in questo modo a causa di questioni discusse nella questione linkato sopra.

La risposta di Dirk è fantastica.Evidenzia inoltre una differenza fondamentale nella sintassi utilizzata per l'indicizzazione data.framesabbia data.tableS:

## The data.frame way
dd[with(dd, order(-z, b)), ]

## The data.table way: (7 fewer characters, but that's not the important bit)
dd[order(-z, b)]

La differenza tra i due appelli è piccola, ma può avere conseguenze importanti.Soprattutto se scrivi codice di produzione e/o sei interessato alla correttezza della tua ricerca, è meglio evitare ripetizioni inutili di nomi di variabili. data.tableti aiuta a fare questo.

Ecco un esempio di come la ripetizione dei nomi delle variabili potrebbe metterti nei guai:

Cambiamo il contesto rispetto alla risposta di Dirk e diciamo che fa parte di un progetto più ampio in cui ci sono molti nomi di oggetti e sono lunghi e significativi;invece di dd è chiamato quarterlyreport.Diventa :

quarterlyreport[with(quarterlyreport,order(-z,b)),]

Ok bene.Non c'è niente di sbagliato in questo.Successivamente il tuo capo ti chiede di includere il rapporto dell'ultimo trimestre nel rapporto.Esamini il tuo codice, aggiungendo un oggetto lastquarterlyreport in vari posti e in qualche modo (come diavolo?) ti ritrovi con questo:

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

Non è quello che intendevi, ma non l'hai notato perché l'hai fatto velocemente ed è annidato in una pagina di codice simile.Il codice non cade (nessun avviso e nessun errore) perché R pensa che sia quello che intendevi.Spereresti che chiunque legga il tuo rapporto se ne accorga, ma forse non è così.Se lavori molto con i linguaggi di programmazione, questa situazione potrebbe esserti troppo familiare.È stato un "errore di battitura" direte voi.Correggerò l'"errore di battitura" che dirai al tuo capo.

In data.table siamo preoccupati per piccoli dettagli come questo.Quindi abbiamo fatto qualcosa di semplice per evitare di digitare due volte i nomi delle variabili.Qualcosa di molto semplice. i viene valutato nell'ambito di dd già, automaticamente.Non ne hai bisogno with() affatto.

Invece di

dd[with(dd, order(-z, b)), ]

è appena

dd[order(-z, b)]

E invece di

quarterlyreport[with(lastquarterlyreport,order(-z,b)),]

è appena

quarterlyreport[order(-z,b)]

È una differenza molto piccola, ma un giorno potrebbe salvarti il ​​collo.Quando soppesi le diverse risposte a questa domanda, considera il conteggio delle ripetizioni dei nomi delle variabili come uno dei criteri per decidere.Alcune risposte hanno parecchie ripetizioni, altre non ne hanno nessuna.

Ci sono un sacco di risposte eccellenti qui, ma dplyr dà l'unica sintassi che posso in modo rapido e facile da ricordare (e così ora utilizzare molto spesso):

library(dplyr)
# sort mtcars by mpg, ascending... use desc(mpg) for descending
arrange(mtcars, mpg)
# sort mtcars first by mpg, then by cyl, then by wt)
arrange(mtcars , mpg, cyl, wt)

Per il problema del PO:

arrange(dd, desc(z),  b)

    b x y z
1 Low C 9 2
2 Med D 3 1
3  Hi A 8 1
4  Hi A 9 1

Il pacchetto data.table R fornisce sia veloce e efficiente della memoria ordinamento dei data.tables con una sintassi semplice (una parte del quale Matt ha evidenziato abbastanza bene nella sua risposta ). C'è stato un bel po 'di miglioramenti e anche una nuova funzione setorder() da allora. Da v1.9.5+, setorder() funziona anche con data.frames .

Per prima cosa, creeremo un insieme di dati abbastanza grande e punto di riferimento i diversi metodi citati da altre risposte e quindi elencare le caratteristiche di data.table .

Dati:

require(plyr)
require(doBy)
require(data.table)
require(dplyr)
require(taRifx)

set.seed(45L)
dat = data.frame(b = as.factor(sample(c("Hi", "Med", "Low"), 1e8, TRUE)),
                 x = sample(c("A", "D", "C"), 1e8, TRUE),
                 y = sample(100, 1e8, TRUE),
                 z = sample(5, 1e8, TRUE), 
                 stringsAsFactors = FALSE)

Benchmark:

I tempi riportati sono l'esecuzione system.time(...) su queste funzioni mostrate di seguito. I tempi sono tabulati di seguito (in ordine di lenta alla più veloce).

orderBy( ~ -z + b, data = dat)     ## doBy
plyr::arrange(dat, desc(z), b)     ## plyr
arrange(dat, desc(z), b)           ## dplyr
sort(dat, f = ~ -z + b)            ## taRifx
dat[with(dat, order(-z, b)), ]     ## base R

# convert to data.table, by reference
setDT(dat)

dat[order(-z, b)]                  ## data.table, base R like syntax
setorder(dat, -z, b)               ## data.table, using setorder()
                                   ## setorder() now also works with data.frames 

# R-session memory usage (BEFORE) = ~2GB (size of 'dat')
# ------------------------------------------------------------
# Package      function    Time (s)  Peak memory   Memory used
# ------------------------------------------------------------
# doBy          orderBy      409.7        6.7 GB        4.7 GB
# taRifx           sort      400.8        6.7 GB        4.7 GB
# plyr          arrange      318.8        5.6 GB        3.6 GB 
# base R          order      299.0        5.6 GB        3.6 GB
# dplyr         arrange       62.7        4.2 GB        2.2 GB
# ------------------------------------------------------------
# data.table      order        6.2        4.2 GB        2.2 GB
# data.table   setorder        4.5        2.4 GB        0.4 GB
# ------------------------------------------------------------
  • sintassi data.table di DT[order(...)] stato ~ 10x più veloce del più veloce di altri metodi (dplyr), pur consumando la stessa quantità di memoria come dplyr.

  • data.table di setorder() stato ~ 14x più veloce del più veloce di altri metodi (dplyr), durante l'assunzione di solo 0.4GB di memoria aggiuntiva . dat è ora in ordine abbiamo bisogno (in quanto viene aggiornato per riferimento).

caratteristiche data.table:

Velocità:

  • data.table s 'ordinamento è estremamente veloce perché implementa radix ordinare .

  • Il DT[order(...)] sintassi è ottimizzato internamente utilizzare data.table s 'ordinamento veloce pure. È possibile continuare a utilizzare la sintassi di base R familiare ma accelerare il processo (e utilizzare meno memoria).

Memory:

  • La maggior parte delle volte, non richiedono l'originale data.frame o data.table dopo il riordino. Cioè, di solito assegnare il risultato di nuovo allo stesso oggetto, ad esempio:

    DF <- DF[order(...)]
    

    Il problema è che questo richiede almeno due volte (2x) la memoria dell'oggetto originale. Essere efficiente della memoria , data.table quindi fornisce anche una funzione setorder().

    riordini setorder() data.tables by reference ( in-place ), senza apportare ulteriori copie. Si utilizza solo memoria aggiuntiva pari alla dimensione di una colonna.

Altre caratteristiche:

  1. Supporta integer, logical, numeric, character e tipi anche bit64::integer64.

      

    Si noti che factor, Date, POSIXct ecc .. classi sono tutti i tipi integer / numeric sotto con attributi aggiuntivi e sono pertanto supportati.

  2. In base di R, non possiamo usare - su un vettore di carattere per ordinare per quella colonna in ordine decrescente. Invece dobbiamo usare -xtfrm(.).

    Tuttavia, in data.table , possiamo solo fare, per esempio, o dat[order(-x)] setorder(dat, -x).

Con questa funzione (molto utile) da Kevin Wright , pubblicato nella sezione consigli del wiki R, questo è facilmente ottenibile.

sort(dd,by = ~ -z + b)
#     b x y z
# 4 Low C 9 2
# 2 Med D 3 1
# 1  Hi A 8 1
# 3  Hi A 9 1

oppure è possibile utilizzare il pacchetto DOBY

library(doBy)
dd <- orderBy(~-z+b, data=dd)

Supponiamo di avere un data.frame A e si desidera ordinare utilizzando colonna chiamata x ordine decrescente. Chiamare il data.frame newdata ordinato

newdata <- A[order(-A$x),]

Se vuoi per poi sostituirlo con niente "-" ascendente. Si può avere qualcosa di simile

newdata <- A[order(-A$x, A$y, -A$z),]

dove x e z sono alcune colonne in data.frame A. Questo significa ordina data.frame A da x discendente, y ascendente e discendente z.

In alternativa, utilizzando il pacchetto Deducer

library(Deducer)
dd<- sortData(dd,c("z","b"),increasing= c(FALSE,TRUE))

se SQL viene naturalmente a voi, sqldf maniglie ORDER BY come Codd destinato.

La risposta di Dirk è buona, ma se è necessario il tipo di persistere ti consigliamo di applicare l'ordinamento di nuovo sul nome di quella data frame. Utilizzando il codice di esempio:

dd <- dd[with(dd, order(-z, b)), ] 

Ho imparato a conoscere order con il seguente esempio che poi mi ha confuso per molto tempo:

set.seed(1234)

ID        = 1:10
Age       = round(rnorm(10, 50, 1))
diag      = c("Depression", "Bipolar")
Diagnosis = sample(diag, 10, replace=TRUE)

data = data.frame(ID, Age, Diagnosis)

databyAge = data[order(Age),]
databyAge

L'unica ragione per questo esempio funziona è perché order è l'ordinamento per l'vector Age, non dalla colonna denominata Age nel data frame data.

Per vedere questo crea un frame di dati identici utilizzando read.table con leggermente diversi nomi di colonna e senza fare uso di qualsiasi dei vettori di cui sopra:

my.data <- read.table(text = '

  id age  diagnosis
   1  49 Depression
   2  50 Depression
   3  51 Depression
   4  48 Depression
   5  50 Depression
   6  51    Bipolar
   7  49    Bipolar
   8  49    Bipolar
   9  49    Bipolar
  10  49 Depression

', header = TRUE)

La struttura di linea di cui sopra per order non funziona più perché non c'è nessun vettore denominato age:

databyage = my.data[order(age),]

La seguente riga funziona perché i tipi order sulla age colonna my.data.

databyage = my.data[order(my.data$age),]

Ho pensato che questo valeva la pubblicazione dato come ero confuso da questo esempio per così tanto tempo. Se questo post non si ritiene opportuno per il thread che posso toglierlo.

EDIT: 13 maggio 2014

Di seguito è un modo generalizzato di ordinare un frame di dati da ogni colonna senza specificare nomi di colonna. Il codice seguente mostra come ordinare da sinistra a destra o da destra a sinistra. Questo funziona se ogni colonna è numerico. Non ho provato con una colonna di carattere aggiunto.

Ho trovato il codice do.call un mese o due fa, in un vecchio post su un sito diverso, ma solo dopo ampia e difficile ricerca. Non sono sicuro che avrei potuto spostare quel post ora. La presente discussione è il primo colpo per ordinare un data.frame in R. Così, ho pensato che la mia versione ampliata di quel codice do.call originale potrebbe essere utile.

set.seed(1234)

v1  <- c(0,0,0,0, 0,0,0,0, 1,1,1,1, 1,1,1,1)
v2  <- c(0,0,0,0, 1,1,1,1, 0,0,0,0, 1,1,1,1)
v3  <- c(0,0,1,1, 0,0,1,1, 0,0,1,1, 0,0,1,1)
v4  <- c(0,1,0,1, 0,1,0,1, 0,1,0,1, 0,1,0,1)

df.1 <- data.frame(v1, v2, v3, v4) 
df.1

rdf.1 <- df.1[sample(nrow(df.1), nrow(df.1), replace = FALSE),]
rdf.1

order.rdf.1 <- rdf.1[do.call(order, as.list(rdf.1)),]
order.rdf.1

order.rdf.2 <- rdf.1[do.call(order, rev(as.list(rdf.1))),]
order.rdf.2

rdf.3 <- data.frame(rdf.1$v2, rdf.1$v4, rdf.1$v3, rdf.1$v1) 
rdf.3

order.rdf.3 <- rdf.1[do.call(order, as.list(rdf.3)),]
order.rdf.3

In risposta ad un commento aggiunto nel PO per come ordinare a livello di codice:

Utilizzando dplyr e data.table

library(dplyr)
library(data.table)

dplyr

Basta usare arrange_, che è la versione di valutazione standard per arrange.

df1 <- tbl_df(iris)
#using strings or formula
arrange_(df1, c('Petal.Length', 'Petal.Width'))
arrange_(df1, ~Petal.Length, ~Petal.Width)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.4         3.9          1.3         0.4  setosa
7           5.5         3.5          1.3         0.2  setosa
8           4.4         3.0          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...


#Or using a variable
sortBy <- c('Petal.Length', 'Petal.Width')
arrange_(df1, .dots = sortBy)
    Source: local data frame [150 x 5]

   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
          (dbl)       (dbl)        (dbl)       (dbl)  (fctr)
1           4.6         3.6          1.0         0.2  setosa
2           4.3         3.0          1.1         0.1  setosa
3           5.8         4.0          1.2         0.2  setosa
4           5.0         3.2          1.2         0.2  setosa
5           4.7         3.2          1.3         0.2  setosa
6           5.5         3.5          1.3         0.2  setosa
7           4.4         3.0          1.3         0.2  setosa
8           4.4         3.2          1.3         0.2  setosa
9           5.0         3.5          1.3         0.3  setosa
10          4.5         2.3          1.3         0.3  setosa
..          ...         ...          ...         ...     ...

#Doing the same operation except sorting Petal.Length in descending order
sortByDesc <- c('desc(Petal.Length)', 'Petal.Width')
arrange_(df1, .dots = sortByDesc)

maggiori informazioni qui: https://cran.r-project.org/web /packages/dplyr/vignettes/nse.html

E 'meglio usare la formula in quanto coglie anche l'ambiente per valutare un'espressione in

data.table

dt1 <- data.table(iris) #not really required, as you can work directly on your data.frame
sortBy <- c('Petal.Length', 'Petal.Width')
sortType <- c(-1, 1)
setorderv(dt1, sortBy, sortType)
dt1
     Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
  1:          7.7         2.6          6.9         2.3 virginica
  2:          7.7         2.8          6.7         2.0 virginica
  3:          7.7         3.8          6.7         2.2 virginica
  4:          7.6         3.0          6.6         2.1 virginica
  5:          7.9         3.8          6.4         2.0 virginica
 ---                                                            
146:          5.4         3.9          1.3         0.4    setosa
147:          5.8         4.0          1.2         0.2    setosa
148:          5.0         3.2          1.2         0.2    setosa
149:          4.3         3.0          1.1         0.1    setosa
150:          4.6         3.6          1.0         0.2    setosa

Arrange () in dplyer è la mia opzione preferita. Utilizzare l'operatore di pipe e passare da almeno importante aspetto più importante

dd1 <- dd %>%
    arrange(z) %>%
    arrange(desc(x))

Per ragioni di completezza: è anche possibile utilizzare la funzione sortByCol() dal pacchetto BBmisc:

library(BBmisc)
sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE))
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Confronto delle prestazioni:

library(microbenchmark)
microbenchmark(sortByCol(dd, c("z", "b"), asc = c(FALSE, TRUE)), times = 100000)
median 202.878

library(plyr)
microbenchmark(arrange(dd,desc(z),b),times=100000)
median 148.758

microbenchmark(dd[with(dd, order(-z, b)), ], times = 100000)
median 115.872

Proprio come le selezionatrici di carte meccanici di un tempo, Ordina la chiave meno significativo, quindi il prossimo più significativo, ecc Nessun libreria richiesta, funziona con qualsiasi numero di chiavi e qualsiasi combinazione di salire e scendere le chiavi.

 dd <- dd[order(dd$b, decreasing = FALSE),]

Ora siamo pronti a fare la chiave più significativo. L'ordinamento è stabile, e gli eventuali legami nella chiave più significativi sono già stati risolti.

dd <- dd[order(dd$z, decreasing = TRUE),]

Questo può non essere il più veloce, ma è certamente semplice e affidabile

Un'altra alternativa, utilizzando il pacchetto rgr:

> library(rgr)
> gx.sort.df(dd, ~ -z+b)
    b x y z
4 Low C 9 2
2 Med D 3 1
1  Hi A 8 1
3  Hi A 9 1

Stavo lottando con le soluzioni di cui sopra quando ho voluto automatizzare il mio processo di ordinazione per le colonne n, i cui nomi colonna potrebbe essere diverso ogni volta. Ho trovato una funzione super disponibile dal pacchetto psych per fare questo in modo semplice:

dfOrder(myDf, columnIndices)

dove columnIndices sono indici di una o più colonne, nell'ordine in cui si desidera ordinarli. Maggiori informazioni qui:

funzione dfOrder da 'psych' pacchetto

Solo per ragioni di completezza, dal momento che non molto è stato detto circa l'ordinamento per numeri di colonna ... Si può sicuramente affermare che spesso non è desiderabile (perché l'ordine delle colonne potrebbe cambiare, aprendo la strada ad errori ), ma in alcune situazioni specifiche (quando, per esempio, è necessario un lavoro rapido e non vi sia alcun rischio del genere di colonne mutevoli ordini), potrebbe essere la cosa più sensata da fare, soprattutto quando si tratta di un gran numero di colonne.

In questo caso, do.call() viene in soccorso:

ind <- do.call(what = "order", args = iris[,c(5,1,2,3)])
iris[ind, ]

##        Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
##    14           4.3         3.0          1.1         0.1     setosa
##    9            4.4         2.9          1.4         0.2     setosa
##    39           4.4         3.0          1.3         0.2     setosa
##    43           4.4         3.2          1.3         0.2     setosa
##    42           4.5         2.3          1.3         0.3     setosa
##    4            4.6         3.1          1.5         0.2     setosa
##    48           4.6         3.2          1.4         0.2     setosa
##    7            4.6         3.4          1.4         0.3     setosa
##    (...)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top