데이터 프레임 목록을 만들려면 어떻게합니까?


186

데이터 프레임 목록을 작성하는 방법과 목록에서 해당 데이터 프레임 각각에 액세스하는 방법은 무엇입니까?

예를 들어, 이러한 데이터 프레임을 어떻게 목록에 넣을 수 있습니까?

d1 <- data.frame(y1 = c(1, 2, 3),
                 y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1),
                 y2 = c(6, 5, 4))

13
이것은 몇 가지 답변에 있지만 여기에서도 눈에 띄는 코멘트를 가진 그것의 가치는 : 사용 =하지 <-내부 data.frame(). 글로벌 환경에서 <-생성 y1하고 사용 하면 y2데이터 프레임이 원하는 것이 아닙니다.
Gregor Thomas

37
<-data.frame () 안에 공백과 s 가없는 코드 엉망을보십시오 . 내가 얼마나 새롭습니까.
Ben

5
더 이상은 아닙니다. 코드 형식을 수정하기 위해 질문을 편집했습니다. 향수를 느끼면 되돌릴 수 있습니다.
Claus Wilke

답변:


133

이것은 귀하의 질문과 관련이 없지만 함수 호출 내에서 사용 =하고 싶지 않습니다 <-. 를 사용 하면 작업 환경 과 환경에서 <-변수를 만들 수 있습니다.y1y2

d1 <- data.frame(y1 <- c(1, 2, 3), y2 <- c(4, 5, 6))
y1
# [1] 1 2 3
y2
# [1] 4 5 6

이것은 데이터 프레임에서 열 이름을 만들 때 원하는 것처럼 보이지 않습니다.

d1
#   y1....c.1..2..3. y2....c.4..5..6.
# 1                1                4
# 2                2                5
# 3                3                6

반면에 =연산자는 벡터를 인수와 연관시킵니다 data.frame.

귀하의 질문에 관해서는, 데이터 프레임 목록을 만드는 것이 쉽습니다.

d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6))
d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4))
my.list <- list(d1, d2)

다른 목록 요소에 액세스하는 것처럼 데이터 프레임에 액세스합니다.

my.list[[1]]
#   y1 y2
# 1  1  4
# 2  2  5
# 3  3  6

344

다른 답변을 보여 어떻게 당신이 때 data.frames의 목록을 만들기 위해 이미 예를 들어, data.frames의 무리 d1, d2.... 문제가 순차적으로 명명 된 데이터 프레임을 갖는, 그리고 목록에 넣어 것은입니다 좋은 수정이지만 가장 좋은 방법은 처음 에는 목록없는 많은 데이터 프레임을 사용하지 않는 것입니다 .

다른 답변은 요소를 나열하고 액세스하는 등 데이터 프레임을 할당하는 방법에 대한 자세한 정보를 제공합니다. 여기서도 조금 다룰 것입니다. 그러나 요점많은 것을 가질 때까지 기다리지 말아야 한다는 것 입니다. data.frames목록에 추가하십시오. 목록부터 시작하십시오.

