development

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

big-blog 2020. 2. 15. 23:17
반응형

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


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

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

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

목록의 목록을 다음과 같이 가정합니다 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)

rbind

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

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


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 답변과 동일한 결과를 얻습니다.


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

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


목록이라고 가정 L하고

data.frame(Reduce(rbind, L))

패키지 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)


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>

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 ()를 사용하여 한 줄 로이 작업을 수행 있습니다.


목록의 구조에 따라 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

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

목록 :

x <- as.list(mtcars)

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

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

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

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

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

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

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

중첩 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

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

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

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

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


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

솔루션 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()

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

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

데이터 프레임은 길이가 동일한 벡터목록 이기 때문에 짧은 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)

참고 URL : https://stackoverflow.com/questions/4227223/convert-a-list-to-a-data-frame



반응형