যখন কলামগুলির বিভিন্ন সেট থাকে তখন সারি (rbind) দ্বারা দুটি ডেটা ফ্রেম একত্রিত করুন


232

কলামগুলির একই সেট নেই এমন দুটি ডেটা ফ্রেমের সীমাবদ্ধ করা কি সম্ভব? আমি আশা করি যে কলামগুলি বাঁধার পরেও মেলে না তা ধরে রাখব।

উত্তর:


223

rbind.fillপ্যাকেজ থেকে plyrআপনি যা খুঁজছেন তা হতে পারে।


12
rbind.fillএবং bind_rows()উভয় নিঃশব্দে rownames ড্রপ।
মেরোস

3
@ মেরোজ হ্যাডলি: "হ্যাঁ, সমস্ত dplyr পদ্ধতি rownames উপেক্ষা করে।"
zx8754

এখানে ডকুমেন্টেশনের লিঙ্ক রয়েছে: rdocamentation.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 বছরে অনেক কিছুই ঘটেছে :) আমি সম্ভবত স্মার্টবাইন্ডটি আজ ব্যবহার করতে পারি না। এছাড়াও নোট করুন যে মূল প্রশ্নটি বড় ডেটা ফ্রেম নির্দিষ্ট করে না।
নীলফিউজ


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.tableso

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

এই পরিস্থিতিতে কাজ করবে। আপনি যখন বেশ কয়েকটি ডেটা টেবিল রাখেন এবং একটি তালিকা তৈরি করতে চান না তখন এটি পছন্দনীয় হতে পারে।


এটি সবচেয়ে সহজ, বাক্সের বাইরে সমাধান যা সহজেই যেকোন সংখ্যক ডেটাফ্রেমকে সাধারণীকরণ করে, কারণ আপনি সেগুলি পৃথক তালিকার উপাদানগুলিতে সংরক্ষণ করতে পারেন। intersectপদ্ধতির মতো অন্যান্য উত্তরগুলি কেবল 2 ডেটা ফ্রেমের জন্য কাজ করে এবং সহজেই সাধারণীকরণ হয় না।
সমৃদ্ধ পাউলো

35

বেস আর এর বেশিরভাগ উত্তরগুলির মধ্যে পরিস্থিতি সম্বোধন করা হয় যেখানে কেবলমাত্র একটি ডেটা.ফ্রেমে অতিরিক্ত কলাম রয়েছে বা ফলস্বরূপ ডেটা.ফ্রেমে কলামগুলির ছেদ থাকবে। যেহেতু ওপি লিখেছেন আমি কলামগুলি বাঁধার পরেও মেলে না তা ধরে রাখার প্রত্যাশা করছি , এই সমস্যাটির সমাধানের জন্য বেস আর পদ্ধতির সাহায্যে একটি উত্তর সম্ভবত পোস্ট করার উপযুক্ত।

নীচে, আমি দুটি বেস আর পদ্ধতি উপস্থাপন করছি: একটি যা মূল ডেটা ফ্রেমগুলিকে পরিবর্তন করে এবং একটি যা তা নয়। অতিরিক্তভাবে, আমি এমন একটি পদ্ধতি অফার করি যা অ-ধ্বংসাত্মক পদ্ধতিটিকে দুটিরও বেশি ডেটা.ফ্রেমে সাধারণ করে তোলে।

প্রথমে আসুন কিছু নমুনা ডেটা নেওয়া যাক।

# 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(এবং কোনও ত্রুটির ফলশ্রুতি ছাড়াই ফাংশনটি কাজ করার অনুমতি দিন), আপনি প্রতিটি ডেটাতে এনএ কলাম যুক্ত করবেন in ব্যবহার 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

নোট করুন যে প্রথম দুটি লাইন দু'এই কলামের পুরো সেট যুক্ত করে মূল তথ্য.ফ্রেমেস, ডিএফ 1 এবং ডিএফ 2 কে পরিবর্তন করে।


দুটি ডাটা.ফ্রেমে, আসল পরিবর্তন করবেন না
আসল ডাটা.ফ্রেমগুলি অক্ষত রেখে প্রথমে পৃথক নামের মাধ্যমে লুপ করুন, এন.এ. এর একটি নামযুক্ত ভেক্টরকে ডেটা.ফ্রেম ব্যবহার করে একটি তালিকায় সংযুক্ত করে ফিরিয়ে দিন 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)))
)

