programing

원래 행 순서를 유지하면서 두 데이터 프레임 병합

newsource 2023. 10. 17. 20:17

원래 행 순서를 유지하면서 두 데이터 프레임 병합

그중 하나의 원래 행 순서를 지키면서 두 개의 데이터 프레임을 병합하려고 합니다 (df.2아래의 예에서).

다음은 몇 가지 샘플 데이터입니다(모든 값:class열은 두 데이터 프레임 모두에서 정의됩니다.)

df.1 <- data.frame(class = c(1, 2, 3), prob = c(0.5, 0.7, 0.3))
df.2 <- data.frame(object = c('A', 'B', 'D', 'F', 'C'), class = c(2, 1, 2, 3, 1))

다음을 수행할 경우:

merge(df.2, df.1)

출력:

  class object prob
1     1      B  0.5
2     1      C  0.5
3     2      A  0.7
4     2      D  0.7
5     3      F  0.3

추가하면sort = FALSE:

merge(df.2, df.1, sort = F)                                                        

결과는 다음과 같습니다.

  class object prob
1     2      A  0.7
2     2      D  0.7
3     1      B  0.5
4     1      C  0.5
5     3      F  0.3

하지만 제가 원하는 것은:

  class object prob
1     2      A  0.7
2     1      B  0.5
3     2      D  0.7
4     3      F  0.3    
5     1      C  0.5

df.2의 행 번호를 나타내는 변수만 생성하면 됩니다.그런 다음 데이터를 병합한 후 이 변수에 따라 새 데이터 집합을 정렬합니다.다음은 예입니다.

df.1<-data.frame(class=c(1,2,3), prob=c(0.5,0.7,0.3))
df.2<-data.frame(object=c('A','B','D','F','C'), class=c(2,1,2,3,1))
df.2$id  <- 1:nrow(df.2)
out  <- merge(df.2,df.1, by = "class")
out[order(out$id), ]

plyr 패키지에서 join 기능을 확인해보세요.이것은 병합과 같지만 데이터 세트 중 하나의 행 순서를 유지할 수 있게 해줍니다.전반적으로 합병보다 유연성이 뛰어납니다.

우리는 당신의 예 데이터를 사용하여,join다음과 같이:

> join(df.2,df.1)
Joining by: class
  object class prob
1      A     2  0.7
2      B     1  0.5
3      D     2  0.7
4      F     3  0.3
5      C     1  0.5

다음은 행 순서를 유지하기 위한 병합 함수에 대한 수정 사항을 설명하는 몇 가지 링크입니다.

http://www.r-statistics.com/2012/01/merging-two-data-frame-objects-while-preserving-the-rows-order/

http://r.789695.n4.nabble.com/patching-merge-to-allow-the-user-to-keep-the-order-of-one-of-the-two-data-frame-objects-merged-td4296561.html

당신은 또한 확인할 수 있습니다.inner_join해들리의 기능dplyr패키지(다음 버전)plyr 첫 의 행 첫 번째 데이터 집합의 행 순서를 유지합니다.원하는 솔루션과 약간 다른 점은 첫 번째 데이터 집합의 원래 열 순서도 유지된다는 점입니다.따라서 합병 시 사용했던 컬럼을 반드시 첫 번째 위치에 배치하지는 않습니다.

위의 예시를 사용하면,inner_join결과는 다음과 같습니다.

inner_join(df.2,df.1)
Joining by: "class"
  object class prob
1      A     2  0.7
2      B     1  0.5
3      D     2  0.7
4      F     3  0.3
5      C     1  0.5

data.table v1.9.5+에서 다음 작업을 수행할 수 있습니다.

require(data.table) # v1.9.5+
setDT(df.1)[df.2, on="class"]

는 열에 조인을 수행합니다.class일치하는 행을 찾음df.1의 각 df.2해당하는 열을 추출합니다.

완전성을 위해 조인에서 업데이트하면 원래 행 순서도 유지됩니다.추가할 열이 몇 개뿐인 경우 이는 아룬의 대답에 대한 대안이 될 수 있습니다.

library(data.table)
setDT(df.2)[df.1, on = "class", prob := i.prob][]
   object class prob
1:      A     2  0.7
2:      B     1  0.5
3:      D     2  0.7
4:      F     3  0.3
5:      C     1  0.5

여기서,df.2에 바로 가입되어 있습니다.df.1그리고 새 칼럼을 얻습니다.prob일치하는 행에서 복사되는df.1.

