목록을 데이터 프레임으로 변환


513

중첩 된 데이터 목록이 있습니다. 길이는 132이고 각 항목은 길이가 20 인 목록입니다. 이 구조를 132 행과 20 열의 데이터가있는 데이터 프레임으로 변환 하는 빠른 방법이 있습니까?

다음은 사용할 샘플 데이터입니다.

l <- replicate(
  132,
  list(sample(letters, 20)),
  simplify = FALSE
)

따라서 각 목록 요소를 data.frame의 데이터 행으로 원하십니까?
Joshua Ulrich

2
@RichieCotton 그것은 좋은 예가 아닙니다. "각 항목은 길이가 20 인 목록 "이고 각 항목은 길이가 20 인 벡터 의 한 요소 목록을 얻었습니다 .
Marek

1
파티에 늦었지만 아무도 이것을 언급하지 못했습니다. 매우 편리하다고 생각했습니다 (내가 원하는 것을 위해).
mflo-ByeSE


답변:


390

목록의 목록을 다음과 같이 가정합니다 l.

df <- data.frame(matrix(unlist(l), nrow=length(l), byrow=T))

위의 모든 문자 열을 인수로 변환하여 data.frame () 호출에 매개 변수를 추가 할 수 있습니다.

df <- data.frame(matrix(unlist(l), nrow=132, byrow=T),stringsAsFactors=FALSE)

109
데이터가 모두 같은 유형이 아닌 경우주의하십시오. 행렬을 통과하면 모든 데이터가 공통 유형으로 강제 변환됩니다. 즉, 하나의 문자 데이터 열과 하나의 숫자 데이터 열이 있으면 숫자 데이터는 matrix ()에 의해 문자열로 강제 변환되고 data.frame ()에 의해 인수 분해됩니다.
Ian Sudbery

목록에 결 측값이 있거나 데이터 프레임에 NA를 포함시키는 가장 좋은 방법은 무엇입니까?
Dave

1
@ 데이브 : 나를 위해 작동 ... 참조 r-fiddle.org/#/fiddle?id=y8DW7lqL&version=3
nico

4
문자 데이터 형식이있는 경우에도주의하십시오. data.frame은이를 문자로 변환합니다.
Alex Brown

4
@nico df에서 목록 요소 이름을 colname 또는 rowname으로 유지하는 방법이 있습니까?
N.Varela

472

rbind

do.call(rbind.data.frame, your_list)

편집 : 이전 버전 반환 data.framelist(@IanSudbery 댓글에서 지적) '는 벡터 대신이야.


5
왜 이것이 작동하지만 rbind(your_list)1x32 목록 행렬을 반환합니까?
eykanal

26
@eykanal은의 인수로의 do.call요소를 your_list전달합니다 rbind. 와 동일 rbind(your_list[[1]], your_list[[2]], your_list[[3]], ....., your_list[[length of your_list]])합니다.
Marek

2
이 방법은 null 상황에서 어려움을 겪습니다.
Frank Wang

3
@FrankWANG 그러나이 방법은 상황을 무효화하도록 설계되지 않았습니다. your_list동일한 크기의 벡터 를 포함 해야합니다 . NULL길이가 0이므로 실패해야합니다.
Marek

12
이 방법은 올바른 객체를 반환하는 것처럼 보이지만 객체를 검사 할 때 열이 벡터가 아닌 목록이기 때문에 예상치 못한 경우 선 아래로 문제가 발생할 수 있습니다.
Ian Sudbery

135

plyr패키지 를 사용할 수 있습니다 . 예를 들어 양식의 중첩 목록

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

이제 길이가 4이고 각 목록 l의 길이가 3 인 다른 목록이 있습니다. 이제 실행할 수 있습니다

  library (plyr)
  df <- ldply (l, data.frame)

@Marek 및 @nico 답변과 동일한 결과를 얻습니다.


8
좋은 대답입니다. 어떻게 작동하는지 조금 설명해 주시겠습니까? 단순히 각 목록 항목에 대한 데이터 프레임을 반환합니까?
Michael Barton

13
최고의 답변을 임호. 정직한 data.frame을 반환합니다. 모든 데이터 유형 (문자, 숫자 등)이 올바르게 변환됩니다. 목록에 다른 데이터 유형이있는 경우 모두 matrix접근 방식 으로 문자로 변환됩니다 .
Roah

1
여기에 제공된 샘플은 질문에서 제공 한 샘플이 아닙니다. 원래 데이터 세트에 대한이 답변의 결과가 올바르지 않습니다.
MySchizoBuddy

나를 위해 잘 작동합니다! 그리고 결과 데이터 프레임의 열 이름이 설정됩니다! Tx
bAN

plyr 멀티 코어입니까? 아니면 mclapply와 함께 사용할 수있는 lapply 버전이 있습니까?
Garglesoap 2016 년

103

data.frame(t(sapply(mylistlist,c)))

sapply그것을 행렬로 변환합니다. data.frame행렬을 데이터 프레임으로 변환합니다.


19
최고의 답변! 다른 솔루션은 유형 / 열 이름을 올바르게 얻지 못합니다. 감사합니다!
d_a_c321

