2016-03-28 6 views
0

私はパンダに2列、QuarterHourDimIDStartDateDimIDのテーブルを持っています。これらの列は私に日付と時間のペアごとのIDを与えます。たとえば、2015年1月1日の午後12時15分には、StartDateDimID1097に等しく、QuarterHourDimID26に等しくなります。これは、私が読んでいるデータがどのように整理されているかです。パンダは大きなデータセットに速度を適用します。

pyodbcpandas.read_sql()、〜450M行と〜60列を使用して読んでいる大きなテーブルです。パフォーマンスが問題です。追加の列datetimeを作成するために、私はすべての行に適用する機能を実行している実行可能datetimeインデックスにQuarterHourDimIDStartDateDimID列を解析する

追加の解析を行わずにテーブルを読み取るコードは約800msです。しかし、この適用関数を実行すると、合計実行時間が約4秒増える(問合せが予想される5.8〜6秒の間)。返されるdfは約45K行と5列(〜450日*〜100時間)

私が書いたものをより効率的に書き換えて、途中で入力を得ることを望んでいます。以下は

私がこれまでに書いたコードです:

import pandas as pd 
from datetime import datetime, timedelta 
import pyodbc 

def table(network, demo): 
    connection_string = "DRIVER={SQL Server};SERVER=OURSERVER;DATABASE=DB" 
    sql = """SELECT [ID],[StartDateDimID],[DemographicGroupDimID],[QuarterHourDimID],[Impression] FROM TABLE_NAME 
     WHERE (MarketDimID = 1 
     AND RecordTypeDimID = 2 
     AND EstimateTypeDimID = 1 
     AND DailyOrWeeklyDimID = 1 
     AND RecordSequenceCodeDimID = 5 
     AND ViewingTypeDimID = 4 
     AND NetworkDimID = {} 
     AND DemographicGroupDimID = {} 
     AND QuarterHourDimID IS NOT NULL)""".format(network, demo) 

    with pyodbc.connect(connection_string) as cnxn: 
     df = pd.read_sql(sql=sql, con=cnxn, index_col=None) 


    def time_map(quarter_hour, date): 
     if quarter_hour > 72: 
      return date + timedelta(minutes=(quarter_hour % 73)*15) 
     return date + timedelta(hours=6, minutes=(quarter_hour-1)*15) 

    map_date = {} 

    init_date = datetime(year=2012, month=1, day=1) 

    for x in df.StartDateDimID.unique(): 
     map_date[x] = init_date + timedelta(days=int(x)-1) 

    #this is the part of my code that is likely bogging things down 
    df['datetime'] = df.apply(lambda row: time_map(int(row['QuarterHourDimID']), 
                map_date[row['StartDateDimID']]), 
                axis=1) 
    if network == 1278: 
     df = df.loc[df.groupby('datetime')['Impression'].idxmin()] 

    df = df.set_index(['datetime']) 

    return df 
+1

... WHEN ... THEN ... ELSE' - はるかに速くなるはずです – MaxU

+0

ありがとうございました。これは間違いなくトリックでした。パフォーマンスが大幅に向上しました。 – mburke05

答えて

0

ただ、上記を使用して、日付時刻SQLで実行される変換ではなく、パンダと時間モックアップの例を投稿しますコードを実行し、6.4秒/実行の平均時間を得て、私は完全にSQLでコードを書き直すことができ、640ms /実行の平均時間を得た。

更新されたコード:私はSQL Serverの `DATEADD()`関数と `CASEを使用してSQL Server側で仮想列を追加しようと

import pandas as pd 
import pyodbc 

SQL_QUERY =""" 
SELECT [Impressions] = MIN(naf.Impression), [datetime] = DATEADD(minute,td.Minute,DATEADD(hour,td.Hour,CONVERT(smalldatetime, ddt.DateKey))) 
FROM [dbo].[NielsenAnalyticsFact] AS naf 
LEFT JOIN [dbo].[DateDim] AS ddt 
ON naf.StartDateDimID = ddt.DateDimID 
LEFT JOIN [dbo].[TimeDim] as td 
ON naf.QuarterHourDimID = td.TimeDimID 
WHERE (naf.NielsenMarketDimID = 1 
    AND naf.RecordTypeDimID = 2 
    AND naf.AudienceEstimateTypeDimID = 1 
    AND naf.DailyOrWeeklyDimID = 1 
    AND naf.RecordSequenceCodeDimID = 5 
    AND naf.ViewingTypeDimID = 4 
    AND naf.NetworkDimID = 1278 
    AND naf.DemographicGroupDimID = 3 
    AND naf.QuarterHourDimID IS NOT NULL) 
GROUP BY DATEADD(minute,td.Minute,DATEADD(hour,td.Hour,CONVERT(smalldatetime, ddt.DateKey))) 
ORDER BY DATEADD(minute,td.Minute,DATEADD(hour,td.Hour,CONVERT(smalldatetime, ddt.DateKey))) ASC 
""" 

%%timeit -n200 
with pyodbc.connect(DB_CREDENTIALS) as cnxn: 
    df = pd.read_sql(sql=SQL_QUERY, 
      con=cnxn, 
      index_col=None) 
200 loops, best of 3: 613 ms per loop 
関連する問題