승인된 답변은 사용할 때 질서를 유지하는 수동 방법을 제안합니다.merge, 대부분의 경우 작동하지만 불필요한 수작업이 필요합니다.이 솔루션은 정렬하지 않고 ddply()를 적용하는 방법(How to ddply?)을 통해 제공되며, 이는 질서를 유지하는 문제를 다루지만 분할 적용-결합 맥락에서 다루고 있습니다.

이것은 얼마 전에 (@kohske less) plyrer 메일링 리스트에 올라왔고, 이것은 Peter Milstrup이 한정된 경우에 제공하는 솔루션입니다.

#Peter's version used a function gensym to
# create the col name, but I couldn't track down
# what package it was in.
keeping.order <- function(data, fn, ...) { 
  col <- ".sortColumn"
  data[,col] <- 1:nrow(data) 
  out <- fn(data, ...) 
  if (!col %in% colnames(out)) stop("Ordering column not preserved by function") 
  out <- out[order(out[,col]),] 
  out[,col] <- NULL 
  out 
} 

이제 이 제네릭을 사용할 수 있습니다.keeping.ordera의 원래 행 순서를 유지하는 함수merge출:

df.1<-data.frame(class=c(1,2,3), prob=c(0.5,0.7,0.3))
df.2<-data.frame(object=c('A','B','D','F','C'), class=c(2,1,2,3,1))
keeping.order(df.2, merge, y=df.1, by = "class")

요청에 따라 다음과 같은 결과가 발생합니다.

> keeping.order(df.2, merge, y=df.1, by = "class")
  class object id prob
3     2      A  1  0.7
1     1      B  2  0.5
4     2      D  3  0.7
5     3      F  4  0.3
2     1      C  5  0.5

그렇게keeping.order승인된 답변에서 접근 방식을 효과적으로 자동화합니다.

@PAC 덕분에 다음과 같은 것을 생각해 냈습니다.

merge_sameord = function(x, y, ...) {
    UseMethod('merge_sameord')
}

merge_sameord.data.frame = function(x, y, ...) {
    rstr = paste(sample(c(0:9, letters, LETTERS), 12, replace=TRUE), collapse='')
    x[, rstr] = 1:nrow(x)
    res = merge(x, y, all.x=TRUE, sort=FALSE, ...)
    res = res[order(res[, rstr]), ]
    res[, rstr] = NULL
    res
}

이것은 첫 번째 데이터 프레임의 순서를 유지하고 병합된 데이터 프레임의 행 수가 첫 번째 데이터 프레임과 동일하다고 가정합니다.추가 열 없이 깨끗한 데이터 프레임을 제공합니다.

패키지 개발자용

패키지 개발자로서 가능한 한 적은 수의 다른 패키지에 의존하기를 원합니다.패키지 개발자 IMHO에게 너무 자주 바뀌는 깔끔한 역기능.

의 가입 기능을 활용할 수 있도록 하기 위해서는dplyr가져오기 없이 패키지dplyr, 아래는 빠른 구현입니다.원래 정렬을 유지하고(OP에서 요청한 대로) 접합 열을 앞쪽으로 이동시키지 않습니다(이것은 또 다른 성가신 일입니다).merge()).

left_join <- function(x, y, ...) {
  merge_exec(x = x, y = y, all.x = TRUE, ...)
}
right_join <- function(x, y, ...) {
  merge_exec(x = x, y = y, all.y = TRUE, ...)
}
inner_join <- function(x, y, ...) {
  merge_exec(x = x, y = y, all = TRUE, ...)
}
full_join <- function(x, y, ...) {
  merge_exec(x = x, y = y, ...)
}

# workhorse:
merge_exec <- function(x, y, ...) {
  # set index
  x$join_id_ <- 1:nrow(x)
  # do the join
  joined <- merge(x = x, y = y, sort = FALSE, ...)
  # get suffices (yes, I prefer this over suffixes)
  if ("suffixes" %in% names(list(...))) {
    suffixes <- list(...)$suffixes
  } else {
    suffixes <- c("", "")
  }
  # get columns names in right order, so the 'by' column won't be forced first
  cols <- unique(c(colnames(x), 
                   paste0(colnames(x), suffixes[1]), 
                   colnames(y), 
                   paste0(colnames(y), suffixes[2])))
  # get the original row and column index
  joined[order(joined$join_id),
         cols[cols %in% colnames(joined) & cols != "join_id_"]]
}

