將Numpy datetime64類型日期進行格式轉換
今天使用tushare獲取個股的bar數據時,遇到這樣一個問題。獲取數據寫入MySQL後,表裡面date欄位顯示帶有"00:00:00"格式,而且欄位類型為datetime,如下圖所示。
這或許沒有什麼問題,但和我預期的結果有差異,我預期date欄位的數據類型是date,不希望它是datetime。並且,我不想date欄位的值裡面帶有"00:00:00"這些內容。
排查原因,最後發現是tushare包裡面bar函數,獲取到數據後,通過Pandas.to_datetime函數,將日期欄位轉換為帶"00:00:00"格式的日期值。
見trading.py程序裡面第861行,如下所示。
data[datetime] = pd.to_datetime(data[datetime])
起初想直接修改這行代碼,讓它不返回帶"00:00:00"格式的數據,有點遺憾,試過幾個方法,都沒能成功。在數據源頭下手,其實是最好的方法,但目前功力不夠,只能採用其它方法。
生成bar數據的原始代碼如下。
def store_bar(code, start_date=None, end_date=None): """ store_bar:獲取指定個股成交明細數據 """ df_bar = bar(code, start_date=start_date, end_date=end_date) df_bar = df_bar.loc[:,[ code, open, close, high, low, vol, amount, tor, vr, ma5, ma10, ma20, ma60 ]] # 將DataFrame的index轉換成列date df_bar[date] = df_bar.index # 設置索引值 df_bar = df_bar.set_index([date,code], drop=True, verify_integrity=True) dict_bar ={ code: VARCHAR(df_bar.index. get_level_values(code).str.len().max()) } write_records_into_mysql(df_bar, bar, dtype=dict_bar)#---------------------------------------------------------- #--------------- 存儲bar數據到資料庫 ----------------------- #---------------------------------------------------------- if __name__ == __main__: print "PGM begin" store_bar(300223) print "PGM end"
其它方法,就只能是,生成帶"00:00:00"格式的數據後,將其進行類型轉換或數據拆分。
方法一,進行類型轉換。
我們知道資料庫裡面"2018-04-04 00:00:00"這種格式的數據,屬於Numpy的datetime64類型。因此我們的思路是先將其轉換為Python自帶的datetime類型,然後提取YY-MM-DD部分。以下是採取方法一後的程序代碼。
def store_bar(code, start_date=None, end_date=None): """ store_bar:獲取指定個股成交明細數據 """ df_bar = bar(code, start_date=start_date, end_date=end_date) df_bar = df_bar.loc[:,[ code, open, close, high, low, vol, amount, tor, vr, ma5, ma10, ma20, ma60 ]] # 將DataFrame的index轉換成列date df_bar[date] = df_bar.index """ to_pydatetime函數將DatetimeIndex類型轉換為array類型,把DataFrame的dtype從 datetime64轉換為了object,然後使用apply函數只獲取%Y-%m-%d格式,即將index欄位 裡面的時間參數去掉了。 轉換前: DatetimeIndex([2018-04-04, 2018-04-03, 2018-04-02, 2018-03-30, 2018-03-29, 2018-03-28, 2018-03-27, 2018-03-26, 2018-03-23, 2018-03-22, ... 2011-06-14, 2011-06-13, 2011-06-10, 2011-06-09, 2011-06-08, 2011-06-07, 2011-06-03, 2011-06-02, 2011-06-01, 2011-05-31], dtype=datetime64[ns], name=udatetime, length=1441, freq=None) 轉換後: array([datetime.datetime(2018, 4, 4, 0, 0), datetime.datetime(2018, 4, 3, 0, 0), datetime.datetime(2018, 4, 2, 0, 0), ..., datetime.datetime(2011, 6, 2, 0, 0), datetime.datetime(2011, 6, 1, 0, 0), datetime.datetime(2011, 5, 31, 0, 0)], dtype=object) 參考: https://blog.csdn.net/dm_vincent/article/details/48696857 """ # 第一種方法,將Numpy的datetime64類型先轉換為Python裡面的datetime類型, # 再使用函數進行格式化,只提取我們需要的YY:MM:DD部分 df_bar[date] = df_bar.index.to_pydatetime() # 提取YY-MM-DD部分 df_bar[date] = df_bar[date].apply(lambda x: x.strftime(%Y-%m-%d)) df_bar = df_bar.set_index([date,code], drop=True, verify_integrity=True) dict_bar ={ # 方法一,需要添加date欄位 # 將date欄位轉換為str類型後,必須指定其長度,否則報1170錯誤,轉換後date欄位 # 變成一個VARCHAR類型,不再是date類型 date:VARCHAR(df_bar.index. get_level_values(date).str.len().max()), code: VARCHAR(df_bar.index. get_level_values(code).str.len().max()) } write_records_into_mysql(df_bar, bar, dtype=dict_bar)#---------------------------------------------------------- #--------------- 存儲bar數據到資料庫 ----------------------- #---------------------------------------------------------- if __name__ == __main__: print "PGM begin" store_bar(300223) print "PGM end"
採用這種方法,能夠解決問題,但生成出來的數據如下圖所示,date欄位它的類型變成了VARCHAR。並且,對DataFrame的index使用to_pydatetime進行類型轉換,以及將date轉換為VARCHAR類型,兩步操作都挺影響性能。
方法二,進行數據拆分。
將Numpy的datetime64拆分為兩個列date和time,date欄位存放日期,time欄位存放時間。以下是採取方法二後的程序代碼。
def store_bar(code, start_date=None, end_date=None): """ store_bar:獲取指定個股成交明細數據 """ df_bar = bar(code, start_date=start_date, end_date=end_date) df_bar = df_bar.loc[:,[ code, open, close, high, low, vol, amount, tor, vr, ma5, ma10, ma20, ma60 ]] # 將DataFrame的index轉換成列date df_bar[date] = df_bar.index # 第二種方法,使用split將Numpy的datetime64類型拆分為date和time兩個欄位,這樣存入MySQL裡面的 # HH:MM:SS就會剝離到time欄位了 df_bar[[date,time]] = df_bar[date].apply( lambda x: pd.Series([i for i in str(x).split(" ")])) df_bar = df_bar.set_index([date,code], drop=True, verify_integrity=True) dict_bar ={ code: VARCHAR(df_bar.index. get_level_values(code).str.len().max()), # 方法二,需要設置date和time類型 date: Date, time: Time } write_records_into_mysql(df_bar, bar, dtype=dict_bar)#---------------------------------------------------------- #------------------- 存儲bar數據到資料庫 --------------------- #---------------------------------------------------------- if __name__ == __main__: print "PGM begin" store_bar(300223) print "PGM end"
方法二生成結果如下圖所示,效果比方法一要好,生成出來的date欄位是預期的date類型,額外多出來的time欄位,完全可以刪除。
這個問題可能根本不是一個問題,因為date欄位包含"00:00:00"格式,並沒有導致程序出錯;也不是說date欄位包含"00:00:00"格式,數據就無法使用,只是我單純覺得datetime類型沒有date類型好、包含"00:00:00"格式的內容不易於理解,這兩點不符合我預期才做出的修改。
如果從源頭出發,可能會有更好的解決辦法,以後找到方法再做補充。
原文鏈接:
將Numpy datetime64類型日期進行格式轉換參考資料:
pandas 將「字元類型的日期列」轉化成「時間戳索引(DatetimeIndex)」[pandas] 轉換DatetimeIndex為一個日期字元串的SeriesConverting between datetime, Timestamp and datetime64Datetimes and Timedeltas推薦閱讀:
※【翻譯】《利用Python進行數據分析·第2版》第5章(中)pandas入門
※如何與pandas愉快地玩耍(一)
※Pandas學習-6concat合併
※Redis初體驗
※(12)Python初入坑之案例分析二