स्तंभों के अलग-अलग सेट होने पर पंक्तियों (rbind) द्वारा दो डेटा फ़्रेमों को मिलाएं


232

क्या दो डेटा फ़्रेमों को बांधना संभव है, जिसमें स्तंभों का एक ही सेट नहीं है? मैं उन स्तंभों को बनाए रखने की उम्मीद कर रहा हूं जो बाइंड के बाद मेल नहीं खाते हैं।

जवाबों:


223

rbind.fillपैकेज से वह plyrहो सकता है जिसे आप ढूंढ रहे हैं।


12
rbind.fillऔर bind_rows()दोनों चुपचाप रोने वालों को छोड़ देते हैं।
MERose

3
@ मेरोस हैडली: "हां, सभी सपने देखने वाले तरीकों में रोने वाले लोगों की अनदेखी होती है।"
zx8754

यहाँ प्रलेखन के लिए एक लिंक है: rdocumentation.org/packages/plyr/versions/1.8.4/topics/…
गेब्रियल फेयर

124

एक अधिक हाल के समाधान का उपयोग करने के लिए है dplyrके bind_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

मैं बड़ी संख्या में डेटाफ्रेम (16) को विभिन्न कॉलम नामों के साथ संयोजित करने का प्रयास कर रहा हूं जब मैं यह कोशिश करता हूं तो मुझे एक त्रुटि मिलती है: कॉलम ABCको वर्ण से संख्यात्मक में नहीं बदला जा सकता है। क्या पहले कॉलम को बदलने का कोई तरीका है?
सर

46

आप पैकेज smartbindसे उपयोग कर सकते हैं gtools

उदाहरण:

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

3
मैंने smartbindदो बड़े डेटा फ़्रेमों के साथ (कुल मिलाकर लगभग 3 * 10 ^ 6 पंक्तियों में) की कोशिश की और 10 मिनट के बाद इसे निरस्त कर दिया।
जो

2
9 साल में बहुत कुछ हुआ है :) मैं आज स्मार्टबैंड का उपयोग नहीं कर सकता हूं। ध्यान दें कि मूल प्रश्न में बड़े डेटा फ़्रेम निर्दिष्ट नहीं थे।
नीलफूज

42

में स्तंभों तो DF1 में उन लोगों के एक सबसेट है df2 (स्तंभ नाम से):

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

37

इसके साथ एक विकल्प 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)

rbinddata.tableतब तक भी काम करेगा जब तक वस्तुओं को वस्तुओं में परिवर्तित किया जाता data.tableहै

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

इस स्थिति में भी काम करेगा। यह तब बेहतर हो सकता है जब आपके पास data.tables की एक जोड़ी हो और सूची का निर्माण न करना हो।


यह सबसे सरल, आउट-द-बॉक्स समाधान है जो आसानी से किसी भी संख्या में डेटाफ्रेम का सामान्यीकरण करता है, क्योंकि आप उन सभी को अलग-अलग सूची तत्वों में संग्रहीत कर सकते हैं। अन्य उत्तर, intersectदृष्टिकोण की तरह , केवल 2 डेटाफ्रेम के लिए काम करते हैं और आसानी से सामान्य नहीं करते हैं।
रिच पॉल

35

अधिकांश बेस R उत्तर उस स्थिति को संबोधित करते हैं जहां केवल एक data.frame के पास अतिरिक्त कॉलम हैं या जिसके परिणामस्वरूप data.frame स्तंभों का प्रतिच्छेदन होगा। चूंकि ओपी लिखते हैं, मैं उन स्तंभों को बनाए रखने की उम्मीद कर रहा हूं जो बांधने के बाद मेल नहीं खाते हैं , इस मुद्दे को संबोधित करने के लिए आधार आर विधियों का उपयोग कर एक उत्तर संभवतः पोस्ट करने के लायक है।

नीचे, मैं दो आधार आर तरीके प्रस्तुत करता हूं: एक जो मूल data.frames को बदल देता है, और एक जो नहीं करता है। इसके अतिरिक्त, मैं एक ऐसी विधि प्रदान करता हूं जो गैर-विनाशकारी विधि को दो से अधिक डेटा.फ्रेम में सामान्यीकृत करती है।

पहले, चलो कुछ नमूना डेटा प्राप्त करते हैं।

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

दो डेटा.फ्रेम, ऑरिजनल में परिवर्तन
। दोनों डेटा rbind( एफ़ में और बिना किसी त्रुटि के परिणाम के बिना फ़ंक्शन को काम करने की अनुमति देने के लिए) सभी कॉलम बनाए रखने के लिए , आप प्रत्येक डेटा में एनए कॉलम जोड़ें। उपयुक्त अनुपलब्ध नामों के साथ फ़्रेम करें का उपयोग कर setdiff

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