1
c목록 데이터의 한 인스턴스 인 여기에서 어떤 역할을 하시겠습니까? 연결 함수를 기다립니다. c? @mnel의 사용법과 혼동되기 c. 또한 @dchandler와 동의하여 열 이름을 올바르게 사용하는 것이 유스 케이스에서 중요한 요구 사항이었습니다. 훌륭한 솔루션.
jxramos

그 권리-표준 c 함수; 보낸 사람 ?c:Combine Values into a Vector or List
Alex Brown

1
질문에 제공된 샘플 데이터로는 작동하지 않습니다
MySchizoBuddy

3
이것이 목록의 data.frame을 생성하지 않습니까?
Carl

69

목록이라고 가정 L하고

data.frame(Reduce(rbind, L))

2
좋은 것! @Alex Brown의 솔루션과 귀하의 솔루션에 비해 한 가지 차이점이 있습니다. 경로를 이동하면 어떤 이유로 든 다음과 같은 경고 메시지가 나타납니다. : 3,4-> row.names NOT used '
jxramos

아주 좋아요 !! 나를 위해 일했다 : stackoverflow.com/questions/32996321/…
Anastasia Pupynina

2
목록에 하나의 요소가 없으면 잘 작동합니다. 2 개의 행, 1 개의 열이data.frame(Reduce(rbind, list(c('col1','col2')))) 있는 데이터 프레임을 생성합니다 (1 개의 행 2 개의 열

61

패키지 data.table에는의 rbindlist초고속 구현 기능 이 do.call(rbind, list(...))있습니다.

이 목록을 취할 수 lists, data.frames또는 data.tables 입력으로.

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)

이에서 data.table상속을 반환합니다 data.frame.

당신이 경우 정말 data.frame 사용으로 다시 변환 할as.data.frame(DT)


마지막 줄과 관련하여 setDF이제 참조로 data.frame으로 돌아갈 수 있습니다.
Frank

1
30k 개 항목이 포함 된 내 목록의 경우 rbindlist는 ldply보다 훨씬 빠르게 작동했습니다.
tallharish

35

tibble패키지 기능을 갖는 enframe()로 해결할 중첩 강요함으로써이 문제 있음 list중첩에 객체 tibble( "단정"데이터 프레임) 객체. 다음은 R for 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]>

목록에 여러 개의 중첩 l이 있으므로를 사용하여 unlist(recursive = FALSE)불필요한 중첩을 제거하여 단일 계층 목록 만 가져온 다음에 전달할 수 enframe()있습니다. 나는 사용 tidyr::unnest()하여 두 개의 열 (그룹의 하나가 하나의 수준 "단정"데이터 프레임에 출력 unnest로 name하고, 그룹과 관찰을위한 하나 value). 너비가 넓은 열을 원하면 add_column()값의 순서를 132 번 반복 하여 열을 추가 할 수 있습니다 . 그런 다음 spread()값만.


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>

OP 인용 : "이 구조를 132 행과 20 열의 데이터가있는 데이터 프레임으로 변환하는 빠른 방법이 있습니까?" 아마도 당신은 확산 단계 또는 무언가가 필요할 것입니다.
Frank

1
아, 그렇습니다. 퍼질 수있는 인덱스 열만 있으면됩니다. 곧 업데이트하겠습니다.
Matt Dancho

17

목록의 구조에 따라 tidyverse길이가 다른 목록과 잘 작동 하는 몇 가지 옵션이 있습니다.

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

벡터와 데이터 프레임을 혼합 할 수도 있습니다.

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

이 dplyr :: bind_rows 함수는 JSON으로 시작된 목록으로 작업하기 어려운 경우에도 잘 작동합니다. JSON에서 놀랍도록 깨끗한 ​​데이터 프레임까지. 좋은.
GGAnderson

@sbha 내가 DF <사용하려고 - purrr :: map_df (L ~ .x를)을하지만 그것이 작동하지 않는 것 같아, 내가 가지고있는 오류 메시지가 오류입니다 : 열이 X2문자로 정수로 변환 할 수 없습니다
졸인

16

Reshape2는 위 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

픽셀이 거의 없으면 recast ()를 사용하여 한 줄 로이 작업을 수행 할 있습니다.


12

이 방법은 tidyverse패키지 ( purrr )를 사용합니다.

목록 :

x <- as.list(mtcars)

데이터 프레임으로 변환 ( tibble보다 구체적으로) :

library(purrr)
map_df(x, ~.x)

10

@Marek의 대답으로 확장 : 문자열이 요인으로 바뀌지 않고 효율성을 고려하지 않으려는 경우 시도하십시오.

do.call(rbind, lapply(your_list, data.frame, stringsAsFactors=FALSE))

10

중첩 JSON에서 얻은 것과 같은 수준이 3 개 이상인 깊게 중첩 된 목록의 일반적인 경우 :

{
"2015": {
  "spain": {"population": 43, "GNP": 9},
  "sweden": {"population": 7, "GNP": 6}},
"2016": {
  "spain": {"population": 45, "GNP": 10},
  "sweden": {"population": 9, "GNP": 8}}
}

