2016-10-31 1 views
1

私はすべてのIDの日付範囲にわたって合計を計算しようとしています。私はこれを行うためのSQL構文について、ここではどこからでも見てきましたが、これはかなり一般的な問題であるはずですが、私はというものを見つけませんでした。正確にはです。例えばthisです。MySQLを使用してデータをいくつかの範囲で効率的に要約します。R

私は次の形式を持つテーブルがある:

ID | start_date | end_date 
---|---|--- 
aaa|2016-10-26 07:00| 2016-12-15 04:00 
aaa|2016-10-26 08:00| 2016-12-15 05:00 
bbb|2016-10-26 07:00| 2016-11-15 03:00 
ccc|2016-10-26 07:00| 2016-10-30 04:00 

この表はIDstart_date PKとして持っていると言えます。 (このテーブルには〜1.5Mのレコードがあります)。このテーブルのすべての行を「ピリオド」と呼ぶことができます。

私はまた、次のようなテーブル内のすべての「作業のタイムスロット」をマークし、カレンダーいる:最後に、私は、消費データを持つテーブルがある

|end_date| 
|-| 
|2016-10-26 07:00| 
|2016-10-26 08:00| 
|2016-10-26 09:00| 
|...| 
|2016-12-26 09:00| 

(この表は、〜800件のレコードを持っている) を以下のようになります。 (このテーブルには〜2.3Mレコードがあります)。私は、結果として取得したい何

|ID|start_date|consumption| 
|-|-|-| 
|aaa|2016-10-27 07:00| 1| 
|aaa|2016-10-27 08:00| 5| 
|aaa|2016-10-27 09:00| 3| 
|bbb|2016-10-27 07:00| 3| 

は次の表です:

|ID|start_date|end_date|consumption_sum| 
|-|-|-|-| 
|aaa|2016-10-26 07:00| 2016-12-15 04:00|14| 
|bbb|2016-10-26 07:00| 2016-11-15 03:00|32| 
|ccc|2016-10-26 07:00| 2016-10-30 04:00|17| 

consumption_sum = SUM(START_DATEとEND_DATEの間営業日のすべての消費データの各IDのための消費)。つまり、各IDの各期間内の消費量の合計が必要です。

今、私は最初の2つのテーブルの間で何らかの種類の結合を行って、すべての「期間」の毎日の展開された行で大きな(大きすぎる)テーブルを取得します。

|ID|start_date|end_date_s| 
|-|-|-| 
|aaa|2016-10-26 07:00| 2016-10-26 07:00| 
|aaa|2016-10-26 07:00| 2016-10-26 08:00| 
|aaa|2016-10-26 07:00| 2016-10-26 09:00| 
|aaa|2016-10-26 07:00| 2016-10-26 10:00| 
|aaa|2016-10-26 07:00| ...| 
|aaa|2016-10-26 07:00| 2016-12-15 04:00| 
|bbb|2016-10-26 07:00| 2016-10-26 07:00| 
|bbb|2016-10-26 07:00| 2016-10-26 08:00| 
|bbb|2016-10-26 07:00| 2016-10-26 09:00| 
|bbb|2016-10-26 07:00| ...| 
|bbb|2016-10-26 07:00| 2016-11-15 03:00| 
|ccc|2016-10-26 07:00| 2016-10-26 07:00| 
|ccc|2016-10-26 07:00| ...| 

、その後、毎日end_date_sの消費量を取得するために三番目に、このテーブルに参加:次のように。

最後に、(ID、開始日)を合計して目的のテーブルを取得します。

私は今までに見つけた最高のfoverlapsという名前のdata.table関数を使ってRでこれをやっています。これは正しく動作します。

悲しいことに、データのサイズによって、最初の2つのテーブルを結合するときに自分のPCがメモリ不足になります。

R(またはMySQL経由で、私は気にしません)がうまくいくかどうか、私は疑問に思っていました。

