سؤال

قد يبدو هذا أمرًا نموذجيًا 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])) (على الرغم من أنك قد تضيف بعض الخطوط الأخرى للتحقق من وجود إدخال صالح ووضعه في أسماء الأعمدة).

هل لديك تطبيقات أخرى أكثر عمومية في الاعتبار؟ أم أن هذه هي حالة من ياجني?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top