2

以下に示すように、データフレーム「m」があります。

メートル

各アカウントの最もアクティブな月 (V1 の数が最も多い月) を見つけようとしています。たとえば、アカウント「2」の場合は「月 6」、アカウント 3 の場合は「月 1」、....

以下のループを書きました。問題なく動作しますが、8000 行しか使用していなくても時間がかかります。データセット全体には 250,000 行あるため、以下のコードは使用できません。これを達成するためのより良い方法を提案できる人はいますか?

どうもありがとう。

コード

4

5 に答える 5

3

plyrを使用してそれを行うことができます

library(plyr)
ddply(m, "AccountID", subset, V1==max(V1))

EDITED:月ごとに結果を取得するには、「id」変数を変更するだけです

library(plyr)
ddply(m, "Month", subset, V1==max(V1))
于 2012-04-15T09:16:32.067 に答える
2

Owe Jessen のコメントは正しいと思いますが、これは問題に対する答えではありません。これが の助けを借りた私のショットですdata.table

まず、もう少し理解しやすい例を使用しましょう。

library(data.table)
DT <- data.table(AccountID = rep(1:3, each=4),
                 V1        = sample(1:100, 12, replace=FALSE),
                 Month     = rep(1:4, times=3))
      AccountID V1 Month
 [1,]         1 81     1
 [2,]         1 23     2
 [3,]         1 72     3
 [4,]         1 36     4
 [5,]         2 22     1
 [6,]         2 13     2
 [7,]         2 50     3
 [8,]         2 40     4
 [9,]         3 74     1
[10,]         3 83     2
[11,]         3  4     3
[12,]         3  3     4

したがって、ここでは 3 つのアカウントと 4 か月があり、すべてのアカウント/月の組み合わせに対して V1 があります。したがって、各アカウントの最大 V1 を見つけるには、次のようにします。

setkey(DT, AccountID)
DT <- DT[, list(maxV1=max(V1)), by="AccountID"][DT]
DT[maxV1==V1]
     AccountID maxV1 V1 Month
[1,]         1    81 81     1
[2,]         2    50 50     3
[3,]         3    83 83     2

これはちょっとわかりにくいので、少し説明してみましょう。AccountID を DT のキーとして設定します。さて、私は基本的に で 2 つのステップを実行しDT[, list(maxV1=max(V1)), by="AccountID"][DT]ます。まず、各アカウント ( ) の最大 V1 値を計算し、その後すぐにDT[, list(maxV1=max(V1)), by="AccountID"]呼び出して、この新しい列を古いに追加します。明らかに、保持するすべての行を取得するだけで済みます。[DT]maxV1DTmaxV1==V1

このソリューションを Nico のより高度な例に適用し、 adata.frameを aに変換する方法を示しdata.tableます。

library(data.table)
DT <- as.data.table(m)
#Note that this line is only necessary if there are more than one rows per Month/AccountID combination
DT <- DT[, sum(V1), by="Month,AccountID"]
setkey(DT, AccountID)
DT <- DT[, list(maxV1=max(V1)), by="AccountID"][DT]
DT[maxV1==V1]
   AccountID maxV1 Month    V1
           1 24660     1 24660
           2 22643     2 22643
           3 23642     3 23642
           4 22766     5 22766
           5 22445    12 22445
...

これにより、正確に 50 行が得られます。

編集:

そして、ここにbase-Rソリューションがあります:

df <- data.frame(AccountID = rep(1:3, each=4),
                 V1        = sample(1:100, 12, replace=FALSE),
                 Month     = rep(1:4, times=3))
df$maxV1 <- ave(df$V1, df$AccountID, FUN = max)
df[df$maxV1==df$V1, ]

ここからインスピレーションを得ました。

于 2012-04-15T11:04:43.043 に答える
1

基本的にこれはTalと同じ解決策だと思います

私は次のループで妥当な時間を得る

# Generate some random data
AccountID <- sample(1:50, 250000, replace=T)
V1 <- sample(1:100, 250000, replace=T)
Month <- sample(1:12, 250000, replace=T)

m <- data.frame(AccountID, V1, Month)

# Aggregate the data by month

ac = as.numeric(levels(as.factor(m$AccountID)))
active.month = rep(NA, length(ac))
names(active.month) = ac

system.time(
{
  for(i in ac)
  {
    subm = subset(m, AccountID == i)
    active.month[i] = subm[which.max(subm[,"V1"]),"Month"]
  }
})
   User      System verstrichen 
   0.78        0.14        0.92 
于 2012-04-15T11:11:02.453 に答える
1

このアルゴリズムをベクトル化する方法がわかりません (他の誰かがそうするなら、その方法を知りたいです)。

これが私がそれをどのようにコーディングするかです(ps:将来的に自己完結型のコードを含めてください。ヘルプについては?dputも見てください):

make.data <- function(n = 100) # 250000
{
# Generate some random data
AccountID <- sample(1:50, n, replace=T)
V1 <- sample(1:100, n, replace=T)
Month <- sample(1:12, n, replace=T)

m <- data.frame(AccountID, V1, Month)
m
}



fo <- function(X)
{
unique_ID <- unique(X$AccountID)
M_max <- numeric(length(unique_ID ))

for(i in seq_along(unique_ID))
{
    ss <- X$AccountID == unique_ID[i]
    M_max [i] <- X[ss,"Month"][which.max(X[ss,"V1"])]
}

# results:
# M_max
data.frame(unique_ID , M_max)
}


X <- make.data(1000000)
system.time(fo(X))
#   user  system elapsed 
#   2.32    0.33    2.70 

これらの関数のいくつかは、あなたが使用したものよりも高速である可能性があると思います (ただし、時間をテストする価値はあります)。

編集: R の新しい JIT が役立つかもしれません (詳細については、こちらを参照してください: Just-In-Time (JIT) コンパイラを使用して R コードを高速化する)

ループを並列化することも価値があるかもしれません (ただし、ここでは説明しません)。

タイミングが現実的でない場合は、data.table パッケージを使用してそれを実行するか (ただし、私はそれを使用した経験がありません)、SQL を使用して実行することさえあるかもしれません...

幸運を祈ります、タル

更新:私はニコの例を使用し、ソリューションを関数でラップしました。タイミングはまったく問題ありません。より高度なソリューションは必要ありません...

于 2012-04-15T08:13:56.400 に答える
1

これは、250000行を使用する私のラップトップではほとんど瞬時です(さらに、はるかにクリーンです)

# Generate some random data
AccountID <- sample(1:50, 250000, replace=T)
V1 <- sample(1:100, 250000, replace=T)
Month <- sample(1:12, 250000, replace=T)

m <- data.frame(AccountID, V1, Month)

# Aggregate the data by month
V1.per.month <- aggregate(m$V1, sum, by=list(Month = m$Month))

編集:質問を読み直して、アカウントを考慮するのを忘れていたことに気づきました(しゃれた意図)

ただし、これは行う必要があります

V1.per.month <- aggregate(m$V1, sum, 
             by=list(Month = m$Month, Account= m$AccountID))

タイミング グラフ (エラー バーは SD)。ご覧のとおり、100 万行あたり約 2.5 秒かかりますが、これは非常に許容範囲だと思います。

行数あたりの経過時間

于 2012-04-15T08:15:41.797 に答える