Comment obtenir un bloc de données avec les mêmes données qu'une matrice 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 cadre 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 la manière de procéder plus élégamment? Veuillez noter que mes données réelles comportent quelques colonnes supplémentaires (40 colonnes).
Si vous modifiez 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 voudrez peut-être reconvertir l'heure en numérique, ou ce n'est peut-être pas grave.
Vous pouvez utiliser stack
à partir du package de base. Mais vous devez d’abord contraindre votre matrice à un data.frame
et réorganiser les colonnes une fois les données 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 package reshape2
.
melt()
de reshape2 package vous rapproche ...
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 peut-être post-traiter ses résultats pour obtenir vos noms de colonnes et vos commandes 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
Utiliser 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é le "cheat" suivant très net 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à!