programing

두 데이터 프레임에 서로 다른 열 집합이 있는 경우 행(rbind)으로 결합

muds 2023. 7. 5. 21:03
반응형

두 데이터 프레임에 서로 다른 열 집합이 있는 경우 행(rbind)으로 결합

동일한 열 집합이 없는 두 개의 데이터 프레임을 행 바인딩할 수 있습니까?바인딩 후에 일치하지 않는 열을 유지하고 싶습니다.

rbind.fill포장에서plyr당신이 찾고 있는 것일 수도 있습니다.

더 최근의 해결책은 다음과 같습니다.dplyrbind_rows내가 생각하기에 더 효율적인 기능.smartbind.

df1 <- data.frame(a = c(1:5), b = c(6:10))
df2 <- data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5])
dplyr::bind_rows(df1, df2)
    a  b    c
1   1  6 <NA>
2   2  7 <NA>
3   3  8 <NA>
4   4  9 <NA>
5   5 10 <NA>
6  11 16    A
7  12 17    B
8  13 18    C
9  14 19    D
10 15 20    E

대부분의 기본 R 응답은 하나의 data.frame에 추가 열이 있거나 결과 data.frame에 열이 교차하는 상황을 해결합니다.OP가 쓰기 때문에 바인드 후에도 일치하지 않는 열을 유지하기를 희망합니다. 이 문제를 해결하기 위해 기본 R 방법을 사용한 답변은 게시할 가치가 있습니다.

아래에서는 두 가지 기본 R 방법을 제시합니다.원본 data.frames를 변경하는 것과 그렇지 않은 것.또한 비파괴적 방법을 두 개 이상의 data.frame으로 일반화하는 방법을 제안합니다.

우선 샘플 데이터를 받아보겠습니다.

# sample data, variable c is in df1, variable d is in df2
df1 = data.frame(a=1:5, b=6:10, d=month.name[1:5])
df2 = data.frame(a=6:10, b=16:20, c = letters[8:12])

두 개의 data.frames, 원본 변경
두 data.frames의 모든 열을 저장하려면 다음과 같이 하십시오.rbind(그리고 오류가 발생하지 않고 함수가 작동할 수 있도록 허용) 각 data.frame에 NA 열을 추가하고 다음을 사용하여 해당 누락된 이름을 입력합니다.setdiff.

# fill in non-overlapping columns with NAs
df1[setdiff(names(df2), names(df1))] <- NA
df2[setdiff(names(df1), names(df2))] <- NA

지금이다,rbind-em

rbind(df1, df2)
    a  b        d    c
1   1  6  January <NA>
2   2  7 February <NA>
3   3  8    March <NA>
4   4  9    April <NA>
5   5 10      May <NA>
6   6 16     <NA>    h
7   7 17     <NA>    i
8   8 18     <NA>    j
9   9 19     <NA>    k
10 10 20     <NA>    l

처음 두 줄은 원래 data.frames, df1 및 df2를 변경하여 전체 열 집합을 두 열에 모두 추가합니다.


두 개의 data.frames, 원본을 변경하지 마십시오.
원본 data.frames를 그대로 유지하려면 먼저 서로 다른 이름을 루프하여 다음을 사용하여 data.frames와 목록에 연결된 NA의 명명된 벡터를 반환합니다.c.그리고나서,data.frame결과를 적절한 data.frame으로 변환합니다.rbind.

rbind(
  data.frame(c(df1, sapply(setdiff(names(df2), names(df1)), function(x) NA))),
  data.frame(c(df2, sapply(setdiff(names(df1), names(df2)), function(x) NA)))
)

많은 data.frames는 원본을 변경하지 않습니다.
두 개 이상의 data.frames가 있는 경우 다음을 수행할 수 있습니다.

# put data.frames into list (dfs named df1, df2, df3, etc)
mydflist <- mget(ls(pattern="df\\d+"))
# get all variable names
allNms <- unique(unlist(lapply(mydflist, names)))

# put em all together
do.call(rbind,
        lapply(mydflist,
               function(x) data.frame(c(x, sapply(setdiff(allNms, names(x)),
                                                  function(y) NA)))))

원본 data.frames의 행 이름을 보지 않는 것이 더 좋을까요?그럼 이렇게 해요.

do.call(rbind,
        c(lapply(mydflist,
                 function(x) data.frame(c(x, sapply(setdiff(allNms, names(x)),
                                                    function(y) NA)))),
          make.row.names=FALSE))

의 대안data.table:

library(data.table)
df1 = data.frame(a = c(1:5), b = c(6:10))
df2 = data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5])
rbindlist(list(df1, df2), fill = TRUE)

