1

私は、米国企業の収益に関する月次観測からなるデータセットを持っています。NA以外の観察が一定数未満のすべての企業をサンプルから除外しようとしています。

を使用してやりたいことができましforeachたが、データセットが非常に大きく、これには長い時間がかかります。これは、私が望んでいたことをどのように達成したかを示し、うまくいけば私の目標を明確にする実用的な例です

#load required packages
library(data.table)
library(foreach)

#example data
myseries <- data.table(
 X = sample(letters[1:6],30,replace=TRUE),
 Y = sample(c(NA,1,2,3),30,replace=TRUE))

setkey(myseries,"X") #so X is the company identifier

#here I create another data table with each company identifier and its number 
#of non NA observations
nobsmyseries <- myseries[,list(NOBSnona = length(Y[complete.cases(Y)])),by=X]

# then I select the companies which have less than 3 non NA observations
comps <- nobsmyseries[NOBSnona <3,]

#finally I exclude all companies which are in the list "comps", 
#that is, I exclude companies which have less than 3 non NA observations
#but I do for each of the companies in the list, one by one, 
#and this is what makes it slow.

for (i in 1:dim(comps)[1]){
myseries <- myseries[X != comps$X[i],]
}

どうすればこれをより効率的に行うことができますか? data.table同じ結果を得る方法はありますか?

4

2 に答える 2

2

NA値について検討したい列が複数ある場合は、を使用できますがcomplete.cases(.SD)、単一の列をテストしたい場合は、次のようなものをお勧めします。

naCases <- myseries[,list(totalNA  = sum(!is.na(Y))),by=X]

次に、合計NA値のしきい値を指定して参加できます

例えば

threshold <- 3
myseries[naCases[totalNA > threshold]]

除外したケースを取得するために、参加しないを使用することを選択することもできます

 myseries[!naCases[totalNA > threshold]]

コメントに記載されているように、

myseries[,totalNA  := sum(!is.na(Y)),by=X][totalNA > 3]

ただし、この場合はdata.table全体に対してベクトルスキャンを実行しますが、前のソリューションでは.tableのみのdata.tableに対してベクトルスキャンを実行しましたnrow(unique(myseries[['X']]))

これが単一のベクトルスキャンであることを考えると、それは関係なく効率的です(そして、おそらくバイナリ結合+小さなベクトルスキャンは大きなベクトルスキャンよりも遅いかもしれません)が、どちらの方法でも大きな違いがあるとは思えません。

于 2013-02-27T00:25:39.747 に答える
2

Y の NA の数を X で集計してからサブセット化するのはどうですか?

# Aggregate number of NAs
num_nas <- as.data.table(aggregate(formula=Y~X, data=myseries, FUN=function(x) sum(!is.na(x))))

# Subset
myseries[!X %in% num_nas$X[Y>=3],]
于 2013-02-27T00:32:45.787 に答える