私は現在使用しているRコードは以下の通り(例データが間違っているが、少なくとも、あなたは、コードを見ることができます):これは確かに答えた場合には、事前(と気の毒に

library(data.table) 
library(magrittr) 

    stocks_periodo <- 
    structure(list(CODIGO_REFERENCIA = c("5293cb5478d6d400f0f555d531f2d63b", 
    "0fe0b44806573de5bde3c200455f5f03", "eb57daacff2abadf0f4551386f3c6678", 
    "2ead409e514f379fec7c94504f79206b", "cd0f1f709ed6631aeaf00881fc43ccad" 
    ), PERIODO_INI = structure(c(1477512000, 1477512000, 1477512000, 
    1477512000, 1477512000), class = c("POSIXct", "POSIXt"), tzone = "Europe/Paris"), 
     PERIODO_FIN = structure(c(1477533600, 1477533600, 1477533600, 
     1477533600, 1477533600), class = c("POSIXct", "POSIXt"), tzone = "Europe/Paris")), class = "data.frame", .Names = c("CODIGO_REFERENCIA", 
    "PERIODO_INI", "PERIODO_FIN"), row.names = c(NA, -5L)) %>% data.table(key="PERIODO_INI,PERIODO_FIN") 


    calendario_n <- 
    structure(list(PERIODO_INI = structure(c(1477512000, 1477515600, 
    1477519200, 1477522800, 1477526400), class = c("POSIXct", "POSIXt" 
    ), tzone = "Europe/Paris"), PERIODO_FIN = structure(c(1477512000, 
    1477515600, 1477519200, 1477522800, 1477526400), class = c("POSIXct", 
    "POSIXt"), tzone = "Europe/Paris")), .Names = c("PERIODO_INI", 
    "PERIODO_FIN"), row.names = c(NA, 5L), class = "data.frame") %>% data.table(key="PERIODO_INI,PERIODO_FIN") 

    consumos <- 
    structure(list(PERIODO = structure(c(1478034000, 1478037600, 
    1478041200, 1478044800, 1478048400), class = c("POSIXct", "POSIXt" 
    ), tzone = ""), CODIGO_REFERENCIA = c("f3bcfd70cc0c3434d96278c0cfee1df4", 
    "f3bcfd70cc0c3434d96278c0cfee1df4", "f3bcfd70cc0c3434d96278c0cfee1df4", 
    "f3bcfd70cc0c3434d96278c0cfee1df4", "f3bcfd70cc0c3434d96278c0cfee1df4" 
    ), DIARIO_CONSUMOS = c(8L, 8L, 8L, 8L, 8L)), class = "data.frame", .Names = c("PERIODO", 
    "CODIGO_REFERENCIA", "DIARIO_CONSUMOS"), row.names = c(NA, -5L 
    )) %>% data.table(key="CODIGO_REFERENCIA,PERIODO") 

    consumos_futuros<- 
    foverlaps(calendario_n, stocks_periodo, nomatch=0L) %>% 
    select(-i.PERIODO_INI, -PERIODO_FIN) %>% 
    rename(PERIODO_FIN= i.PERIODO_FIN) %>% 
    data.table(key="CODIGO_REFERENCIA,PERIODO_INI,PERIODO_FIN") 

    stocks_periodo %<>% 
    data.table(key=c("CODIGO_REFERENCIA", "PERIODO_INI", "PERIODO_FIN")) 

    consumos_futuros <- consumos_futuros[!stocks_periodo] 

    consumos_futuros %<>% 
    rename(PERIODO= PERIODO_FIN) %>% 
    data.table(key="CODIGO_REFERENCIA,PERIODO") %>% 
    merge(consumos) %>% 
    group_by(CODIGO_REFERENCIA, PERIODO_INI) %>% 
    summarize(CONSUMO_TOTAL= sum(DIARIO_CONSUMOS)) %>% 
    data.table 

感謝をどこか別の場所)。

+0

@JasonAizkalnsありがとう、ちょうど私はそれを理解しました。 OPはmagrittrではなくdplyrを指定しており、彼の質問を編集してライブラリステートメントを含める必要があります。 –

+1

