Konwertuj listę na ramkę danych
Mam zagnieżdżoną listę danych. Jego długość wynosi 132, a każdy element jest listą długości 20. Czy istnieje Szybki sposób na przekształcenie tej struktury w ramkę danych, która ma 132 wiersze i 20 kolumn danych?
Oto przykładowe dane do pracy:
l <- replicate(
132,
as.list(sample(letters, 20)),
simplify = FALSE
)
22 answers
Aktualizacja Lipiec 2020:
Wartością domyślną dla parametru stringsAsFactors
jest teraz default.stringsAsFactors()
, co z kolei daje FALSE
jako wartość domyślną.
Zakładając, że Twoja lista list nazywa się l
:
df <- data.frame(matrix(unlist(l), nrow=length(l), byrow=TRUE))
Powyższe konwertuje wszystkie kolumny znaków na czynniki, aby tego uniknąć, możesz dodać parametr do danych.frame() wywołanie:
df <- data.frame(matrix(unlist(l), nrow=132, byrow=TRUE),stringsAsFactors=FALSE)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-02-05 13:46:42
Z rbind
do.call(rbind.data.frame, your_list)
Edit: poprzednia wersja zwraca data.frame
z list
zamiast wektorów (jak zauważył @IanSudbery w komentarzach).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-29 16:13:28
Możesz użyć pakietu plyr
.
Na przykład zagnieżdżona lista formularza
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
Ma teraz długość 4, a każda lista w l
zawiera kolejną listę o długości 3.
Teraz możesz uruchomić
library (plyr)
df <- ldply (l, data.frame)
I powinien dostać taki sam wynik jak w odpowiedzi @Marek i @nico.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-19 17:07:46
Ustalanie przykładowych danych tak, aby pasowały do oryginalnego opisu "każdy element jest listą długości 20"
mylistlist <- replicate(
132,
as.list(sample(letters, 20)),
simplify = FALSE
)
Możemy przekonwertować go do ramki danych w następujący sposób:
data.frame(t(sapply(mylistlist,c)))
sapply
przekształca go w matrycę.
data.frame
konwertuje matrycę na ramkę danych.
W wyniku:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-11 20:01:23
Załóżmy, że Twoja lista nazywa się L
,
data.frame(Reduce(rbind, L))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-24 14:49:15
Pakiet data.table
posiada funkcję rbindlist
, która jest superszybką implementacją do.call(rbind, list(...))
.
Może mieć listę lists
, data.frames
lub data.tables
jako wejście.
library(data.table)
ll <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
DT <- rbindlist(ll)
Zwraca data.table
dziedziczenie z data.frame
.
Jeśli naprawdę. chcesz przekonwertować z powrotem na dane.użycie ramki as.data.frame(DT)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-25 21:59:44
Pakiet tibble
posiada funkcję enframe()
, która rozwiązuje ten problem poprzez wymuszenie zagnieżdżonych obiektów list
do zagnieżdżonych obiektów tibble
("tidy" ramka danych). Oto krótki przykład z R dla Data Science :
x <- list(
a = 1:5,
b = 3:4,
c = 5:6
)
df <- enframe(x)
df
#> # A tibble: 3 × 2
#> name value
#> <chr> <list>
#> 1 a <int [5]>
#> 2 b <int [2]>
#> 3 c <int [2]>
Ponieważ masz kilka gniazd na liście, l
, możesz użyć unlist(recursive = FALSE)
, aby usunąć niepotrzebne zagnieżdżanie, aby uzyskać tylko jedną hierarchiczną listę, a następnie przejść do enframe()
. Używam tidyr::unnest()
, aby unnest wyjście do jednego poziomu" tidy " ramki danych, która ma dwie kolumny (jedna dla grupy name
i jeden dla obserwacji z grupami value
). Jeśli chcesz, aby kolumny były szerokie, możesz dodać kolumnę za pomocą add_column()
, która po prostu powtarza kolejność wartości 132 razy. Następnie po prostu spread()
wartości.
library(tidyverse)
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
l_tib <- l %>%
unlist(recursive = FALSE) %>%
enframe() %>%
unnest()
l_tib
#> # A tibble: 2,640 x 2
#> name value
#> <int> <chr>
#> 1 1 d
#> 2 1 z
#> 3 1 l
#> 4 1 b
#> 5 1 i
#> 6 1 j
#> 7 1 g
#> 8 1 w
#> 9 1 r
#> 10 1 p
#> # ... with 2,630 more rows
l_tib_spread <- l_tib %>%
add_column(index = rep(1:20, 132)) %>%
spread(key = index, value = value)
l_tib_spread
#> # A tibble: 132 x 21
#> name `1` `2` `3` `4` `5` `6` `7` `8` `9` `10` `11`
#> * <int> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
#> 1 1 d z l b i j g w r p y
#> 2 2 w s h r i k d u a f j
#> 3 3 r v q s m u j p f a i
#> 4 4 o y x n p i f m h l t
#> 5 5 p w v d k a l r j q n
#> 6 6 i k w o c n m b v e q
#> 7 7 c d m i u o e z v g p
#> 8 8 f s e o p n k x c z h
#> 9 9 d g o h x i c y t f j
#> 10 10 y r f k d o b u i x s
#> # ... with 122 more rows, and 9 more variables: `12` <chr>, `13` <chr>,
#> # `14` <chr>, `15` <chr>, `16` <chr>, `17` <chr>, `18` <chr>,
#> # `19` <chr>, `20` <chr>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-10 20:15:21
W zależności od struktury twoich list istnieje kilka opcji tidyverse
, które dobrze działają z listami o nierównej długości:
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5)
, c = list(var.1 = 7, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = NA))
df <- dplyr::bind_rows(l)
df <- purrr::map_df(l, dplyr::bind_rows)
df <- purrr::map_df(l, ~.x)
# all create the same data frame:
# A tibble: 4 x 3
var.1 var.2 var.3
<dbl> <dbl> <dbl>
1 1 2 3
2 4 5 NA
3 7 NA 9
4 10 11 NA
Można również mieszać wektory i ramki danych:
library(dplyr)
bind_rows(
list(a = 1, b = 2),
data_frame(a = 3:4, b = 5:6),
c(a = 7)
)
# A tibble: 4 x 2
a b
<dbl> <dbl>
1 1 2
2 3 5
3 4 6
4 7 NA
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-11 02:07:45
Reshape2 daje takie samo wyjście jak powyższy przykład plyr:
library(reshape2)
l <- list(a = list(var.1 = 1, var.2 = 2, var.3 = 3)
, b = list(var.1 = 4, var.2 = 5, var.3 = 6)
, c = list(var.1 = 7, var.2 = 8, var.3 = 9)
, d = list(var.1 = 10, var.2 = 11, var.3 = 12)
)
l <- melt(l)
dcast(l, L1 ~ L2)
L1 var.1 var.2 var.3
1 a 1 2 3
2 b 4 5 6
3 c 7 8 9
4 d 10 11 12
Jeśli prawie zabrakło pikseli, mógłbyś zrobić to wszystko w jednej linii z funkcją przekształcania ().
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-16 19:26:14
Ta metoda wykorzystuje pakiet tidyverse
(purrr).
Lista:
x <- as.list(mtcars)
Przekształcenie go w ramkę danych (a tibble
dokładniej):
library(purrr)
map_df(x, ~.x)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-30 02:00:12
Więcej odpowiedzi, wraz z czasem odpowiedzi na to pytanie: Jaki jest najskuteczniejszy sposób tworzenia listy jako ramki danych?
Najszybszy sposób, który nie tworzy ramki danych z listami, a nie wektorami dla kolumn wydaje się być (z odpowiedzi Martina Morgana):
l <- list(list(col1="a",col2=1),list(col1="b",col2=2))
f = function(x) function(i) unlist(lapply(x, `[[`, i), use.names=FALSE)
as.data.frame(Map(f(l), names(l[[1]])))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:33
ODPOWIEDŹ @Marek: jeśli chcesz uniknąć przerobienia ciągów na czynniki, a wydajność nie jest problemem spróbuj
do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-28 10:31:40
Dla ogólnego przypadku głęboko zagnieżdżonych list z 3 lub więcej poziomami jak te uzyskane z zagnieżdżonego JSON:
{
"2015": {
"spain": {"population": 43, "GNP": 9},
"sweden": {"population": 7, "GNP": 6}},
"2016": {
"spain": {"population": 45, "GNP": 10},
"sweden": {"population": 9, "GNP": 8}}
}
Rozważ podejście melt()
, Aby przekonwertować zagnieżdżoną listę na wysoki format:
myjson <- jsonlite:fromJSON(file("test.json"))
tall <- reshape2::melt(myjson)[, c("L1", "L2", "L3", "value")]
L1 L2 L3 value
1 2015 spain population 43
2 2015 spain GNP 9
3 2015 sweden population 7
4 2015 sweden GNP 6
5 2016 spain population 45
6 2016 spain GNP 10
7 2016 sweden population 9
8 2016 sweden GNP 8
Następnie dcast()
Następnie ponownie do szerokiego zbioru danych, gdzie każda zmienna tworzy kolumnę a, a każda obserwacja tworzy wiersz:
wide <- reshape2::dcast(tall, L1+L2~L3)
# left side of the formula defines the rows/observations and the
# right side defines the variables/measurements
L1 L2 GNP population
1 2015 spain 9 43
2 2015 sweden 6 7
3 2016 spain 10 45
4 2016 sweden 8 9
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-06 12:37:07
Czasami dane mogą być listą list wektorów o tej samej długości.
lolov = list(list(c(1,2,3),c(4,5,6)), list(c(7,8,9),c(10,11,12),c(13,14,15)) )
(wewnętrzne wektory mogą być również listami, ale upraszczam, aby ułatwić czytanie).
Następnie możesz wprowadzić następującą modyfikację. Pamiętaj, że możesz nie wyświetlać jednego poziomu na raz:
lov = unlist(lolov, recursive = FALSE )
> lov
[[1]]
[1] 1 2 3
[[2]]
[1] 4 5 6
[[3]]
[1] 7 8 9
[[4]]
[1] 10 11 12
[[5]]
[1] 13 14 15
Teraz użyj swojej ulubionej metody wymienionej w innych odpowiedziach:
library(plyr)
>ldply(lov)
V1 V2 V3
1 1 2 3
2 4 5 6
3 7 8 9
4 10 11 12
5 13 14 15
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-27 18:34:41
To w końcu mi się udało:
do.call("rbind", lapply(S1, as.data.frame))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 11:15:24
Dla rozwiązania równoległego (wielordzeniowego, wielosesyjnego itp.) używającego rodziny rozwiązań purrr
, Użyj:
library (furrr)
plan(multisession) # see below to see which other plan() is the more efficient
myTibble <- future_map_dfc(l, ~.x)
Gdzie l
jest listą.
Aby porównać najefektywniejsze plan()
możesz użyć:
library(tictoc)
plan(sequential) # reference time
# plan(multisession) # benchamark plan() goes here. See ?plan().
tic()
myTibble <- future_map_dfc(l, ~.x)
toc()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-23 10:42:06
Zadziałało dla mnie następujące proste polecenie:
myDf <- as.data.frame(myList)
Reference (Quora answer )
> myList <- list(a = c(1, 2, 3), b = c(4, 5, 6))
> myList
$a
[1] 1 2 3
$b
[1] 4 5 6
> myDf <- as.data.frame(myList)
a b
1 1 4
2 2 5
3 3 6
> class(myDf)
[1] "data.frame"
Ale to się nie powiedzie, jeśli nie jest oczywiste, jak przekonwertować listę na ramkę danych:
> myList <- list(a = c(1, 2, 3), b = c(4, 5, 6, 7))
> myDf <- as.data.frame(myList)
Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, :
arguments imply differing number of rows: 3, 4
Uwaga : odpowiedź jest w kierunku tytułu pytania i może pominąć niektóre szczegóły pytania
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-03-15 04:53:59
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-20 17:48:48
Krótkim (ale być może nie najszybszym) sposobem na to byłoby użycie bazy r, ponieważ ramka danych jest tylko listą wektorów o równej długości . W ten sposób konwersja między listą wejściową a danymi 30 x 132.ramka będzie:
df <- data.frame(l)
Stamtąd możemy transponować go do matrycy 132 x 30 i konwertować z powrotem do ramki danych:
new_df <- data.frame(t(df))
Jako jednoliterowy:
new_df <- data.frame(t(data.frame(l)))
Nazwy wierszy będą dość irytujące, ale zawsze można je zmienić z
rownames(new_df) <- 1:nrow(new_df)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-02 21:36:23
Każde znalezione rozwiązanie wydaje się mieć zastosowanie tylko wtedy, gdy każdy obiekt w list
ma to samo length
. Musiałem przekonwertować list
na data.frame
, Gdy length
obiektów w list
były nierówne length
. Poniżej znajduje się baza R
rozwiązanie, które wymyśliłem. Bez wątpienia jest to bardzo nieefektywne, ale wydaje się działać.
x1 <- c(2, 13)
x2 <- c(2, 4, 6, 9, 11, 13)
x3 <- c(1, 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13)
my.results <- list(x1, x2, x3)
# identify length of each list
my.lengths <- unlist(lapply(my.results, function (x) { length(unlist(x))}))
my.lengths
#[1] 2 6 20
# create a vector of values in all lists
my.values <- as.numeric(unlist(c(do.call(rbind, lapply(my.results, as.data.frame)))))
my.values
#[1] 2 13 2 4 6 9 11 13 1 1 2 3 3 4 5 5 6 7 7 8 9 9 10 11 11 12 13 13
my.matrix <- matrix(NA, nrow = max(my.lengths), ncol = length(my.lengths))
my.cumsum <- cumsum(my.lengths)
mm <- 1
for(i in 1:length(my.lengths)) {
my.matrix[1:my.lengths[i],i] <- my.values[mm:my.cumsum[i]]
mm <- my.cumsum[i]+1
}
my.df <- as.data.frame(my.matrix)
my.df
# V1 V2 V3
#1 2 2 1
#2 13 4 1
#3 NA 6 2
#4 NA 9 3
#5 NA 11 3
#6 NA 13 4
#7 NA NA 5
#8 NA NA 5
#9 NA NA 6
#10 NA NA 7
#11 NA NA 7
#12 NA NA 8
#13 NA NA 9
#14 NA NA 9
#15 NA NA 10
#16 NA NA 11
#17 NA NA 11
#18 NA NA 12
#19 NA NA 13
#20 NA NA 13
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-30 04:36:03
Może użyjesz funkcji map_
razem z pętlą for
? Oto moje rozwiązanie:
list_to_df <- function(list_to_convert) {
tmp_data_frame <- data.frame()
for (i in 1:length(list_to_convert)) {
tmp <- map_dfr(list_to_convert[[i]], data.frame)
tmp_data_frame <- rbind(tmp_data_frame, tmp)
}
return(tmp_data_frame)
}
Gdzie map_dfr
konwertuje każdy element listy na dane.ramki, a następnie rbind
połącz je w całość.
W Twoim przypadku chyba byłoby:
converted_list <- list_to_df(l)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-29 07:25:50
Try collapse::unlist2d
(skrót od 'unlist to data.frame'):
l <- replicate(
132,
list(sample(letters, 20)),
simplify = FALSE
)
library(collapse)
head(unlist2d(l))
.id.1 .id.2 V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20
1 1 1 e x b d s p a c k z q m u l h n r t o y
2 2 1 r t i k m b h n s e p f o c x l g v a j
3 3 1 t r v z a u c o w f m b d g p q y e n k
4 4 1 x i e p f d q k h b j s z a t v y l m n
5 5 1 d z k y a p b h c v f m u l n q e i w j
6 6 1 l f s u o v p z q e r c h n a t m k y x
head(unlist2d(l, idcols = FALSE))
V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20
1 e x b d s p a c k z q m u l h n r t o y
2 r t i k m b h n s e p f o c x l g v a j
3 t r v z a u c o w f m b d g p q y e n k
4 x i e p f d q k h b j s z a t v y l m n
5 d z k y a p b h c v f m u l n q e i w j
6 l f s u o v p z q e r c h n a t m k y x
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-01 22:05:14