it-swarm.asia

دمج إطارين للبيانات مع الاحتفاظ بترتيب الصف الأصلي

أريد دمج إطارين للبيانات مع الحفاظ على ترتيب الصف الأصلي لأحدهما (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
51
DJack

تحقق من وظيفة الصلة في حزمة plyr. يشبه الدمج ، لكنه يسمح لك بالاحتفاظ بترتيب الصفوف بإحدى مجموعات البيانات. عموما ، هو أكثر مرونة من الدمج.

باستخدام بيانات المثال الخاص بك ، سوف نستخدم 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- الأجسام المدمجة - td4296561.html

26
user2635373

تحتاج فقط إلى إنشاء متغير يعطي رقم الصف في 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), ]
45
PAC

من data.table v1.9.5 + ، يمكنك القيام بما يلي:

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

ينفذ الصلة على عمود class عن طريق إيجاد صفوف مطابقة في df.1 لكل صف في df.2 واستخراج الأعمدة المقابلة.

11
Arun

يمكنك أيضًا التحقق من وظيفة inner_join في حزمة dplyr من Hadley (التكرار التالي لـ 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
8
alex23lemm

من أجل الاكتمال ، التحديث في صلة يحتفظ بترتيب الصف الأصلي أيضًا. قد يكون هذا بديلاً عن إجابة Arun data.table إذا كان هناك بضعة أعمدة فقط لإلحاقها:

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.

5
Uwe

الإجابة المقبولة تقترح طريقة يدوية للحفاظ على النظام عند استخدام merge ، والذي يعمل في معظم الأحيان ولكنه يتطلب عمل يدوي غير ضروري. يأتي هذا الحل في الجزء الخلفي من كيفية ddply () دون الفرز؟ ، الذي يتعامل مع مسألة الحفاظ على النظام ولكن في سياق تقسيم التطبيق - الجمع:

جاء هذا على قائمة plyr البريدية لفترة من الوقت (التي أثارها kohske لا أقل) وهذا هو الحل الذي يقدمه بيتر Meilstrup للحالات المحدودة:

#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.order العامة للحفاظ على ترتيب الصف الأصلي لمكالمة 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 بأتمتة النهج في الإجابة المقبولة.

3
landroni

في هذه الحالة بالذات ، يمكن أن نتمكن من 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
Moody_Mudskipper

بفضل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
}

يفترض هذا أنك تريد الاحتفاظ بترتيب إطار البيانات الأول ، وسيكون لإطار البيانات المدمج نفس عدد الصفوف في إطار إطار البيانات الأول. سوف يوفر لك إطار البيانات النظيف بدون أعمدة إضافية.

1
qed

هناك العديد من حالات الاستخدام التي تعمل فيها مجموعة فرعية بسيطة:

# 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() مطلوبة:

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