2013-04-08 3 views
33

Jak uzyskać ramkę danych z tymi samymi danymi, co już istniejąca macierz?Utwórz ramkę danych z macierzy w R

Uproszczony przykład mojej matrycy:

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 

chciałbym stworzyć ramkę danych, który wygląda tak:

 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 

Wszystkie moje próby są dość niezdarna, na przykład:

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"])))) 

Czy ktoś ma pomysł, jak to zrobić bardziej elegancko? Proszę zauważyć, że moje prawdziwe dane mają kilka dodatkowych kolumn (40 kolumn).

+2

Szukasz 'melt'?. Szukaj również '[r] reshape2' w polu wyszukiwania SO –

+1

Więcej informacji tutaj: [www.statmethods.net/management/reshape.html](http://www.statmethods.net/management/reshape.html). – Backlin

Odpowiedz

33

Jeśli zmienisz swoją kolumnę time na nazwy wierszy, możesz użyć as.data.frame(as.table(mat)) dla prostych takich przypadków.

przykład:

> 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 

W tym przypadku czas i nazwa są czynnikami. Konieczna może być konwersja czasu z powrotem na wartość numeryczną lub może nie mieć znaczenia.

4

melt() z reshape2 pakiet ją zamknąć ...

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 

... chociaż może chcesz postprocesowego swoje wyniki, aby uzyskać preferowane nazwy kolumn i kolejnością.

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

Dzięki! Próbowałem 'melt (mat, id =" time ")' po komentarzach powyżej, ale nie mogłem wymyślić, że potrzebuję 'as.data.frame (mat)' – user1981275

8

Możesz użyć stack z pakietu podstawowego. Ale musisz najpierw przekonstruować macierz do data.frame i zmienić kolejność kolumn po ułożeniu danych.

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 

Zauważ, że stack jest generalnie bardziej wydajne niż opakowaniu reshape2.

+0

Wolę rozwiązanie 'stack', także dlatego, że wygrałem trzeba załadować 'reshape2' – user1981275

0

Znalazłem następującą "oszukiwać" pracować bardzo starannie i bezbłędną

> 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 voila!

0

Korzystanie dplyr i 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