リストでdata.frameのサブセットと行により、各部分に関数を適用
質問
これは典型的な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
のサブセットをしたかったです。これは心理学的研究でデータ操作を伴う関数からのコードの一部ですので、あなたは人格アンケート(10科目、20 VARS)からの結果としてm
を考えることができます。アンケートの下位尺度(例えば、性格特性)を定義リストホールド列インデックスでのベクトル。各下位尺度は、いくつかの項目(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))
@Hadleyは、私はあなたの応答をチェックしましたし、簡単に簿記のために(事実のほかに、それは、より汎用的な-ソリューションです)。しかし、ここの事をして、(私はRをインストールした後base
とplyr
をインストールするので簡単です)のみreshape
パッケージが必要私のそれほど長いスクリプトです。さて、ここでソースがあります:
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)
}
あなたの具体的な例については、1行のソリューションは、(あなたは、列名に有効な入力とプットをチェックするためにいくつかのより多くの行が追加される場合がありますが)sapply(lst,function(x) rowSums(m[,x]))
です。
あなたは心の中で他の、より一般的なアプリケーションを持っていますか?それともこれは YAGNI の?
の場合、おそらくです