melt()먼저 중첩 목록을 긴 형식으로 변환 하는 방법을 고려하십시오 .

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

다음에 dcast()각 변수가 각 단 칼럼 관찰 형태 행을 형성 단정 세트로 다시 폭으로 다음 :

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

9

이 질문에 대한 답변의 타이밍과 함께 더 많은 답변 : 목록을 데이터 프레임으로 캐스팅하는 가장 효율적인 방법은 무엇입니까?

열에 대한 벡터가 아닌 목록이있는 데이터 프레임을 생성하지 않는 가장 빠른 방법은 다음과 같습니다 (마틴 모건의 대답에서).

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

8

때로는 데이터가 같은 길이의 벡터 목록 목록 일 수 있습니다.

lolov = list(list(c(1,2,3),c(4,5,6)), list(c(7,8,9),c(10,11,12),c(13,14,15)) )

(내부 벡터도 목록이 될 수 있지만 이것을 쉽게 읽을 수 있도록 단순화하고 있습니다).

그런 다음 다음과 같이 수정할 수 있습니다. 한 번에 하나의 레벨을 나열 해제 할 수 있습니다.

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

이제 다른 답변에서 언급 한 좋아하는 방법을 사용하십시오.

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

4

이것이 마침내 나를 위해 일한 것입니다.

do.call("rbind", lapply(S1, as.data.frame))


4
l <- replicate(10,list(sample(letters, 20)))
a <-lapply(l[1:10],data.frame)
do.call("cbind", a)

3

솔루션 purrr제품군을 사용하는 병렬 (멀티 코어, 멀티 세션 등) 솔루션의 경우 다음을 사용하십시오.

library (furrr)
plan(multisession) # see below to see which other plan() is the more efficient
myTibble <- future_map_dfc(l, ~.x)

l목록은 어디에 있습니까 ?

가장 효율적인 벤치마킹 방법은 plan()다음과 같습니다.

library(tictoc)
plan(sequential) # reference time
# plan(multisession) # benchamark plan() goes here. See ?plan().
tic()
myTibble <- future_map_dfc(l, ~.x)
toc()

3

다음과 같은 간단한 명령이 나를 위해 일했습니다.

myDf <- as.data.frame(myList)

참조 ( 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"

그러나 목록을 데이터 프레임으로 변환하는 방법이 확실하지 않으면 실패합니다.

> 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

참고 : 답변은 질문의 제목에 대한 것이며 질문의 세부 사항을 건너 뛸 수 있습니다


질문의 입력에서 이것은 일종의 작동합니다. OP는 132 개의 행과 20 개의 열을 요구하지만, 이는 20 개의 행과 132 개의 열을 제공합니다.
Gregor Thomas

길이가 다른 입력이 실패한 예에서는 원하는 결과가 무엇인지 명확하지 않습니다.
Gregor Thomas

@Gregor 사실이지만 질문 제목은 "R-list to data frame"입니다. 질문에 대한 많은 방문자와 투표 한 사람들은 OP의 정확한 문제가 없습니다. 질문 제목을 기준으로 목록을 데이터 프레임으로 변환하는 방법을 찾습니다. 나 자신도 같은 문제가 있었고 내가 게시 한 솔루션으로 문제를 해결했다
Ahmad

그렇습니다. 비공개. 답변에서 비슷한 답변을하지만 다른 답변과는 완전히 다른 점에 유의하는 것이 좋습니다.
Gregor Thomas

1

데이터 프레임은 길이가 동일한 벡터목록 이기 때문에 짧은 r (아마도 가장 빠르지는 않은) 방법은 base r을 사용하는 것 입니다. 따라서 입력 목록과 30 x 132 data.frame 간의 변환은 다음과 같습니다.

df <- data.frame(l)

거기에서 132 x 30 행렬로 바꾸고 다시 데이터 프레임으로 변환 할 수 있습니다.

new_df <- data.frame(t(df))

원 라이너로 :

new_df <- data.frame(t(data.frame(l)))

행 이름은보기에 꽤 성가 시겠지만 언제든지 이름을 바꿀 수 있습니다.

rownames(new_df) <- 1:nrow(new_df)


2
이것이 왜 하향 조정 되었습니까? 잘못된 정보가 계속 퍼지지 않도록 알고 싶습니다.
Will C

data.frame과 t의 조합을 사용 하여이 작업을 확실히 수행했습니다! 공감 한 사람들은 더 나은 방법, 특히 이름을 엉망으로 만들지 않는 방법이 있다고 생각합니다.
Arthur Yip

1
좋은 지적입니다. 목록에 이름을 유지하려는 경우에도 잘못된 것 같습니다.
Will C

0

사용은 어떻습니까 map_ 과 기능을 함께를 for루프? 내 해결책은 다음과 같습니다.

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)
  }
  print(tmp_data_frame)
}

여기서 map_dfr각 목록 요소를 data.frame으로 변환 한 다음 rbind완전히 결합하십시오.

귀하의 경우에는 다음과 같습니다.

converted_list <- list_to_df(l)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.