[this post](http://stackoverflow.com/q/24480031/2572423)を読んでいますか? – JasonAizkalns

+0

@JasonAizkalnsありがとうございます。はい:私はその投稿にも到達したと思います。私はそこに記述したのと同じ機能を使っていると思う。私はそれ(またはメモリがなくても同じ機能を使用する方法)への代替方法を探しています。 – pchtsp

答えて

1

これが実際に「一般的な」状況を解決するかどうかはわかりませんが、少なくともそれは私の問題を解決しました。

最初の表に示すように、同じIDに対して多くのローリング期間がありました。 これらは、一連のend_dateを生成するための連続したstart_dateのセットに対する固定量の時間(IDに基づいて)を合計することによって構築されました。

なぜ私は早くこのことを考えなかったのですが、zooパッケージにはrollsumrollapplyの機能があります。これはまさに私が望んだことです:所定のサイズのローリング・サム。

したがって、start_dateとend_dateで定義された任意のピリオドを合計する代わりに、IDに応じたsizeパラメータで指定された数の行を合計しました。

の行を持つことに気をつけなければならないのは、消費があったかどうかにかかわらず、すべて作業時間です。

元のコードを編集したままにした例として、合計消費量(STOCK_HORAS)に作業時間を含む新しいテーブルreferenciasを追加しました。

library(data.table) 
library(magrittr) 
library(dplyr) 
library(zoo) 
library(tidyr) 

stocks_periodo <- 
    structure(list(CODIGO_REFERENCIA = c("5293cb5478d6d400f0f555d531f2d63b", 
             "0fe0b44806573de5bde3c200455f5f03", "eb57daacff2abadf0f4551386f3c6678", 
             "2ead409e514f379fec7c94504f79206b", "cd0f1f709ed6631aeaf00881fc43ccad" 
), PERIODO_INI = structure(c(1477512000, 1477512000, 1477512000, 
           1477512000, 1477512000), class = c("POSIXct", "POSIXt"), tzone = "Europe/Paris"), 
    PERIODO_FIN = structure(c(1477533600, 1477533600, 1477533600, 
          1477533600, 1477533600), class = c("POSIXct", "POSIXt"), tzone = "Europe/Paris")), class = "data.frame", .Names = c("CODIGO_REFERENCIA", 
                                       "PERIODO_INI", "PERIODO_FIN"), row.names = c(NA, -5L)) %>% data.table(key="PERIODO_INI,PERIODO_FIN") 


calendario_n <- 
    structure(list(PERIODO_INI = structure(c(1477512000, 1477515600, 
              1477519200, 1477522800, 1477526400), class = c("POSIXct", "POSIXt" 
              ), tzone = "Europe/Paris"), PERIODO_FIN = structure(c(1477512000, 
                           1477515600, 1477519200, 1477522800, 1477526400), class = c("POSIXct", 
                                          "POSIXt"), tzone = "Europe/Paris")), .Names = c("PERIODO_INI", 
                                                      "PERIODO_FIN"), row.names = c(NA, 5L), class = "data.frame") %>% data.table(key="PERIODO_INI,PERIODO_FIN") 

consumos <- 
    structure(list(PERIODO = structure(c(1478034000, 1478037600, 
             1478041200, 1478044800, 1478048400), class = c("POSIXct", "POSIXt" 
             ), tzone = ""), CODIGO_REFERENCIA = c("f3bcfd70cc0c3434d96278c0cfee1df4", 
                      "f3bcfd70cc0c3434d96278c0cfee1df4", "f3bcfd70cc0c3434d96278c0cfee1df4", 
                      "f3bcfd70cc0c3434d96278c0cfee1df4", "f3bcfd70cc0c3434d96278c0cfee1df4" 
             ), DIARIO_CONSUMOS = c(8L, 8L, 8L, 8L, 8L)), class = "data.frame", .Names = c("PERIODO", 
                                "CODIGO_REFERENCIA", "DIARIO_CONSUMOS"), row.names = c(NA, -5L 
                                )) %>% data.table(key="CODIGO_REFERENCIA,PERIODO") 
referencias <- structure(list(CODIGO_REFERENCIA = c("3bed628bf8f6242c28d88200faa7e869", 
                "cb3b6727071ec6659c712c3ec99c873a", "84bf5c06deaa2e42ae7edf6055b490db", 
                "bb10cc5b0c3e127bd2073336365bf0e5", "b8b71160125f95a104e24878ff651e9c", 
                "564169fbe71a04b31bb8e141be3fac66"), STOCK_HORAS = c(14, 14, 
                             14, 18, 18, 14)), .Names = c("CODIGO_REFERENCIA", "STOCK_HORAS" 
                             ), class = c("data.table", "data.frame"), row.names = c(NA, -6L 
                             )) %>% data.table 

calendario_refs <- 
    CJ(PERIODO= calendario_n %>% select(PERIODO=PERIODO_INI) %>% first, 
    CODIGO_REFERENCIA= referencias %>% select(CODIGO_REFERENCIA) %>% first) 

# por alguna razón rollsum va rápido pero no tiene partial =TRUE. Esto hace que 
# valga la pena partir los cálculos en 2 y luego juntarlos. 

rollsum_1 <- 
    calendario_refs %>% 
    merge(consumos, by=c("CODIGO_REFERENCIA", "PERIODO"), all.x=TRUE) %>% 
    merge(referencias, by="CODIGO_REFERENCIA") %>% 
    replace_na(list(DIARIO_CONSUMOS=0)) %>% 
    select(CODIGO_REFERENCIA, PERIODO, STOCK_HORAS, DIARIO_CONSUMOS) %>% 
    arrange(CODIGO_REFERENCIA, PERIODO) %>% 
    group_by(CODIGO_REFERENCIA) %>% 
    # si tenemos menos periodos que la suma móvil: reajustamos a lo máximo 
    mutate(STOCK_HORAS= pmin(STOCK_HORAS, n())) %>% 
    mutate(CONSUMO_TOTAL= rollsum(DIARIO_CONSUMOS, first(STOCK_HORAS), align = "left", fill=NA)) %>% 
    data.table 
関連する問題