행 단위로 R 데이터 프레임 만들기


107

R에서 행 단위로 데이터 프레임을 구성하고 싶습니다. 몇 가지 검색을 수행했으며 내가 생각 해낸 것은 빈 목록을 만들고 목록 인덱스 스칼라를 유지 한 다음 매번 목록에 추가하라는 제안뿐입니다. 단일 행 데이터 프레임을 만들고 목록 인덱스를 1 씩 앞으로 이동합니다. 마지막으로 do.call(rbind,)목록에 있습니다.

이것이 작동하는 동안 매우 번거로운 것 같습니다. 동일한 목표를 달성하는 더 쉬운 방법이 없습니까?

분명히 일부 apply기능을 사용할 수없고 명시 적으로 데이터 프레임을 행 단위로 만들어야하는 경우를 언급합니다 . 적어도 push사용 된 마지막 인덱스를 명시 적으로 추적하는 대신 목록의 끝 으로가는 방법이 있습니까?


1
당신이 사용할 수있는 append()[아마 삽입을 지정해야하는] 또는 c()하지만 여기에 도움이되지 않습니다, 목록의 끝에 항목을 추가 할 수 있습니다.
hatmatrix

반환 데이터 프레임은 당신이 그들을 반환하지 않는 것을 R에 많은 기능이되지 않습니다 [행 방향]에서 lapply(), Map()등,하지만 당신은 또한에서 살펴 봐야 할 수 있습니다 aggregate(), dapply() {heR.Misc}그리고 cast() {reshape}당신의 작업이 이들에 의해 처리 될 수 있는지 함수 (모두 반환 데이터 프레임).
hatmatrix

답변:


96

을 추가하거나 사용하여 행별로 늘릴 수 있습니다 rbind().

그렇다고해서 그래야한다는 의미는 아닙니다. 동적으로 성장하는 구조는 R에서 코딩하는 가장 효율적인 방법 중 하나입니다.

가능하다면 전체 data.frame을 미리 할당하십시오.

N <- 1e4  # total number of rows to preallocate--possibly an overestimate

DF <- data.frame(num=rep(NA, N), txt=rep("", N),  # as many cols as you need
                 stringsAsFactors=FALSE)          # you don't know levels yet

그런 다음 작업 중에 한 번에 행을 삽입하십시오.

DF[i, ] <- list(1.4, "foo")

임의의 data.frame에서 작동하고 훨씬 더 효율적입니다. N을 초과하면 항상 끝에서 빈 행을 축소 할 수 있습니다.


6
1.4를 문자 모드로 강요하지 않도록 10 대신 N을, c (1.4, "foo") 대신 list (1.4, "foo")를 넣으려고하지 않았습니까?
hatmatrix

네, data.frame 생성에 N을 사용하려고했습니다. 또한 채팅에 대한 강압을 아주 잘 포착했습니다. 저는 그것을 놓쳤습니다.
Dirk Eddelbuettel

1
댓글에 남겨 두는 것보다 답변을 수정하는 것이 좋습니다. 나는이 대답을 구하기 위해 혼란 스러웠다.
User

4
data.tabledata.frames를 사용하는 사전 할당보다 훨씬 빠른 것 같습니다. 여기에 테스트 : stackoverflow.com/a/11486400/636656
아리 B. 프리드먼

이것이 더 빨라져야하는 R 3.1에서도 여전히 사실입니까?
userJT 2014

49

행을 추가 할 수 있습니다 NULL.

df<-NULL;
while(...){
  #Some code that generates new row
  rbind(df,row)->df
}

예를 들어

df<-NULL
for(e in 1:10) rbind(df,data.frame(x=e,square=e^2,even=factor(e%%2==0)))->df
print(df)

3
데이터 프레임이 아닌 행렬을 출력합니다
Olga

1
@Olga 동일한 유형의 요소 행을 바인딩하는 경우에만-이 경우 BTW는 sapply(또는 벡터화) 전치 하는 것이 좋습니다 .
mbq

1
@mbq 정확히 내가하는 일. 또한 df <-data.frame ()으로 초기화하면 데이터 프레임이 출력된다는 것을 발견했습니다.
Olga

9

이것은 [와 유사한 ] do.call(rbind,)의 출력에 사용하는 방법에 대한 어리석은 예입니다 .Map()lapply()

> DF <- do.call(rbind,Map(function(x) data.frame(a=x,b=x+1),x=1:3))
> DF
  x y
1 1 2
2 2 3
3 3 4
> class(DF)
[1] "data.frame"

이 구조를 자주 사용합니다.


8

내가 Rcpp를 너무 좋아하는 이유는 항상 R Core가 어떻게 생각하는지 이해하지 못하기 때문이며 Rcpp를 사용하면 더 자주 그렇지 않아도됩니다.

철학적으로 말하면 모든 가치 다른 모든 가치와 독립적으로 나타나 도록하는 기능적 패러다임과 관련하여 당신은 죄의 상태에 있습니다 . 하나의 값을 변경하면 C에서 표현을 공유하는 포인터와 같은 방식으로 다른 값에 가시적 인 변경이 발생해서는 안됩니다.