rbind에서도 작동합니다.data.table객체가 로 변환되는 한data.table객체, 그래서

rbind(setDT(df1), setDT(df2), fill=TRUE)

이 경우에도 작동합니다.data.tables가 몇 개 있고 목록을 구성하지 않으려는 경우 이 방법이 좋습니다.

사용할 수 있습니다.smartbindgtools꾸러미

예:

library(gtools)
df1 <- data.frame(a = c(1:5), b = c(6:10))
df2 <- data.frame(a = c(11:15), b = c(16:20), c = LETTERS[1:5])
smartbind(df1, df2)
# result
     a  b    c
1.1  1  6 <NA>
1.2  2  7 <NA>
1.3  3  8 <NA>
1.4  4  9 <NA>
1.5  5 10 <NA>
2.1 11 16    A
2.2 12 17    B
2.3 13 18    C
2.4 14 19    D
2.5 15 20    E

df1의 열이 df2의 열의 하위 집합인 경우(열 이름 기준):

df3 <- rbind(df1, df2[, names(df1)])

일반적인 열 이름을 꺼낼 수도 있습니다.

> cols <- intersect(colnames(df1), colnames(df2))
> rbind(df1[,cols], df2[,cols])

저는 제 코드가 잘못된 것이 있으면 알려주는 것이 좋아서 이를 위한 기능을 썼습니다.이 함수는 어떤 열 이름이 일치하지 않고 유형이 일치하지 않는지 명시적으로 알려줍니다.그러면 어쨌든 data.frames를 결합하기 위해 최선을 다할 것입니다.제한 사항은 한 번에 두 개의 data.frame만 결합할 수 있다는 것입니다.

### combines data frames (like rbind) but by matching column names
# columns without matches in the other data frame are still combined
# but with NA in the rows corresponding to the data frame without
# the variable
# A warning is issued if there is a type mismatch between columns of
# the same name and an attempt is made to combine the columns
combineByName <- function(A,B) {
    a.names <- names(A)
    b.names <- names(B)
    all.names <- union(a.names,b.names)
    print(paste("Number of columns:",length(all.names)))
    a.type <- NULL
    for (i in 1:ncol(A)) {
        a.type[i] <- typeof(A[,i])
    }
    b.type <- NULL
    for (i in 1:ncol(B)) {
        b.type[i] <- typeof(B[,i])
    }
    a_b.names <- names(A)[!names(A)%in%names(B)]
    b_a.names <- names(B)[!names(B)%in%names(A)]
    if (length(a_b.names)>0 | length(b_a.names)>0){
        print("Columns in data frame A but not in data frame B:")
        print(a_b.names)
        print("Columns in data frame B but not in data frame A:")
        print(b_a.names)
    } else if(a.names==b.names & a.type==b.type){
        C <- rbind(A,B)
        return(C)
    }
    C <- list()
    for(i in 1:length(all.names)) {
        l.a <- all.names[i]%in%a.names
        pos.a <- match(all.names[i],a.names)
        typ.a <- a.type[pos.a]
        l.b <- all.names[i]%in%b.names
        pos.b <- match(all.names[i],b.names)
        typ.b <- b.type[pos.b]
        if(l.a & l.b) {
            if(typ.a==typ.b) {
                vec <- c(A[,pos.a],B[,pos.b])
            } else {
                warning(c("Type mismatch in variable named: ",all.names[i],"\n"))
                vec <- try(c(A[,pos.a],B[,pos.b]))
            }
        } else if (l.a) {
            vec <- c(A[,pos.a],rep(NA,nrow(B)))
        } else {
            vec <- c(rep(NA,nrow(A)),B[,pos.b])
        }
        C[[i]] <- vec
    }
    names(C) <- all.names
    C <- as.data.frame(C)
    return(C)
}

gtools/smartbind는 날짜와 함께 일하는 것을 좋아하지 않았습니다. 아마도 그것이 as.vecting이었기 때문일 것입니다.그래서 여기 내 해결책이...

sbind = function(x, y, fill=NA) {
    sbind.fill = function(d, cols){ 
        for(c in cols)
            d[[c]] = fill
        d
    }

    x = sbind.fill(x, setdiff(names(y),names(x)))
    y = sbind.fill(y, setdiff(names(x),names(y)))

    rbind(x, y)
}

문서화를 위해서만.사용할 수 있습니다.Stack과 그 Stack다음과 같은 형태로:

Stack(df_1, df_2)

또한 대용량 데이터 세트의 경우 다른 방법보다 빠르다는 인상을 받았습니다.

