0

そのため、データセットの年間顧客 ID ごとの最大、2 番目の最大、および 3 番目の最大水使用量を見つけようとしています。私は R と sqldf ライブラリを使用していますが、これに対する R ソリューションを受け入れることができます。サンプルデータの一部を次に示します。

 Year  | ID | Month  | Use |
----------------------------
2009    101 1   103

2009    101 2   209

2009    101 3   375

2009    101 4   360

2010    101 1   170

2010    101 2   381

2010    101 3   275

2010    101 4   260

2009    102 1   263

2009    102 2   234

2009    102 3   45

2009    102 4   275

2010    102 1   469

2010    102 2   107

2010    102 3   354

2010    102 4   436

理想的には、列、、(またはそれぞれ 2 番目の最大値または 3 番目の最大値) を持つ 3 つの行列max1、を返したいと思います。max2max3IDYearMaxmax1 = [101, 2009, 375, 101, 2010, 381, 102, 2009, 275, 102, 2010, 469]

私の最初のアプローチは、次のように、 andのドメインとしてlistofIDsandを入れ子にした for ループを作成することでした。listofYearsIDYear

for i in 1:length(listofIDs){

for y in 1:length(listofYears){

monthlylist<-sqldf("select Month, Use from Dataframe where ID=listofIDs[i] and Year=listofYears[y]")

そしてmonthlylist、最大値などを並べ替えて引き出します。ただし、sqldfそのような変数は読み取れないため、毎回明示的に where ID = 101、 whereを指定する必要があります。ID = 102

sqldf に変数を認識させる方法、または年と ID で集計された最大値、2 番目の最大値、3 番目の最大値を見つけるより良い方法についてのアイデアはありますか? 私は大きなデータセットを扱っているので、理想的には永遠にかからないものです。

4

2 に答える 2

2

次のコードは、3 つのデータ フレームのリストを作成します (datは元のデータ フレームです)。

lapply(seq(3), function(x)
  aggregate(Use ~ Year + ID, dat, function(y)
    y[order(-y)][x]))

結果:

[[1]]
  Year  ID Use
1 2009 101 375
2 2010 101 381
3 2009 102 275
4 2010 102 469

[[2]]
  Year  ID Use
1 2009 101 360
2 2010 101 275
3 2009 102 263
4 2010 102 436

[[3]]
  Year  ID Use
1 2009 101 209
2 2010 101 260
3 2009 102 234
4 2010 102 354

仕組み

この関数lapplyは、別の関数を複数回適用するために使用されます。このコマンドseq(3)は、1 から 3 までの数値のベクトルを生成します。パラメーターxは、これらの数値の 1 つを表します。この関数は、および でグループ化された値にaggregate別の関数を適用するために使用されます。パラメータは、 1 つのグループ内の値を表します。このコマンドは、値を降順に並べ替えます。その後、を使用して、この順序付けられたベクトルの 1 番目、2 番目、3 番目の要素をそれぞれ抽出します。UseYearIDyUsey[order(-y)]Use[x]

于 2013-11-19T22:01:00.257 に答える
1

最初に、簡単に再現可能な形式でテスト データを設定します。

# set up test data

Lines <- "Year ID Month Use
2009 101 1 103
2009 101 2 209
2009 101 3 375
2009 101 4 360
2010 101 1 170
2010 101 2 381
2010 101 3 275
2010 101 4 260
2009 102 1 263
2009 102 2 234
2009 102 3 45
2009 102 4 275
2010 102 1 469
2010 102 2 107
2010 102 3 354
2010 102 4 436
"
DF <- read.table(text = Lines, header = TRUE)

ここに入力データがあるので、いくつかのアプローチがあります。

1) sqldf/SQLite次の 3 つの SQL ステートメントは、これらの量を計算する必要があります。実行が遅すぎる場合は、年、ID インデックスを追加してみてください。from3 つの SQL ステートメントは、句を除いて同じであることに注意してください。

次に、3 つのデータ フレームを作成します。

library(sqldf)

max1 <- sqldf("select Year, ID, max(Use) Use 
   from DF 
   group by Year, ID") 

max2 <- sqldf("select Year, ID, max(Use) Use 
   from (select Year, ID, Use from DF 
         except select * from max1) 
   group by Year, ID")

max3 <- sqldf("select Year, ID, max(Use) Use 
   from (select Year, ID, Use from DF 
         except select * from max1 
         except select * from max2) 
   group by Year, ID")

2) sqldf/PostgreSQLrank()上記は sqlite を使用した sqldf の場合ですが、PostgreSQL のウィンドウ機能を使用できるため、sqldf と PostgreSQL を使用するとさらに簡単になります。(sqldf で PostgreSQL を使用する方法の詳細については、こちらを参照してください。)

library(RPostgreSQL)
library(sqldf)

DF2 <- sqldf('select *, rank() over (partition by "Year", "ID" order by "Use" desc) 
              from "DF"')
split(DF2[1:4], DF2$rank)[1:3]

最後の行は、次のように置き換えることもできます。

lapply(1:3, function(r) subset(DF2, rank == r)[1:4])

純粋な SQL ソリューションが必要な場合:

max1 <- sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = 1')
max2 <- sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = 2')
max3 <- sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = 3') 

またはデータフレームのリストを作成するには:

lapply(1:3, function(r) 
   fn$sqldf('select "Year", "ID", "Month", "Use" from "DF2" where "rank" = $r'))

3) aveストレート R でこれを行うのはそれほど難しいことではありません。ここでは、ランク 1 が最大で、ランク 2 が 2 番目に大きいなどです。したがってRank、前のソリューションのように分割して、最初の 3 つのコンポーネントを取得します。

Rank <- with(DF, ave(-Use, Year, ID, FUN = rank))
split(DF, Rank)[1:3]

これは、最後の行の代わりにも機能します。

lapply(1:3, function(r) subset(DF, Rank == r))

これは、コンポーネントが 3 つのデータ フレームであるリストを返します。

更新: 2 番目の解決策も書きました。

于 2013-11-19T22:33:47.977 に答える