이 특정한 경우에 당신은 우리에게factor콤팩트 염기 용액의 경우:

df.2$prob = factor(df.2$class,labels=df.1$prob)

df.2
#   object class prob
# 1      A     2  0.7
# 2      B     1  0.5
# 3      D     2  0.7
# 4      F     3  0.3
# 5      C     1  0.5

일반적인 해결책은 아니지만, 다음과 같은 경우에 효과가 있습니다.

  1. 고유 값을 포함하는 룩업 테이블이 있습니다.
  2. 테이블을 새로 만들지 않고 업데이트하려는 경우
  3. 조회 테이블이 병합 열로 정렬됩니다.
  4. 룩업 테이블에 추가 레벨이 없습니다.
  5. 은 을 .left_join
  6. 인자가 괜찮으시다면

1은 협상할 수 없습니다. 나머지는 우리가 할 수 있습니다.

df.3  <- df.2 # deal with 2.
df.1b <- df.1[order(df.1$class),] # deal with 3
df.1b <- df.1b[df.1$class %in% df.2$class,] # deal with 4.
df.3$prob = factor(df.3$class,labels=df.1b$prob)
df.3 <- df3[!is.na(df.3$prob),] # deal with 5. if you want an `inner join`
df.3$prob <- as.numeric(as.character(df.3$prob)) # deal with 6.

최고 등급의 답변은 원래 포스터가 원하는 대로 1열의 "클래스"를 생성하지 않습니다.OP가 df.2에서 열 순서 전환을 허용할 경우, 가능한 기본 R 비병합 한 줄 답변은 다음과 같습니다.

df.1 <- data.frame(class = c(1, 2, 3), prob = c(0.5, 0.7, 0.3))  
df.2 <- data.frame(class = c(2, 1, 2, 3, 1), object = c('A', 'B', 'D', 'F', 'C'))  
cbind(df.2, df.1[match(df.2$class, df.1$class), -1, drop = FALSE])

행에 묘사된 정보, 이름들이 마음에 듭니다.OP가 원하는 결과를 정확하게 복제하는 완전한 원-라이너는 다음과 같습니다.

data.frame(cbind(df.2, df.1[match(df.2$class, df.1$class), -1, drop = FALSE]),
           row.names = NULL)

시간이 지남에 따라 개발 경로가 자주 다르기 때문에 패키지 개발자가 다른 패키지(또는 "verse")에 의존하는 것이 적을수록 좋다는 https://stackoverflow.com/users/4575331/ms-berends 의 의견에 동의합니다.

참고: 위의 원-라이너는 에 중복이 있을 경우 작동하지 않습니다.df.1$class. 이를 극복할 수 있습니다.'outer'그리고 더 일반적으로 베렌드 씨의 영리한 합병 후 리스크램블링 코드를 가진 루프.

간단한 부분 집합이 다음과 같은 몇 가지 용도로 사용됩니다.

# Use the key variable as row.names
row.names(df.1) = df.1$key

# Sort df.1 so that it's rows match df.2
df.3 = df.1[df.2$key, ]

# Create a data.frame with cariables from df.1 and (the sorted) df.2
df.4 = cbind(df.1, df.3)

이 코드는 df.2와 순서를 유지하고 df.1의 일치하는 데이터만 추가합니다.

변수를 하나만 추가할 경우,cbind()is not required:

row.names(df.1) = df.1$key
df.2$data = df.1[df.2$key, "data"]

나도 같은 문제가 있었지만 새로운 열 'num'에 적용된 더미 벡터 c(1:5)를 사용했습니다.

df.2 <- data.frame(object = c('A', 'B', 'D', 'F', 'C'), class = c(2, 1, 2, 3, 1))

df.2$num <- c(1:5) # This range you can order in the last step.

dfm <- merge(df.2, df.1) # merged

dfm <- dfm[order(dfm$num),] # ascending order

베이스에서 더 효율적인 방법이 있을지도 모릅니다.이것은 기능으로 만들기에 꽤 간단할 것입니다.

varorder <- names(mydata)  # --- Merge 
mydata <- merge(mydata, otherData, by="commonVar")
restOfvars <- names(mydata[!(names(mydata) %in% varorder)])

mydata[c(varorder,restOfvars)]

언급URL : https://stackoverflow.com/questions/17878048/merge-two-data-frames-while-keeping-the-original-row-order