2017-03-28 19 views
0

現在、Rのトリプルループを実行して曜日の異常のしきい値を作成しているため、計算時間に問題があります。一意のIDごとに1時間のレベルです。Rのループを回避する方法[トリプルループ別名トリプル脅威]

私の元のデータフレーム:など ユニークID、イベント日時、イベント日付、週のイベント日、イベント時間、数値変数1、数値変数2、

df <- read.csv("mm.csv",header=TRUE,sep=",") 

for (i in unique(df$customer_id)) { 
    #I initialize the output data frame so I can rbind as I loop though the grains. This data frame is always emptied out once we move onto our next customer_id 
    output.final.df <- data_frame(seller_name = factor(), is_anomaly_date = integer(), event_date_hr = double(), event_day_of_wk = integer(), event_day = double(), ...) 

    for (k in unique(df$event_day_of_wk)) { 
    for (z in unique(df$event_hr)) { 
     merchant.df = df[df$merchant_customer_id==i & df$event_day_of_wk==k & df$event_hr==z,10:19] #columns 10:19 are the 9 different numeric variables I am creating anomaly thresholds 

     #1st anomaly threshold - I have multiple different anomaly thresholds 

     # TRANSFORM VARIABLES - sometime within the for loop I run another loop that transforms the subset of data within it. 
     for(j in names(merchant.df)){ 
     merchant.df[[paste(j,"_log")]] <- log(merchant.df[[j]]+1) 
     #merchant.df[[paste(j,"_scale")]] <- scale(merchant.df[[j]]) 
     #merchant.df[[paste(j,"_cube")]] <- merchant.df[[j]]**3 
     #merchant.df[[paste(j,"_cos")]] <- cos(merchant.df[[j]]) 
     } 

     mu_vector  = apply(merchant.df, 2, mean) 
     sigma_matrix  = cov(merchant.df, use="complete.obs", method='pearson') 
     inv_sigma_matrix = ginv(sigma_matrix) 
     det_sigma_matrix = det(sigma_matrix) 

     z_probas = apply(merchant.df, 1, mv_gaussian, mu_vector, det_sigma_matrix, inv_sigma_matrix) 
     eps = quantile(z_probas,0.01) 
     mv_outliers = ifelse(z_probas<eps, TRUE, FALSE) 

     #2nd anomaly threshold 
     nov = ncol(merchant.df) 
     pca_result <- PCA(merchant.df,graph = F, ncp = nov, scale.unit = T) 
     pca.var <- pca_result$eig[['cumulative percentage of variance']]/100 
     lambda <- pca_result$eig[, 'eigenvalue'] 
     anomaly_score = (as.matrix(pca_result$ind$coord)^2) %*% (1/as.matrix(lambda, ncol = 1)) 
     significance <- c (0.99) 
     thresh = qchisq(significance, nov) 
     pca_outliers = ifelse(anomaly_score > thresh , TRUE, FALSE) 

     #This is where I bind the anomaly points with the original data frame and then I row bind to the final output data frame then the code goes back to the top and loops through the next hour and then day of the week. Temp.output.df is constantly remade and output.df is slowly growing bigger. 
     temp.output.df <- cbind(merchant.df, mv_outliers, pca_outliers) 
     output.df <- rbind(output.df, temp.output.df) 
    } 
    } 
    #Again this is where I write the output for a particular unique_ID then output.df is recreated at the top for the next unique_ID 
    write.csv(output.df,row.names=FALSE) 
    } 

次のコードが表示さ私がやっていることのアイデア。あなたが見ることができるように、3つのforループを実行して、曜日ごとに時間レベルである最も低いグレインで複数の異常検出を計算した後、すべてのunique customer_idレベルをcsvに出力します。

全体的にコードは非常に高速です。しかし、トリプル・フォー・ループをすることは私のパフォーマンスを殺している。誰も私の元のデータフレームを与えられ、すべてのunique_idレベルでcsvを出力する必要があるこのような操作を行うことができる他の方法を知っていますか?

