以下に示すように、データフレーム「m」があります。
各アカウントの最もアクティブな月 (V1 の数が最も多い月) を見つけようとしています。たとえば、アカウント「2」の場合は「月 6」、アカウント 3 の場合は「月 1」、....
以下のループを書きました。問題なく動作しますが、8000 行しか使用していなくても時間がかかります。データセット全体には 250,000 行あるため、以下のコードは使用できません。これを達成するためのより良い方法を提案できる人はいますか?
どうもありがとう。
以下に示すように、データフレーム「m」があります。
各アカウントの最もアクティブな月 (V1 の数が最も多い月) を見つけようとしています。たとえば、アカウント「2」の場合は「月 6」、アカウント 3 の場合は「月 1」、....
以下のループを書きました。問題なく動作しますが、8000 行しか使用していなくても時間がかかります。データセット全体には 250,000 行あるため、以下のコードは使用できません。これを達成するためのより良い方法を提案できる人はいますか?
どうもありがとう。
plyrを使用してそれを行うことができます
library(plyr)
ddply(m, "AccountID", subset, V1==max(V1))
EDITED:月ごとに結果を取得するには、「id」変数を変更するだけです
library(plyr)
ddply(m, "Month", subset, V1==max(V1))
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]
maxV1
DT
maxV1==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, ]
ここからインスピレーションを得ました。
基本的にこれは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
このアルゴリズムをベクトル化する方法がわかりません (他の誰かがそうするなら、その方法を知りたいです)。
これが私がそれをどのようにコーディングするかです(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 を使用して実行することさえあるかもしれません...
幸運を祈ります、タル
更新:私はニコの例を使用し、ソリューションを関数でラップしました。タイミングはまったく問題ありません。より高度なソリューションは必要ありません...
これは、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 秒かかりますが、これは非常に許容範囲だと思います。