অনেক ডেটা.ফ্রেমেস, অরিজিনালগুলিতে পরিবর্তন করবেন না
যে আপনার কাছে দুটিরও বেশি ডেটা রয়েছে ra ফ্রেমগুলি, আপনি নিম্নলিখিতটি করতে পারেন।

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

আসল ডেটা.ফ্রেমসের সারি নামগুলি না দেখতে কিছুটা ভাল লাগবে? তাহলে এই কাজ।

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 মোট কলাম)) আমি এটি চেষ্টা করার পরে, আমি প্রথম কমান্ড <- mget (ls (প্যাটার্ন = "df \\ d +")) এর সাথে আটকে যাই। আমার ডেটাফ্রেমের বিভিন্ন নাম রয়েছে। আমি mydflist <- c (যেমন, ডাঃ, কেআর, হিট, এডি 1, এর) ব্যবহার করে একটি তালিকা তৈরি করার চেষ্টা করেছি তবে এটি আমাকে একটি বিশাল তালিকা দিয়েছে।
সার ২

কেবল @GKi- এর সাথে লিঙ্ক করুন
সার

1
@ ব্যবহার mydflist <- list(as, dr, kr, hyt, ed1, of)। এটি এমন একটি তালিকা তৈরি করতে হবে যা আপনার পরিবেশের আকার বাড়বে না, তবে কেবলমাত্র তালিকার প্রতিটি উপাদানকে নির্দেশ করবে (যতক্ষণ না আপনি পরবর্তীকালের কোনও বিষয়বস্তু পরিবর্তন না করে)। অপারেশনের পরে, কেবল নিরাপদ থাকতে তালিকার অবজেক্টটি সরান।
lmo

20

আপনি সাধারণ কলামের নামগুলিও সরিয়ে ফেলতে পারেন।

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

6

আমি এটি করার জন্য একটি ফাংশন লিখেছিলাম কারণ আমার কোডটি পছন্দ করে যদি কিছু ভুল হয় তবে আমাকে জানাতে। এই ফাংশনটি আপনাকে স্পষ্ট করে বলবে কোন কলামের নাম মেলে না এবং যদি আপনার কোনওরকম মিল নেই। তারপরে এটি যাইহোক ডেটা.ফ্রেমগুলি একত্রিত করার জন্য যথাসাধ্য চেষ্টা করবে। সীমাবদ্ধতাটি হ'ল আপনি একবারে কেবল দুটি ডেটা ফ্রেমগুলি একত্রিত করতে পারেন।

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

হতে পারে আমি আপনার প্রশ্নটি সম্পূর্ণরূপে ভুলভাবে লিখেছি, তবে "আমি আশা করি যে কলামগুলি বাঁধার পরেও মেলে না তা ধরে রাখতে" আমাকে মনে করে যে আপনি কোনও এসকিউএল কোয়েরির সাথে সন্ধান করছেন left joinবা সন্ধান করছেন right join। আর-এর mergeফাংশন রয়েছে যা আপনাকে বাম, ডান, বা অভ্যন্তরীণ এসকিউএল-এ টেবিলগুলিতে যোগদানের অনুরূপ নির্দিষ্ট করতে দেয়।

এখানে ইতিমধ্যে এখানে এই বিষয়ে একটি দুর্দান্ত প্রশ্নোত্তর রয়েছে: ডেটা ফ্রেমগুলিতে (অভ্যন্তরীণ, বাহ্যিক, বাম, ডান) কীভাবে যোগদান করতে হবে?


2

গেটলস / স্মার্টবাইন্ড তারিখগুলির সাথে কাজ করা পছন্দ করেনি, সম্ভবত এটি কারণ ছিল ওয়েভচারিং। সুতরাং এখানে আমার সমাধান ...

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

rpind (x, y) এর জায়গায় dplyr :: bind_rows (x, y) ব্যবহার করে কলাম ক্রমটি প্রথম ডেটা ফ্রেমের ভিত্তিতে রাখে।
রননকাহন

2

শুধু ডকুমেন্টেশন জন্য। আপনি নিম্নলিখিত ফর্মটিতে Stackগ্রন্থাগার এবং এর কার্যকারিতা চেষ্টা করতে পারেন Stack:

Stack(df_1, df_2)

আমার কাছে এমন ধারণাও রয়েছে যে এটি বড় ডেটা সেটগুলির জন্য অন্যান্য পদ্ধতির চেয়ে দ্রুত।


1

আপনি ব্যবহার করতে পারেন sjmisc::add_rows(), যা ব্যবহার করে 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

-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)]))
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.