2013-04-08 18 views
33

Come ottenere un frame di dati con gli stessi dati di una matrice già esistente?Crea frame dati da una matrice in R

Un esempio semplificato della mia matrice:

mat <- matrix(c(0, 0.5, 1, 0.1, 0.2, 0.3, 0.3, 0.4, 0.5), 
       ncol=3, nrow=3, 
       dimnames=list(NULL, c("time", "C_0", "C_1"))) 

> mat 
    time C_0 C_1 
[1,] 0.0 0.1 0.3 
[2,] 0.5 0.2 0.4 
[3,] 1.0 0.3 0.5 

Vorrei creare un frame di dati che assomiglia a questo:

 name time val 
1 C_0 0.0 0.1 
2 C_0 0.5 0.2 
3 C_0 1.0 0.3 
4 C_1 0.0 0.3 
5 C_1 0.5 0.4 
6 C_1 1.0 0.5 

tutti i miei tentativi sono abbastanza goffo, ad esempio:

data.frame(cbind(c(rep("C_1", 3), rep("C_2", 3)), 
       rbind(cbind(mat[,"time"], mat[,"C_0"]), 
         cbind(mat[,"time"], mat[,"C_1"])))) 

Qualcuno ha un'idea di come farlo in modo più elegante? Si noti che i miei dati reali hanno un numero di colonne in più (40 colonne).

+2

Siete alla ricerca di 'melt'?. Cerca anche '[r] reshape2' nella casella di ricerca SO –

+1

Ulteriori informazioni qui: [www.statmethods.net/management/reshape.html](http://www.statmethods.net/management/reshape.html). – Backlin

risposta

33

Se si modifica la colonna time in nomi di riga, è possibile utilizzare as.data.frame(as.table(mat)) per casi semplici come questo.

Esempio:

> data <- c(0.1, 0.2, 0.3, 0.3, 0.4, 0.5) 
> dimnames <- list(time=c(0, 0.5, 1), name=c("C_0", "C_1")) 
> mat <- matrix(data, ncol=2, nrow=3, dimnames=dimnames) 
> as.data.frame(as.table(mat)) 
    time name Freq 
1 0 C_0 0.1 
2 0.5 C_0 0.2 
3 1 C_0 0.3 
4 0 C_1 0.3 
5 0.5 C_1 0.4 
6 1 C_1 0.5 

In questo caso il tempo e il nome sono entrambi fattori. Potresti voler convertire il tempo in numerico o potrebbe non avere importanza.

4

melt() dal reshape2 pacchetto ottiene si chiude ...

library(reshape2) 
(res <- melt(as.data.frame(mat), id="time")) 
# time variable value 
# 1 0.0  C_0 0.1 
# 2 0.5  C_0 0.2 
# 3 1.0  C_0 0.3 
# 4 0.0  C_1 0.3 
# 5 0.5  C_1 0.4 
# 6 1.0  C_1 0.5 

... anche se si consiglia di post-processo i risultati per ottenere i nomi di colonna preferiti e l'ordinamento.

setNames(res[c("variable", "time", "value")], c("name", "time", "val")) 
# name time val 
# 1 C_0 0.0 0.1 
# 2 C_0 0.5 0.2 
# 3 C_0 1.0 0.3 
# 4 C_1 0.0 0.3 
# 5 C_1 0.5 0.4 
# 6 C_1 1.0 0.5 
+0

Grazie! Ho provato 'melt (mat, id =" time ")' dopo i commenti sopra ma non riuscivo a capire che ho bisogno di 'as.data.frame (mat)' – user1981275

8

È possibile utilizzare stack dal pacchetto base. Tuttavia, è necessario prima costringere la matrice a data.frame e riordinare le colonne una volta che i dati sono stati impilati.

mat <- as.data.frame(mat) 
res <- data.frame(time= mat$time,stack(mat,select=-time)) 
res[,c(3,1,2)] 

    ind time values 
1 C_0 0.0 0.1 
2 C_0 0.5 0.2 
3 C_0 1.0 0.3 
4 C_1 0.0 0.3 
5 C_1 0.5 0.4 
6 C_1 1.0 0.5 

noti che stack è generalmente più efficiente del pacchetto reshape2.

+0

Preferisco la soluzione 'stack', anche perché ho vinto 'necessario caricare 'reshape2' – user1981275

0

ho trovato il seguente "barare" per lavorare molto ordinatamente e senza errori

> dimnames <- list(time=c(0, 0.5, 1), name=c("C_0", "C_1")) 
> mat <- matrix(data, ncol=2, nrow=3, dimnames=dimnames) 
> head(mat, 2) #this returns the number of rows indicated in a data frame format 
> df <- data.frame(head(mat, 2)) #"data.frame" might not be necessary 

Et voilà!

0

Utilizzando dplyr e tidyr:

library(dplyr) 
library(tidyr) 

df <- as_data_frame(mat) %>%  # convert the matrix to a data frame 
    gather(name, val, C_0:C_1) %>% # convert the data frame from wide to long 
    select(name, time, val)   # reorder the columns 

df 
# A tibble: 6 x 3 
    name time val 
    <chr> <dbl> <dbl> 
1 C_0 0.0 0.1 
2 C_0 0.5 0.2 
3 C_0 1.0 0.3 
4 C_1 0.0 0.3 
5 C_1 0.5 0.4 
6 C_1 1.0 0.5 
Problemi correlati