이 답변의 나머지 부분에서는 순차 변수를 만들고 싶은 유혹이있을 수있는 몇 가지 일반적인 경우를 다루고 목록으로 바로 이동하는 방법을 보여줍니다. R의 목록을 처음 사용하는 경우 목록 의 요소 [[[액세스 요소의 차이점은 무엇입니까? 를 읽어보십시오 . .


처음부터 목록

절대 만들지 마 d1 d2 d3dn처음 에는 ...을 . 요소 가 포함 된 목록 d을 만듭니다 n.

여러 파일을 데이터 프레임 목록으로 읽기

이것은 파일을 읽을 때 매우 쉽게 수행됩니다. data1.csv, data2.csv, ...디렉토리에 파일 이있을 수 있습니다. 당신의 목표는 data.frames의 목록입니다mydata . 가장 먼저 필요한 것은 모든 파일 이름을 가진 벡터입니다. 붙여 넣기 (예 :)로이를 구성 할 수 my_files = paste0("data", 1:5, ".csv")있지만 list.files적절한 모든 파일을 가져 오는 데 사용 하는 것이 더 쉽습니다 my_files <- list.files(pattern = "\\.csv$"). 정규식을 사용하여 파일을 일치시킬 수 있으며, 도움이 필요한 경우 다른 질문에서 정규식에 대해 자세히 읽어보십시오. 이 방법을 사용하면 멋진 이름 지정 체계를 따르지 않아도 모든 CSV 파일을 가져올 수 있습니다. 또는 여러 CSV 파일에서 특정 CSV 파일을 선택해야하는 경우 더 멋진 정규식 패턴을 사용할 수 있습니다.

이 시점에서 대부분의 R 초보자는 for 루프 아무런 문제가 없으며 정상적으로 작동합니다.

my_data <- list()
for (i in seq_along(my_files)) {
    my_data[[i]] <- read.csv(file = my_files[i])
}

더 R과 같은 방법은 lapply 위의 바로 가기 인

my_data <- lapply(my_files, read.csv)

물론 다른 데이터 가져 오기 기능을 read.csv적절하게 대체하십시오 .readr::read_csv또는 data.table::fread더 빠른 것, 또는 당신은 또한 다른 파일 형식에 대해 다른 기능을해야 할 수도 있습니다.

어느 쪽이든, 파일과 일치하도록 목록 요소의 이름을 지정하는 것이 편리합니다.

names(my_data) <- gsub("\\.csv$", "", my_files)
# or, if you prefer the consistent syntax of stringr
names(my_data) <- stringr::str_replace(my_files, pattern = ".csv", replacement = "")

데이터 프레임을 데이터 프레임 목록으로 분할

이것은 매우 쉬우 며 기본 기능 split()은 당신을 위해 그것을합니다. 데이터의 열 (또는 열) 또는 원하는 다른 항목으로 분할 할 수 있습니다.

mt_list = split(mtcars, f = mtcars$cyl)
# This gives a list of three data frames, one for each value of cyl

또한 교차 유효성 검사를 위해 데이터 프레임을 조각으로 나누는 좋은 방법입니다. mtcars교육, 테스트 및 유효성 검사 로 나눌 수 있습니다 .

groups = sample(c("train", "test", "validate"),
                size = nrow(mtcars), replace = TRUE)
mt_split = split(mtcars, f = groups)
# and mt_split has appropriate names already!

데이터 프레임 목록 시뮬레이션

아마도 당신은 다음과 같은 데이터를 시뮬레이션 할 것입니다 :

my_sim_data = data.frame(x = rnorm(50), y = rnorm(50))

그러나 누가 하나의 시뮬레이션 만합니까? 이 작업을 100 번, 1000 번 이상으로하고 싶습니다! 그러나 작업 공간에 10,000 개의 데이터 프레임을 원하지 않습니다 . 사용 replicate하고 목록에 넣으십시오.

sim_list = replicate(n = 10,
                     expr = {data.frame(x = rnorm(50), y = rnorm(50))},
                     simplify = F)

이 경우 특히 별도의 데이터 프레임이 필요한지 또는 "그룹"열이있는 단일 데이터 프레임이 제대로 작동하는지 고려해야합니다. 사용 data.table하거나 dplyr데이터 그룹에 "그룹 별"작업을 수행하는 것은 매우 쉽습니다.

데이터를 목록에 넣지 않았습니다. (다음에 다시하겠습니다.하지만 지금 어떻게해야합니까?

그것들이 이상한 구색이라면 (비정상적 임), 간단히 그것들을 할당 할 수 있습니다 :

mylist <- list()
mylist[[1]] <- mtcars
mylist[[2]] <- data.frame(a = rnorm(50), b = runif(50))
...

당신이 패턴에 이름이 데이터 프레임이있는 경우 예를 들어, df1, df2, df3, 그리고 당신은 목록에 원하는 작업을 수행 할 수 있습니다 get당신은 이름과 일치하는 정규 표현식을 쓸 수 있는지를. 같은 것

df_list = mget(ls(pattern = "df[0-9]"))
# this would match any object with "df" followed by a digit in its name
# you can test what objects will be got by just running the
ls(pattern = "df[0-9]")
# part and adjusting the pattern until it gets the right objects.

일반적으로 mget여러 객체를 가져 와서 명명 된 목록으로 반환하는 데 사용됩니다. 해당 get객체는 단일 객체를 가져 와서 반환합니다 (목록이 아님).

데이터 프레임 목록을 단일 데이터 프레임으로 결합

일반적인 작업은 데이터 프레임 목록을 하나의 큰 데이터 프레임으로 결합하는 것입니다. 서로 겹쳐서 쌓으려면 rbind한 쌍으로 사용 하지만 데이터 프레임 목록에는 다음 세 가지 중에서 선택할 수 있습니다.

# base option - slower but not extra dependencies
big_data = do.call(what = rbind, args = df_list)

# data table and dplyr have nice functions for this that
#  - are much faster
#  - add id columns to identify the source
#  - fill in missing values if some data frames have more columns than others
# see their help pages for details
big_data = data.table::rbindlist(df_list)
big_data = dplyr::bind_rows(df_list)

( cbind또는 dplyr::bind_cols열과 유사하게 사용 )

데이터 프레임 목록을 병합 (결합)하려면 다음 답변을 볼 수 있습니다 . 종종 아이디어는 Reduce함께 사용하는 것 입니다.merge (또는 다른 결합 기능) 사용하는 것입니다.

왜 데이터를 목록에 넣습니까?

각 데이터 프레임에 비슷한 일을하고 싶어하고, 기능을 좋아하기 때문에 목록에 유사한 데이터를 넣고 lapply, sapply do.call, 패키지 및 기존 기능은 쉽게 그렇게 할 수 있습니다. 목록으로 쉽게 일을하는 사람들의 예는 매우 다양합니다.purrrplyr l*ply

낮은 for 루프를 사용하더라도 변수 이름을 사용 paste하여을 사용하여 객체에 액세스하는 것보다 목록의 요소를 반복하는 것이 훨씬 쉽습니다 get. 디버그도 더 쉽습니다.

확장 성을 생각하십시오 . 당신이 정말로 단지 세 개의 변수, 사용에 그것의 벌금을해야하는 경우 d1, d2, d3. 그러나 실제로 6이 필요하다는 것이 밝혀지면 훨씬 더 타이핑됩니다. 그리고 다음에 10 또는 20이 필요할 때 코드 줄을 복사하여 붙여 넣는 것을 발견하고 찾기 / 바꾸기를 사용하여로 변경 d14하면 이것이 프로그래밍 방식이 아니라고d15 생각 합니다 . 목록을 사용하는 경우 3 건, 30 건, 300 건의 차이는 최대 한 줄의 코드입니다..csv 에서 파일이 없습니다 당신의 예배 규칙서.

숫자 인덱스 이외의 것을 사용하여 데이터 프레임에 액세스하려는 경우 목록의 요소 이름을 지정할 수 있습니다 (둘 다 사용할 수 있으며 XOR 선택이 아님).

전체적으로 목록을 사용하면보다 깔끔하고 읽기 쉬운 코드를 작성할 수있어 버그가 줄어들고 혼동이 줄어 듭니다.


2
목록 작업을 다루는 책은 무엇입니까?
Derelict

15
나는 모두 태그 스택 오버플로에 대한 질문과 답변 읽어 보시기 바랍니다 rlist.
Gregor Thomas

2
@Gregor`my_data <-list my_data <- NULL() '대신에 단순히 할당함으로써 파일과 일치하는리스트 요소의 이름을 피할 수 있다고 덧붙이고 싶습니다 ! :)
Daniel

6
가능하지만 my_data <- list()목록을 작성하고 있음을 분명히합니다. 명확한 코드는 좋은 것입니다. my_data <- NULL대신 사용하면 이점이 없습니다 .
Gregor Thomas

3
나는 당신이 말한 것에 동의하지만, 내가 말했듯이 그렇게하면 파일 이름 지정 단계를 벗어날 수 있습니다. names(my_data) <- gsub("\\.csv$", "", my_files) ;) <br> 그러나 나는 초보자로서 그들로부터 많은 것을 배우고 당신의 조언을 존중하고 정말 감사합니다 :)
Daniel

21

또한 각 목록 요소의 특정 컬럼과 값에 액세스 할 수 있습니다 [[[. 다음은 몇 가지 예입니다. 먼저, 목록에서 각 데이터 프레임의 첫 번째 열에 만 액세스 할 수 있습니다 . lapply(ldf, "[", 1)여기서 1열 번호를 나타냅니다.

ldf <- list(d1 = d1, d2 = d2)  ## create a named list of your data frames
lapply(ldf, "[", 1)
# $d1
#   y1
# 1  1
# 2  2
# 3  3
#
# $d2
#   y1
# 1  3
# 2  2
# 3  1

마찬가지로 두 번째 열의 첫 번째 값에 액세스 할 수 있습니다.

lapply(ldf, "[", 1, 2)
# $d1
# [1] 4
# 
# $d2
# [1] 6

그런 다음 벡터로 열 값에 직접 액세스 할 수도 있습니다. [[

lapply(ldf, "[[", 1)
# $d1
# [1] 1 2 3
#
# $d2
# [1] 3 2 1

13

순차적으로 명명 된 데이터 프레임이 많은 경우 다음과 같이 원하는 데이터 프레임 하위 집합의 목록을 만들 수 있습니다.

d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6))
d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4))
d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1))
d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8))

my.list <- list(d1, d2, d3, d4)
my.list

my.list2 <- lapply(paste('d', seq(2,4,1), sep=''), get)
my.list2

여기서 my.list2두 번째, 세 번째 및 네 번째 데이터 프레임이 포함 된 목록을 반환합니다.

[[1]]
  y1 y2
1  3  6
2  2  5
3  1  4

[[2]]
  y1 y2
1  6  3
2  5  2
3  4  1

[[3]]
  y1 y2
1  9  8
2  9  8
3  9  8

그러나 위 목록의 데이터 프레임은 더 이상 이름이 지정되지 않습니다. 데이터 프레임의 서브 세트를 포함하는 목록을 작성하고 해당 이름을 유지하려면 다음을 시도하십시오.

list.function <-  function() { 

     d1 <- data.frame(y1=c(1,2,3), y2=c(4,5,6))
     d2 <- data.frame(y1=c(3,2,1), y2=c(6,5,4))
     d3 <- data.frame(y1=c(6,5,4), y2=c(3,2,1))
     d4 <- data.frame(y1=c(9,9,9), y2=c(8,8,8))

     sapply(paste('d', seq(2,4,1), sep=''), get, environment(), simplify = FALSE) 
} 

my.list3 <- list.function()
my.list3

다음을 반환합니다.

> my.list3
$d2
  y1 y2
1  3  6
2  2  5
3  1  4

$d3
  y1 y2
1  6  3
2  5  2
3  4  1

$d4
  y1 y2
1  9  8
2  9  8
3  9  8

> str(my.list3)
List of 3
 $ d2:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 3 2 1
  ..$ y2: num [1:3] 6 5 4
 $ d3:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 6 5 4
  ..$ y2: num [1:3] 3 2 1
 $ d4:'data.frame':     3 obs. of  2 variables:
  ..$ y1: num [1:3] 9 9 9
  ..$ y2: num [1:3] 8 8 8

> my.list3[[1]]
  y1 y2
1  3  6
2  2  5
3  1  4

> my.list3$d4
  y1 y2
1  9  8
2  9  8
3  9  8

2
대신에 lapply(foo, get)단지 사용mget(foo)
그레고르 토마스

9

주어진 이름으로 비슷한 이름을 가진 "큰"수의 data.frames (여기서 d # 여기서 #은 양의 정수임)가 주어지면 다음은 @ mark-miller의 방법이 약간 개선 된 것입니다. 더 간결하고 명명 된 이름을 반환합니다. 된 data.frames 목록을 . 여기서 목록의 각 이름은 해당 원본 data.frame의 이름입니다.

열쇠 mget는와 함께 사용 하고 있습니다 ls. 질문에 제공된 데이터 프레임 d1 및 d2가 환경에서 이름이 d # 인 유일한 객체 인 경우

my.list <- mget(ls(pattern="^d[0-9]+"))

어느 것이 돌아 올까

my.list
$d1
  y1 y2
1  1  4
2  2  5
3  3  6

$d2
  y1 y2
1  3  6
2  2  5
3  1  4

이 메소드는의 패턴 인수 ls를 이용하므로 정규 표현식을 사용하여 환경의 객체 이름을보다 정밀하게 파싱 할 수 있습니다. 정규식의 대안 "^d[0-9]+$""^d\\d+$" 입니다.

@gregor가 지적 했듯이 data.frames 가 시작시 명명 된 목록에 배치되도록 데이터 구성 프로세스를 설정하는 것이 더 좋습니다.

데이터

d1 <- data.frame(y1 = c(1,2,3),y2 = c(4,5,6))
d2 <- data.frame(y1 = c(3,2,1),y2 = c(6,5,4))

3

이것은 조금 늦을 수도 있지만 당신의 모범으로 돌아가서 나는 대답을 조금만 연장 할 것이라고 생각했습니다.

 D1 <- data.frame(Y1=c(1,2,3), Y2=c(4,5,6))
 D2 <- data.frame(Y1=c(3,2,1), Y2=c(6,5,4))
 D3 <- data.frame(Y1=c(6,5,4), Y2=c(3,2,1))
 D4 <- data.frame(Y1=c(9,9,9), Y2=c(8,8,8))

그런 다음 목록을 쉽게 만듭니다.

mylist <- list(D1,D2,D3,D4)

이제 목록이 있지만 다음과 같은 이전 방법으로 목록에 액세스하는 대신

mylist[[1]] # to access 'd1'

이 기능을 사용하여 원하는 데이터 프레임을 확보하고 할당 할 수 있습니다.

GETDF_FROMLIST <- function(DF_LIST, ITEM_LOC){
   DF_SELECTED <- DF_LIST[[ITEM_LOC]]
   return(DF_SELECTED)
}

이제 원하는 것을 얻으십시오.

D1 <- GETDF_FROMLIST(mylist, 1)
D2 <- GETDF_FROMLIST(mylist, 2)
D3 <- GETDF_FROMLIST(mylist, 3)
D4 <- GETDF_FROMLIST(mylist, 4)

여분의 비트가 도움이되기를 바랍니다.

건배!


2
예, 알고 있지만 어떤 이유로 복사하여 붙여 넣을 때 모든 것이 제한되었습니다. :( 어쨌든 소문자 코드는 작동합니다.
ML_for_now

4
왜 당신이 선호하는지 궁금 GETDF_FROMLIST(mylist, 1)합니다 mylist[[1]]. 함수 구문을 선호한다면 "[["(mylist, 1)사용자 정의 함수를 정의 하지 않고도 할 수 있습니다.
Gregor Thomas

4
함수 정의를 단순화 할 수도 있습니다. 함수의 전체 본문은 return(DF_LIST[[ITEM_LOC]])중간 변수를 할당 할 필요가 없습니다.
Gregor Thomas

1

매우 간단합니다! 내 제안은 다음과 같습니다.

작업 공간에서 데이터 프레임을 선택하려면 다음을 시도하십시오.

Filter(function(x) is.data.frame(get(x)) , ls())

또는

ls()[sapply(ls(), function(x) is.data.frame(get(x)))]

이 모든 것이 같은 결과를 줄 것입니다.

다음 is.data.frame과 같은 다른 유형의 변수를 확인하도록 변경할 수 있습니다is.function


1

나는 나 자신을 완전한 초보자라고 생각하지만 여기에 언급되지 않은 원래의 하위 질문 중 하나 인 데이터 프레임 또는 그 일부에 액세스하는 것이 매우 간단하다고 생각합니다.

위에서 언급 한대로 데이터 프레임이있는 목록을 작성하여 시작하겠습니다.

d1 <- data.frame(y1 = c(1, 2, 3), y2 = c(4, 5, 6))

d2 <- data.frame(y1 = c(3, 2, 1), y2 = c(6, 5, 4))

my.list <- list(d1, d2)

그런 다음 데이터 프레임 중 하나에서 특정 값에 액세스하려면 이중 괄호를 순차적으로 사용하여 액세스 할 수 있습니다. 첫 번째 세트는 데이터 프레임으로 이동하고 두 번째 세트는 특정 좌표로 이동합니다.

my.list[[1]][[3,2]]

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