4

R でデータフレーム original.data をフィルタリングしたいと考えています。データフレームにはいくつかのフィールドがあり、名前は異なる場合があります。ユーザーは、フィルター処理するフィールドを選択できます。これらのフィールド名は、names(all.filters) に格納されます。ここで、all.filters は可変長のリストです。ユーザーは、names(all.filters) の各フィールドのレベルを選択できます。たとえば、このリストは次のようになります。

> all.filters
$Period
[1] "2010-12-31" "2011-03-31" "2011-06-30" "2011-09-30" "2011-12-31"
[6] "2012-03-31" "2012-06-30" "2012-09-30"

$Size
[1] "L"  "VL"

$Number
[1] "11" "21" "35" "42" "45" "47" "49" "52" "57"

次のコードを使用して、選択したフィルターを適用しています。

attach(original.data)    
filter.names <- names(all.filters)
flag <- 1
for(filter in filter.names){
   flag <- flag*(is.element(get(filter),all.filters[[filter]]))
}
filtered.data <- original.data[flag==1,]

これは機能しますが、少し遅く感じます。get(filter) は、列名が filter と等しい original.data の列を取得することに注意してください。これがデータをフィルタリングする良い方法かどうかはわかりませんが、all.filters の変数の性質により選択肢が少し制限されます。サブセットを使用したかったのですが、select 引数として何を指定すればよいかわかりません。ユーザーがフィルターの選択を更新したときにデータをすばやくプロットできるように、このフィルタリング手順をできるだけ速くしたいと思います。

データがフィルタリングされたら、ggplot2 でプロットする前に、reshape2 を使用してデータを要約します。可能であれば、これらのステップのいずれかでフィルターを適用する方が効率的かもしれないと考えています。

どんな提案でも大歓迎です。

4

3 に答える 3

2

data.table適切に設定されたキーで を使用できます。これにより、メモリ効率が向上します。

list次に、 of フィルターをのiコンポーネントに渡すことができます[.data.table

.period <- seq(from = as.Date("2010/1/1", "%Y/%m/%d"), to = as.Date("2012/1/1", 
    "%Y/%m/%d"), by = "3 months")
.size <- c("XS", "S", "M", "L", "XL")
.number <- as.character(1:100)
DF <- expand.grid(Period = .period, Size = .size, Number = .number, stringsAsFactors = F)

DF$other <- rnorm(nrow(DF))

library(data.table)

DT <- as.data.table(DF)

DT[, `:=`(Period, as.IDate(.period))]


##           Period Size Number    other
##    1: 2010-01-01   XS      1  0.17947
##    2: 2010-04-01   XS      1  1.43252
##    3: 2010-07-01   XS      1 -0.97142
##    4: 2010-10-01   XS      1 -0.98021
##    5: 2011-01-01   XS      1 -0.62964
##   ---                                
## 4496: 2011-01-01   XL    100  0.65831
## 4497: 2011-04-01   XL    100 -0.45277
## 4498: 2011-07-01   XL    100 -0.14236
## 4499: 2011-10-01   XL    100 -0.02376
## 4500: 2012-01-01   XL    100 -0.11525

all_filters <- list(Period = as.IDate(as.Date("2010/1/1", format = "%Y/%m/%d")), 
    Size = "L", Number = c("11", "21", "35", "42", "45", "47", "49", "52", "57"))


setkeyv(DT, names(all_filters))

DT[all_filters]

##        Period Size Number   other
## 1: 2010-01-01    L     11  1.4122
## 2: 2010-01-01    L     21 -0.4923
## 3: 2010-01-01    L     35  1.1262
## 4: 2010-01-01    L     42  1.3527
## 5: 2010-01-01    L     45 -0.3758
## 6: 2010-01-01    L     47 -0.1847
## 7: 2010-01-01    L     49 -0.8503
## 8: 2010-01-01    L     52 -1.0645
## 9: 2010-01-01    L     57 -0.6092

私が見ることができる唯一の問題は、正しい列を参照していることを確認するために毎回キーをリセットする必要があることです. また、フィルター識別子が data.frame の列と同じクラスであることを確認する必要があります。列ではなく、作業する方が簡単な場合がありますcharacterfactor

編集

複数の列で複数のレベルでフィルタリングするには、 を使用しますCJ。CJ はクロス結合です (キーが設定された、expand.grid に相当する data.table)。

all_filters <- list(Period = as.IDate(as.Date("2010/1/1", format = "%Y/%m/%d")), 
  Size = c("L",'XL'), Number = c("11", "21", "35", "42", "45", "47", "49", "52", "57"))




cj_filter <- do.call(CJ, all_filters)

# note you could avoid this `do.call` line by
# cj_filter <- CJ(Period = as.IDate(as.Date("2010/1/1", format = "%Y/%m/%d")), 
  Size = c("L",'XL'), Number = c("11", "21", "35", "42", "45", "47", "49", "52", "57"))

setkeyv(DT, names(cj_filter))

DT[cj_filter]
       Period Size Number       other
 1: 2010-01-01    L     11  0.36289104
 2: 2010-01-01    L     21  1.26356767
 3: 2010-01-01    L     35 -0.18629723
 4: 2010-01-01    L     42  0.92267902
 5: 2010-01-01    L     45  1.68796072
 6: 2010-01-01    L     47  1.75107447
 7: 2010-01-01    L     49  0.24048407
 8: 2010-01-01    L     52  0.06675221
 9: 2010-01-01    L     57  0.49665392
10: 2010-01-01   XL     11  0.33682495
11: 2010-01-01   XL     21  0.67642271
12: 2010-01-01   XL     35 -0.16412768
13: 2010-01-01   XL     42  0.72863394
14: 2010-01-01   XL     45 -0.55527588
15: 2010-01-01   XL     47  1.30850591
16: 2010-01-01   XL     49  1.08688166
17: 2010-01-01   XL     52 -0.31157250
18: 2010-01-01   XL     57  0.43626422

あなたもできる

 setkeyv(DT, names(all_filters))

 DT[do.call(CJ,all_filters)]
于 2012-10-24T23:33:57.497 に答える
1

フィールド名のハードコーディングに依存しない、もう少し一般的なアプローチ: あなたdata.frameとあなたのフィルターが同じ列/フィールドを同じ順序で持っていると仮定します:

foo <- data.frame(Period=sample(x=c("2010-12-31","2011-01-01"),size=100,replace=TRUE),
    Size=sample(x=c("S","L","VL"),size=100,replace=TRUE),
    Number=sample(x=c("9","11","21"),size=100,replace=TRUE))

all.filters <- list(
    Period=c("2010-12-31","2011-03-31"),
    Size=c("L","VL"),
    Number=c("11","21","35"))

次に、最初のフィルタ エントリに対して%in%最初の列に適用しfoo、2 番目のエントリに対して 2 番目の列に適用する必要があります。

bar <- mapply(FUN='%in%',foo,all.filters)

foo最後に、すべてのフィルターが一致する行を抽出します。

foo[apply(bar,1,all),]
于 2012-10-24T22:38:28.623 に答える
0

フィルタ オプションのいずれかに一致するデータが必要ですか? そう"L""VL"、例えば期間問わず?

その場合は、次のようにします。

Filtered.Data <- subset(original.data, Period %in% all.filters$Period | 
            Size %in% all.filters$Size | Number %in% all.filters$Number)

それほど時間はかかりません。これらすべての値に一致するデータが必要な場合は|&明らかにに置き換えます。フィルタ カテゴリが多数ある場合は、forループを実行できますrbind

于 2012-10-24T22:30:25.053 に答える