مجموعة فرعية A DATA.RAFT
سؤال
قد يبدو هذا أمرًا نموذجيًا plyr
مشكلة ، لكن لدي شيء مختلف في الاعتبار. إليك الوظيفة التي أريد تحسينها (تخطي for
عقدة).
# dummy data
set.seed(1985)
lst <- list(a=1:10, b=11:15, c=16:20)
m <- matrix(round(runif(200, 1, 7)), 10)
m <- as.data.frame(m)
dfsub <- function(dt, lst, fun) {
# check whether dt is `data.frame`
stopifnot (is.data.frame(dt))
# check if vectors in lst are "whole" / integer
# vector elements should be column indexes
is.wholenumber <- function(x, tol = .Machine$double.eps^0.5) abs(x - round(x)) < tol
# fall if any non-integers in list
idx <- rapply(lst, is.wholenumber)
stopifnot(idx)
# check for list length
stopifnot(ncol(dt) == length(idx))
# subset the data
subs <- list()
for (i in 1:length(lst)) {
# apply function on each part, by row
subs[[i]] <- apply(dt[ , lst[[i]]], 1, fun)
}
# preserve names
names(subs) <- names(lst)
# convert to data.frame
subs <- as.data.frame(subs)
# guess what =)
return(subs)
}
والآن مظاهرة قصيرة ... في الواقع ، أنا على وشك شرح ما كنت أنوي في المقام الأول. أردت مجموعة فرعية data.frame
بواسطة ناقلات تجمعت في list
هدف. نظرًا لأن هذا جزء من التعليمات البرمجية من وظيفة ترافق معالجة البيانات في البحث النفسي ، يمكنك التفكير m
كنتائج من استبيان الشخصية (10 موضوعات ، 20 vars). المتجهات في قائمة فهارس الأعمدة التي تحدد الاستبيان الفرعي (مثل سمات الشخصية). يتم تعريف كل فروع من العناصر العديدة (الأعمدة في data.frame
). إذا افترضنا أن النتيجة على كل فرع فرعي ليست أكثر من sum
(أو بعض الوظائف الأخرى) لقيم الصفوف (النتائج على هذا الجزء من الاستبيان لكل موضوع) ، يمكنك تشغيل:
> dfsub(m, lst, sum)
a b c
1 46 20 24
2 41 24 21
3 41 13 12
4 37 14 18
5 57 18 25
6 27 18 18
7 28 17 20
8 31 18 23
9 38 14 15
10 41 14 22
لقد ألقيت نظرة على هذه الوظيفة ويجب أن أعترف أن هذه الحلقة الصغيرة لا تفسد الرمز على الإطلاق ... ولكن إذا كانت هناك طريقة أسهل/فعالة للقيام بذلك ، من فضلك ، أخبرني!
المحلول
كنت أتبع نهجًا مختلفًا وأبقي كل شيء كأطر بيانات بحيث يمكنك استخدام الدمج و ddply. أعتقد أنك ستجد أن هذا النهج أكثر عمومية قليلاً ، ومن الأسهل التحقق من أن كل خطوة يتم تنفيذها بشكل صحيح.
# Convert everything to long data frames
m$id <- 1:nrow(m)
library(reshape)
obs <- melt(m, id = "id")
obs$variable <- as.numeric(gsub("V", "", obs$variable))
varinfo <- melt(lst)
names(varinfo) <- c("variable", "scale")
# Merge and summarise
obs <- merge(obs, varinfo, by = "variable")
ddply(obs, c("id", "scale"), summarise,
mean = mean(value),
sum = sum(value))
نصائح أخرى
بعد تحميل حزمة PLYR ، استبدل
subs <- list()
for (i in 1:length(lst)) {
# apply function on each part, by row
subs[[i]] <- apply(dt[ , lst[[i]]], 1, fun)
}
مع
subs <- llply(lst,function(x) apply(dt[,x],1,fun))
@هادلي ، لقد راجعت ردك لأنه واضح ومباشر للغاية بالنسبة لمسك الدفاتر (إلى جانب حقيقة أنه أكثر حلًا للأغراض العامة). ومع ذلك ، إليك نصي غير طويل base
الحزمة (وهو تافهة منذ التثبيت plyr
و reshape
فقط بعد تثبيت R). الآن ، هذا المصدر:
dfsub <- function(dt, lst, fun) {
# check whether dt is `data.frame`
stopifnot (is.data.frame(dt))
# convert data.frame factors to numeric
dt <- as.data.frame(lapply(dt, as.numeric))
# check if vectors in lst are "whole" / integer
# vector elements should be column indexes
is.wholenumber <- function(x, tol = .Machine$double.eps^0.5) abs(x - round(x)) < tol
# fall if any non-integers in list
idx <- rapply(lst, is.wholenumber)
stopifnot(idx)
# check for list length
stopifnot(ncol(dt) == length(idx))
# subset the data
subs <- list()
for (i in 1:length(lst)) {
# apply function on each part, by row
subs[[i]] <- apply(dt[ , lst[[i]]], 1, fun)
}
names(subs) <- names(lst)
# convert to data.frame
subs <- as.data.frame(subs)
# guess what =)
return(subs)
}
للحصول على مثالك المحدد ، يوجد حل خط واحد sapply(lst,function(x) rowSums(m[,x]))
(على الرغم من أنك قد تضيف بعض الخطوط الأخرى للتحقق من وجود إدخال صالح ووضعه في أسماء الأعمدة).
هل لديك تطبيقات أخرى أكثر عمومية في الاعتبار؟ أم أن هذه هي حالة من ياجني?