함수형 프로그래밍이 작은 우주선에 방해가되지 않도록 신호를 보내고 작은 우주선이 "I 'm a lighthouse"라고 답할 때 문제가 발생합니다. 그 동안 처리하고자하는 큰 물체에 대해 긴 일련의 작은 변경을 수행하면 등대 영역에 들어가게됩니다.

C ++ STL에서는 push_back()삶의 방식입니다. 기능성을 발휘하지는 않지만 일반적인 프로그래밍 관용구를 효율적 으로 수용하려고합니다 .

무대 뒤에서 약간의 영리함을 통해 때때로 각 세계에서 한 발을 갖도록 할 수 있습니다. 스냅 샷 기반 파일 시스템이 좋은 예입니다 (양쪽을 연결하는 유니온 마운트와 같은 개념에서 발전).

R Core가이 작업을 수행하려는 경우 기본 벡터 저장소가 유니온 마운트처럼 작동 할 수 있습니다. 벡터 저장소에 대한 한 참조는 첨자 1:N에 대해 유효 할 수 있지만 동일한 저장에 대한 다른 참조는 첨자에 유효합니다 1:(N+1). 아직 유효하게 참조되지 않은 예약 된 저장소가있을 수 있지만 빠른 push_back(). 기존 참조가 유효하다고 간주하는 범위 밖에 추가 할 때 기능 개념을 위반하지 않습니다.

결국 행을 점진적으로 추가하면 예약 된 스토리지가 부족합니다. 저장소에 약간의 증분을 곱하여 모든 항목의 새 복사본을 만들어야합니다. 내가 사용한 STL 구현은 할당을 확장 할 때 스토리지에 2를 곱하는 경향이 있습니다. R Internals에서 스토리지가 20 % 씩 증가하는 메모리 구조가 있다고 읽었습니다. 어느 쪽이든 추가 된 총 요소 수에 대한 대수 빈도로 증가 작업이 발생합니다. 상각 기준으로 이것은 일반적으로 허용됩니다.

뒤에서 트릭이 진행됨에 따라 나는 더 나빠졌습니다. push_back()데이터 프레임에 새 행을 올릴 때마다 최상위 인덱스 구조를 복사해야합니다. 새 행은 이전 기능 값에 영향을주지 않고 공유 표현에 추가 될 수 있습니다. 나는 그것이 가비지 수집기를 많이 복잡하게 만들 것이라고 생각조차하지 않는다. push_front()모든 참조가 할당 된 벡터 스토리지의 앞쪽에 대한 접두사 참조 라고 제안하지 않기 때문에 .


2

Dirk Eddelbuettel의 대답이 최고입니다. 여기에서는 데이터 프레임 차원 또는 데이터 유형을 미리 지정하지 않아도됩니다. 여러 데이터 유형과 많은 열이있는 경우 유용 할 수 있습니다.

row1<-list("a",1,FALSE) #use 'list', not 'c' or 'cbind'!
row2<-list("b",2,TRUE)  

df<-data.frame(row1,stringsAsFactors = F) #first row
df<-rbind(df,row2) #now this works as you'd expect.

그랬어 df<-rbind(df, row2)?
Timothy C. Quinn

1

행렬없이 원시 데이터 프레임을 만드는 방법을 찾았습니다.

자동 열 이름 사용

df<-data.frame(
        t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
        ,row.names = NULL,stringsAsFactors = FALSE
    )

열 이름 포함

df<-setNames(
        data.frame(
            t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
            ,row.names = NULL,stringsAsFactors = FALSE
        ), 
        c("col1","col2","col3")
    )

0

행이 될 벡터가있는 경우를 사용하여 벡터를 연결하고 c()행 단위로 행렬에 전달한 다음 해당 행렬을 데이터 프레임으로 변환합니다.

예 : 행

dummydata1=c(2002,10,1,12.00,101,426340.0,4411238.0,3598.0,0.92,57.77,4.80,238.29,-9.9)
dummydata2=c(2002,10,2,12.00,101,426340.0,4411238.0,3598.0,-3.02,78.77,-9999.00,-99.0,-9.9)
dummydata3=c(2002,10,8,12.00,101,426340.0,4411238.0,3598.0,-5.02,88.77,-9999.00,-99.0,-9.9)

따라서 데이터 프레임으로 변환 할 수 있습니다.

dummyset=c(dummydata1,dummydata2,dummydata3)
col.len=length(dummydata1)
dummytable=data.frame(matrix(data=dummyset,ncol=col.len,byrow=TRUE))

두 가지 주요 제한 사항이 있습니다. (1) 단일 모드 데이터에서만 작동합니다. (2)이 작업을 수행하려면 마지막 # 열을 알아야합니다 (예 : a 가장 큰 행 길이가 선험적으로 알려지지 않은 비정형 배열 ).

이 솔루션은 간단 해 보이지만 R의 유형 변환에 대한 경험으로 볼 때 새로운 도전 과제를 만들어 낼 것이라고 확신합니다. 누구든지 이것에 대해 언급 할 수 있습니까?


0

새 행의 형식에 따라 tibble::add_row새 행이 단순하고 "값 쌍"으로 지정할 수있는 경우 사용할 수 있습니다. 또는 dplyr::bind_rows"do.call (rbind, dfs)의 일반적인 패턴을 효율적으로 구현" 할 수 있습니다 .

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