Créer un dataframe à partir d'une matrice
Comment obtenir une trame de données avec les mêmes données qu'une matrice déjà existante?
Un exemple simplifié de ma 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
Je voudrais créer un bloc de données qui ressemble à ceci:
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
Toutes mes tentatives sont assez maladroites, par exemple:
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"]))))
Quelqu'un a-t-il une idée de comment faire cela plus élégamment? Veuillez noter que mes données réelles ont quelques colonnes de plus (40 colonnes).
5 réponses
Si vous changez votre colonne time
en noms de lignes, vous pouvez utiliser as.data.frame(as.table(mat))
pour des cas simples comme celui-ci.
Exemple:
> 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
Dans ce cas, le temps et le nom sont les deux facteurs. Vous pouvez convertir le temps en numérique, ou cela peut ne pas avoir d'importance.
Vous pouvez utiliser stack
à partir du paquet de base. Mais, vous devez d'abord forcer votre matrice à un data.frame
et réorganiser les colonnes une fois que les données sont empilées.
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
Notez que stack
est généralement plus efficace que le paquet reshape2
.
melt()
à partir du paquet reshape2 , vous vous rapprochez ...
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
... bien que vous souhaitiez post-traiter ses résultats pour obtenir vos noms de colonnes et votre ordre préférés.
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
En utilisant dplyr
et 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
J'ai trouvé la "triche" suivante pour fonctionner très proprement et sans erreur
> 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à!