2013-01-21 11 views
10

Durante l'esperimento con per un'altra domanda here, ho riscontrato un risultato piuttosto strano. Non riesco a capire perché e mi chiedo se quello che sto facendo sia totalmente sbagliato.output imprevisto dall'aggregato

Supponiamo, ho un data.frame come questo:

df <- structure(list(V1 = c(1L, 2L, 1L, 2L, 3L, 1L), 
        V2 = c(2L, 3L, 2L, 3L, 4L, 2L), 
        V3 = c(3L, 4L, 3L, 4L, 5L, 3L), 
        V4 = c(4L, 5L, 4L, 5L, 6L, 4L)), 
        .Names = c("V1", "V2", "V3", "V4"), 
     row.names = c(NA, -6L), class = "data.frame") 
> df 
# V1 V2 V3 V4 
# 1 1 2 3 4 
# 2 2 3 4 5 
# 3 1 2 3 4 
# 4 2 3 4 5 
# 5 3 4 5 6 
# 6 1 2 3 4 

Ora, se mi vuoi mostrare un data.frame con righe uniche con una colonna aggiuntiva che indica la loro frequenza in df. Per questo esempio,

# V1 V2 V3 V4 x 
# 1 1 2 3 4 3 
# 2 2 3 4 5 2 
# 3 3 4 5 6 1 

ho ottenuto questo risultato usando aggregate sperimentando come segue:

> aggregate(do.call(paste, df), by=df, print) 

# [1] "1 2 3 4" "1 2 3 4" "1 2 3 4" 
# [1] "2 3 4 5" "2 3 4 5" 
# [1] "3 4 5 6" 
# V1 V2 V3 V4       x 
# 1 1 2 3 4 1 2 3 4, 1 2 3 4, 1 2 3 4 
# 2 2 3 4 5   2 3 4 5, 2 3 4 5 
# 3 3 4 5 6     3 4 5 6 

Quindi, questo mi ha dato la stringa incollato. Quindi, se dovessi usare length anziché print, dovrebbe darmi il numero di tali occorrenze, che è il risultato desiderato, che è il caso (come mostrato di seguito).

> aggregate(do.call(paste, df), by=df, length) 
# V1 V2 V3 V4 x 
# 1 1 2 3 4 3 
# 2 2 3 4 5 2 
# 3 3 4 5 6 1 

E questo sembrava funzionare. Tuttavia, quando le dimensioni di data.frame sono 4 * 2500, l'uscita data.frame è 1 * 2501 anziché 4 * 2501 (tutte le righe sono univoche, quindi la frequenza è 1).

> df <- as.data.frame(matrix(sample(1:3, 1e4, replace = TRUE), nrow=4)) 
> o <- aggregate(do.call(paste, df), by=df, length) 
> dim(o) 
# [1] 1 2501 

ho testato con piccole data.frames con righe appena uniche e dà l'uscita destra (cambio nrow=40, per esempio). Tuttavia, quando le dimensioni della matrice aumentano, non sembra funzionare. E proprio non riesco a capire cosa sta andando storto! Qualche idea?

+2

Forse, perché le stringhe diventano troppo lunghe e 'as.character' inserisce interruzioni di riga? – Roland

+0

sì, in alternativa si potrebbe fare 'aggregare (rep (1, nrow (df)), df, FUN = length)'. – flodel

+1

Questo non ha nulla a che fare con 'as.character()' dato che ciascuno degli argomenti è un vettore di lunghezza 1. Per vedere che questa parte funziona, basta fare do.call (paste, df [1: 3,]) '. –

risposta

10

Il problema qui è come aggregate.data.frame() determina i gruppi.

In aggregate.data.frame() c'è un ciclo che forma la variabile di raggruppamento grp. In questo ciclo, grp è alterata/aggiornamento tramite:

grp <- grp * nlevels(ind) + (as.integer(ind) - 1L) 

Il problema con il tuo esempio, se che una volta by viene convertito in fattori, e il ciclo si è andati oltre tutte di questi fattori, nel tuo esempio grp estremità up essere:

Browse[2]> grp 
[1] Inf Inf Inf Inf 

Essenzialmente l'aggiornamento loop spinto i valori di grp ad un numero indistinguibile da Inf.

Fatto questo, aggregate.data.frame() poi fa questo

y <- y[match(sort(unique(grp)), grp, 0L), , drop = FALSE] 

e questo è dove il problema in precedenza ora si manifesta come

dim(y[match(sort(unique(grp)), grp, 0L), , drop = FALSE]) 

perché

match(sort(unique(grp)), grp, 0L) 

restituisce con chiarezza solo 1:

> match(sort(unique(grp)), grp, 0L) 
[1] 1 

in quanto esiste un solo valore univoco di grp.

+1

Ci sono solo troppi gruppi formati da 'by'. Non ti consiglio di farlo, ma un altro modo per vedere il problema è quello di formare i frame secondari che l'aggregazione potrebbe funzionare su di esso il 'grp' non è andato a' Inf': 'length (split (do.call (incolla, df), df)) '. ** AVVISO ** che consumerà tutta la tua RAM (sul mio portatile da 4 GB stavo rapidamente sostituendo lo spazio di swap). –

+1

@Arun yep, 'debugonce()' è tuo amico per questo genere di cose. –