كيفية استخدام عدد غير معروف من الأعمدة الرئيسية في data.table

StackOverflow https://stackoverflow.com//questions/11677424

  •  12-12-2019
  •  | 
  •  

سؤال

أريد أن أفعل نفس الشيء كما هو موضح هنا, ، أي.إضافة الصفوف المفقودة إلى data.table.الصعوبة الإضافية الوحيدة التي أواجهها هي أنني أريد عدد الأعمدة الرئيسية، أي:أن تكون تلك الصفوف المستخدمة للانضمام الذاتي مرنة.

فيما يلي مثال صغير يكرر بشكل أساسي ما تم فعله في الرابط المذكور أعلاه:

df <- data.frame(fundID   = rep(letters[1:4], each=6),
                 cfType   = rep(c("D", "D", "T", "T", "R", "R"), times=4),
                 variable = rep(c(1,3), times=12),
                 value    = 1:24)
DT <- as.data.table(df)
idCols <- c("fundID", "cfType")
setkeyv(DT, c(idCols, "variable"))
DT[CJ(unique(df$fundID), unique(df$cfType), seq(from=min(variable), to=max(variable))), nomatch=NA]

ما يزعجني هو السطر الأخير.أريد idCols أن تكون مرنة (على سبيل المثال، إذا كنت أستخدمها ضمن وظيفة ما)، لذلك لا أريد الكتابة unique(df$fundID), unique(df$cfType) يدويا.ومع ذلك، لا أجد أي حل بديل لهذا.كل محاولاتي لتقسيم المجموعة الفرعية تلقائيًا df إلى ناقلات، حسب الحاجة CJ, ، فشل مع رسالة الخطأ خطأ في setkeyv(x, cols, Verbose = Verbose):العمود "V1" هو النوع "قائمة" وهو غير مسموح به (حاليًا) كنوع عمود رئيسي.

CJ(sapply(df[, idCols], unique))
CJ(unique(df[, idCols]))
CJ(as.vector(unique(df[, idCols])))
CJ(unique(DT[, idCols, with=FALSE]))

لقد حاولت أيضًا بناء التعبير بنفسي:

str <- ""
for (i in idCols) {
  str <- paste0(str, "unique(df$", i, "), ")
}
str <- paste0(str, "seq(from=min(variable), to=max(variable))")
str
[1] "unique(df$fundID), unique(df$cfType), seq(from=min(variable), to=max(variable))"

ولكن بعد ذلك لا أعرف كيفية استخدامها str.كل هذا يفشل:

CJ(eval(str))
CJ(substitute(str))
CJ(call(str))

هل يعرف أحد الحل الجيد؟

هل كانت مفيدة؟

المحلول

لم أستخدم حزمة data.table مطلقًا، لذا سامحني إذا فاتني العلامة هنا، ولكن أعتقد أنني حصلت عليها.هناك الكثير يحدث هنا.ابدأ بالقراءة do.call, ، والذي يسمح لك بتقييم أي وظيفة بطريقة غير تقليدية حيث يتم تحديد الوسائط من خلال قائمة مقدمة (حيث يكون كل عنصر في القائمة مطابقًا موضعيًا لوسائط الوظيفة ما لم يتم تسميتها بشكل صريح).لاحظ أيضًا أنه كان علي تحديد ذلك min(df$variable) بدلا من مجرد min(variable).يقرأ صفحة هادلي حول تحديد النطاق للحصول على فكرة عن هذه القضية هنا.

CJargs <- lapply(df[, idCols], unique)
names(CJargs) <- NULL
CJargs[[length(CJargs) +1]] <- seq(from=min(df$variable), to=max(df$variable))
DT[do.call("CJ", CJargs),nomatch=NA]

نصائح أخرى

إجابة مايكل رائعة. do.call هناك حاجة بالفعل للاتصال CJ بمرونة بهذه الطريقة، afaik.

لتوضيح نهج بناء التعبير والبدء بالكود الخاص بك، ولكن إزالة df$ أجزاء (غير مطلوبة ولم يتم تنفيذها في الإجابة المرتبطة، منذ ذلك الحين i يتم تقييمه ضمن نطاق DT) :

str <- "" 
for (i in idCols) { 
  str <- paste0(str, "unique(", i, "), ") 
} 
str <- paste0(str, "seq(from=min(variable), to=max(variable))") 
str 
[1] "unique(fundID), unique(cfType), seq(from=min(variable), to=max(variable))" 

ثم انها :

expr <- parse(text=paste0("CJ(",str,")"))
DT[eval(expr),nomatch=NA]

أو بدلاً من ذلك، قم ببناء الاستعلام بالكامل وتقييمه ديناميكيًا:

eval(parse(text=paste0("DT[CJ(",str,"),nomatch=NA")))

وإذا تم القيام بذلك كثيرًا، فقد يكون من المفيد إنشاء وظيفة مساعدة لنفسك:

E = function(...) eval(parse(text=paste0(...)))

لتقليله إلى:

E("DT[CJ(",str,"),nomatch=NA")
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top