제가 을 완전히 잘못 읽었을 "한다"는이 질을완잘못, "바인딩후라일희다니않합열는망유를기하말합있각하고다게생다니고찾열을새운로이당신은지문을는지하치만지있에도전히도수었을읽▁are▁that▁a▁you▁maybe▁for▁columns▁looking▁me라,▁the▁think▁makes▁the합▁"다니▁"▁question게하각고다생▁but있i▁after고▁to바"▁the찾▁bind질▁your을열▁do▁ileft join또는right joinSQL 쿼리와 유사합니다.은 R을 .mergeSQL의 테이블 조인과 유사한 왼쪽, 오른쪽 또는 안쪽 조인을 지정할 수 있는 함수입니다.

여기에는 이미 이 주제에 대한 훌륭한 질의응답이 있습니다.데이터 프레임(내부, 외부, 왼쪽, 오른쪽)을 결합(합병)하는 방법은 무엇입니까?

를 사용할 수도 있습니다. 를 사용합니다.dplyr::bind_rows()그러나 과는 달리bind_rows(),add_rows()속성을 보존하므로 레이블이 지정된 데이터에 유용합니다.

레이블이 지정된 데이터 집합의 다음 예를 참조하십시오.frq()-function은 데이터에 레이블이 지정된 경우 값 레이블이 있는 빈도 표를 인쇄합니다.

library(sjmisc)
library(dplyr)

data(efc)
# select two subsets, with some identical and else different columns
x1 <- efc %>% select(1:5) %>% slice(1:10)
x2 <- efc %>% select(3:7) %>% slice(11:20)

str(x1)
#> 'data.frame':    10 obs. of  5 variables:
#>  $ c12hour : num  16 148 70 168 168 16 161 110 28 40
#>   ..- attr(*, "label")= chr "average number of hours of care per week"
#>  $ e15relat: num  2 2 1 1 2 2 1 4 2 2
#>   ..- attr(*, "label")= chr "relationship to elder"
#>   ..- attr(*, "labels")= Named num  1 2 3 4 5 6 7 8
#>   .. ..- attr(*, "names")= chr  "spouse/partner" "child" "sibling" "daughter or son -in-law" ...
#>  $ e16sex  : num  2 2 2 2 2 2 1 2 2 2
#>   ..- attr(*, "label")= chr "elder's gender"
#>   ..- attr(*, "labels")= Named num  1 2
#>   .. ..- attr(*, "names")= chr  "male" "female"
#>  $ e17age  : num  83 88 82 67 84 85 74 87 79 83
#>   ..- attr(*, "label")= chr "elder' age"
#>  $ e42dep  : num  3 3 3 4 4 4 4 4 4 4
#>   ..- attr(*, "label")= chr "elder's dependency"
#>   ..- attr(*, "labels")= Named num  1 2 3 4
#>   .. ..- attr(*, "names")= chr  "independent" "slightly dependent" "moderately dependent" "severely dependent"

bind_rows(x1, x1) %>% frq(e42dep)
#> 
#> # e42dep <numeric> 
#> # total N=20  valid N=20  mean=3.70  sd=0.47
#>  
#>   val frq raw.prc valid.prc cum.prc
#>     3   6      30        30      30
#>     4  14      70        70     100
#>  <NA>   0       0        NA      NA

add_rows(x1, x1) %>% frq(e42dep)
#> 
#> # elder's dependency (e42dep) <numeric> 
#> # total N=20  valid N=20  mean=3.70  sd=0.47
#>  
#>  val                label frq raw.prc valid.prc cum.prc
#>    1          independent   0       0         0       0
#>    2   slightly dependent   0       0         0       0
#>    3 moderately dependent   6      30        30      30
#>    4   severely dependent  14      70        70     100
#>   NA                   NA   0       0        NA      NA

두 번째 데이터베이스 행 수를 추가하여 원래 데이터베이스(db1)의 끝에 삽입할 수 있습니다.db2에 포함되지 않은 열에는 NA 값이 표시됩니다.

db1[nrow(db1)+1:nrow(db1)+nrow(db2), names(db2)] <- db2

rbind.ordered=function(x,y){

  diffCol = setdiff(colnames(x),colnames(y))
  if (length(diffCol)>0){
    cols=colnames(y)
    for (i in 1:length(diffCol)) y=cbind(y,NA)
    colnames(y)=c(cols,diffCol)
  }

  diffCol = setdiff(colnames(y),colnames(x))
  if (length(diffCol)>0){
    cols=colnames(x)
    for (i in 1:length(diffCol)) x=cbind(x,NA)
    colnames(x)=c(cols,diffCol)
  }
  return(rbind(x, y[, colnames(x)]))
}

언급URL : https://stackoverflow.com/questions/3402371/combine-two-data-frames-by-rows-rbind-when-they-have-different-sets-of-columns

반응형