+4

を参照してください。特に、 'i'、' k'、 'z'のどれもあなたのループの中で書かれているように使用されていません。 [mcve]を入力してください。 http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-exampleも参照してください。 – dash2

+0

素早い返信をありがとう、私は最も重要な行を忘れてしまった。 @df $ merchant_customer_id == i&df $ event_day_of_wk == k&df $ event_hr == z、10:19] #columns 10:19は、異常しきい値を作成する9種類の数値変数です 私はi、k、zを使ってメインdfをサブセット化し、その特定の一意のID、曜日、時間のデータを取得します。そして、そのレベルで私はすべての計算を行います。 –

+0

私はgroupBy(aggregate)のようなものをお勧めします。 – dk14

答えて

1
  • トリプルループを使用しないでください。 dplyr::group_by(customer_id, event_day_of_wk, event_hr)またはdata.table相当品を使用してください。どちらも速くなければなりません。
  • rbindcbindですべての繰り返しで明示的に追加する必要はなく、パフォーマンスが低下します。
  • また、cbind()あなたの出力dfにあなたの入力dfを入力する必要はありません。唯一の実際の出力はmv_outliers, pca_outliersです。あなたはグループの外側のレベルに行くために必要のある、write.csv()にし、それらを各customer_idためのすべての結果を照合したいために、そして内側のレベルでgroup_by(event_day_of_wk, event_hr):あなたは後でcustomer_id, event_day_of_wk, event_hr
  • EDIT上の入力と出力のDFSをjoin()ことができます。

# Here is pseudocode, you can figure out the rest, do things incrementally 
# It looks like seller_name, is_anomaly_date, event_date_hr, event_day_of_wk, event_day,... are variables from your input 

require(dplyr) 

output.df <- df %>% 
    group_by(customer_id) %>% 
    group_by(event_day_of_wk, event_hr) %>% 

    # columns 10:19 ('foo','bar','baz'...) are the 9 different numeric variables I am creating anomaly thresholds 
    # Either a) you can hardcode their names in mutate(), summarize() calls 
    # or b) you can reference the vars by string in mutate_(), summarize_() calls 

    # TRANSFORM VARIABLES 
    mutate(foo_log = log1p(foo), bar_log = log1p(bar), ...) %>% 

    mutate(mu_vector = c(mean(foo_log), mean(bar_log)...)) %>% 
    # compute sigma_matrix, inv_sigma_matrix, det_sigma_matrix ... 

    summarize(
     z_probas=mv_gaussian(mu_vector, det_sigma_matrix, inv_sigma_matrix), 
     eps = quantile(z_probas,0.01), 
     mv_outliers = (z_probas<eps) 
    ) %>% 

    # similarly, use mutate() and do.call() for your PCA invocation... 

    # Your outputs are mv_outliers, pca_outliers 
    # You don't necessarily need to `cbind(merchant.df, mv_outliers, pca_outliers)` i.e. cbind all your input data together with your output 

    # Now remove all your temporary variables from your output: 
    select(-foo_log, -bar_log, ...) %>% 
    # or else just select(mv_outliers, pca_outliers) the variables you want to keep 

    ungroup() %>% # (this ends the group_by(event_day_of_wk, event_hr) and cbinds all the intermediate dataframes for you) 

    write.csv(c(.$mv_outliers, .$pca_outliers), file='<this_customer_id>.csv') 

ungroup() # group_by(customer_id) 

それはそれを最適化する方法を知っているのは難しい、あなたの実際のコードを見ずにも"write.csv() in dplyr chain"

+0

dplyr:group_byはforループ内で何をしていますか?たとえば、私は可変変換やその他の関数を実行します。 –

+0

@WayneLee:yes 'dplyr'は上記のコード内のすべてを処理できます。 'dplyr :: mutate()、summarize()'のドキュメントを参照してください。 (それで 'data.table'もできます) – smci

関連する問題