अब, rbind-म

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 को बदल देती हैं, दोनों स्तंभों का पूरा सेट जोड़ देती हैं।


दो डेटा.फ्रेम, मूल परिवर्तन न
करें। मूल डेटा को छोड़ दें। अलग-अलग, नामों के माध्यम से पहले लूप को अलग करें, NA का एक नामांकित वेक्टर लौटाएं जिसे डेटा के साथ एक सूची में संक्षिप्त किया गया है c। फिर, 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))

मेरे पास विभिन्न कॉलम (प्रत्येक में लगभग 70-90 कुल कॉलम) के साथ 16 डेटाफ्रेम हैं। जब मैं यह कोशिश करता हूं, तो मैं पहले कमांड के साथ फंस जाता हूं <- mget (ls (पैटर्न = "df \\ d +"))। मेरे डेटाफ्रेम के अलग-अलग नाम हैं। मैंने mydflist <- c (as, dr, kr, hyt, ed1,) का उपयोग करके एक सूची बनाने की कोशिश की, लेकिन इसने मुझे बहुत बड़ी सूची दी।
सर

बस @GKi से लिंक कर रहा है
सर

1
@ सर का उपयोग mydflist <- list(as, dr, kr, hyt, ed1, of)। यह एक सूची ऑब्जेक्ट का निर्माण करना चाहिए जो आपके पर्यावरण के आकार को नहीं बढ़ाता है, लेकिन सूची के प्रत्येक तत्व को इंगित करता है (जब तक आप बाद में किसी भी सामग्री को नहीं बदलते)। ऑपरेशन के बाद, सूची ऑब्जेक्ट को हटा दें, बस सुरक्षित होने के लिए।
lmo

20

आप सामान्य कॉलम नामों को भी निकाल सकते हैं।

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

6

मैंने ऐसा करने के लिए एक फ़ंक्शन लिखा था क्योंकि मुझे अपना कोड पसंद है कि मुझे बताएं कि क्या कुछ गलत है। यह फ़ंक्शन स्पष्ट रूप से आपको बताएगा कि कौन से कॉलम के नाम मेल नहीं खाते हैं और यदि आपके पास एक प्रकार का बेमेल है। फिर यह डेटा को किसी भी तरह से संयोजित करने की पूरी कोशिश करेगा। सीमा यह है कि आप एक समय में केवल दो data.frames गठबंधन कर सकते हैं।

### 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)
}

2

हो सकता है कि मैंने आपके प्रश्न को पूरी तरह से गलत कर दिया हो, लेकिन "मैं उन स्तंभों को बनाए रखने की उम्मीद कर रहा हूं जो बाइंड के बाद मेल नहीं खाते हैं" मुझे लगता है कि आप SQL क्वेरी के समान left joinया इसके right joinसमान देख रहे हैं । R में mergeफ़ंक्शन है जो आपको बाएं, दाएं, या आंतरिक को SQL में टेबल से जुड़ने के समान निर्दिष्ट करता है।

इस विषय पर पहले से ही एक महान प्रश्न और उत्तर यहां दिया गया है: डेटा फ़्रेम (आंतरिक, बाहरी, बाएं, दाएं) कैसे जुड़ें (मर्ज करें)?


2

gtools / smartbind Dates के साथ काम करना पसंद नहीं था, शायद इसलिए कि यह as.vectoring था। तो यहाँ मेरा समाधान है ...

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

dplyr का उपयोग :: rbind (x, y) के स्थान पर bind_rows (x, y) पहले डेटा फ़्रेम के आधार पर कॉलम क्रम को रखता है।
रॉनकॉन

2

सिर्फ दस्तावेज के लिए। आप Stackपुस्तकालय और उसके कार्य Stackको निम्न रूप में आज़मा सकते हैं :

Stack(df_1, df_2)

मुझे यह भी आभास होता है कि यह बड़े डेटा सेट के लिए अन्य विधियों की तुलना में तेज़ है।


1

आप उपयोग भी कर सकते हैं sjmisc::add_rows(), जो उपयोग करता है dplyr::bind_rows(), लेकिन इसके विपरीत bind_rows(), add_rows()विशेषताओं को संरक्षित करता है और इसलिए लेबल किए गए डेटा के लिए उपयोगी है ।

एक लेबल किए गए डेटासेट के साथ निम्न उदाहरण देखें। frq()समारोह, मूल्य लेबल के साथ आवृत्ति तालिकाओं प्रिंट अगर डेटा लेबल किया गया है।

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

-1
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)]))
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.