簡體   English   中英

Python:在特定位置將行插入DataFrame的更快方法?

[英]Python: Faster way to insert rows into a DataFrame at specific locations?

我有一個約40,000行的DataFrame。 DataFrame大致類似於:

             Unix Time                           UTC  Val. 1  Val. 2  Val. 3
1    1518544176.927486    2018-02-13 17:49:36.927486    5.00    0.25    2.00
2    1518544176.929897    2018-02-13 17:49:36.929897    4.50    1.00    3.00
3    1518544176.932310    2018-02-13 17:49:36.932310    4.00    0.75    1.75
...

<class 'numpy.float64'><class 'numpy.float64'> 列1是<class 'pandas._libs.tslib.Timestamp'> 當人們繪制任何數據列與時間的關系時,我們會看到一個波形。 但是,收購中偶爾會有中斷。 例如,我們可能有:

               Unix Time                           UTC  Val. 1  Val. 2  Val. 3
576    1518544181.755085    2018-02-13 17:49:41.755085    0.10    0.01    0.93
577    1518544182.041129    2018-02-13 17:49:42.041129    0.11    0.02    0.95
...

可以看到,讀數576和577之間有大約0.3 s的間隙。問題在於,繪制數據時,即使沒有數據,matplotlib也會連接點。 這個問題的解決方案已經在Stack Overflow和在線一般會員的其他問題中得到解決,盡管我不喜歡...嗯,其中任何一個,最好的選擇似乎是將NaN插入到數據缺口。 由於matplotlib不會繪制NaN,因此這是一種狡猾的方法,可以欺騙它使您的繪制更加逼真。

為此,我首先查找前兩個讀數之間的時間差(這是安全的),然后將該值的兩倍用作“是否存在差距?”的指標。 然后,我遍歷DataFrame,檢查差距。 找到一個后,我在數據列中創建了一個NaN臨時行,並在時間列中的采集間隔的中間創建了時間值。 然后,我修改由舊框架構成的新DataFrame,並添加此行。 這看起來像在這里:

df2 = df.copy()
for i, row in df.iterrows():
    # The following code checks the delta-t of all timestamp pairs.
    # We have i > 0 because it can't activate on the first entry.
    if i > 0:
        delta_t_unix = row['Unix Time'] - prev_timestamp_unix
        delta_t_utc = row['UTC'] - prev_timestamp_utc
        # If delta_t_unix > the allowed data gap, add new timestamps and NaNs.
        if delta_t_unix > allowed_gap:
            time_unix = row['Unix Time'] - (delta_t_unix / 2.0)
            time_utc = row['UTC'] - (delta_t_utc / 2.0)
            val1 = np.nan
            val2 = np.nan
            val3 = np.nan
            new_row = pd.DataFrame({'Unix Time': time_unix, 'UTC': time_utc,
                                    'Val. 1': val1, 'Val. 2': val2,
                                    'Val. 3': val3}, index = [i])
            df2 = pd.concat([df2.ix[:i-1], new_row,
                            df2.ix[i:]]).reset_index(drop = True)
    # Set the previous timestamp for use in the beginning of the loop.
    prev_timestamp_unix = row[timestamp_unix]
    prev_timestamp_utc = row[timestamp_utc]
# Make the final DataFrame with the completed lists.
df2 = df2[['Unix Time', 'UTC', 'Val. 1', 'Val. 2', 'Val. 3']]

多虧了這個問題 ,目前大約需要4.5秒(以前大約需要6.5秒,因為我很愚蠢地遍歷並創建每列的新列表,然后從中創建一個新的DataFrame)。 但是,這仍然比我期望或喜歡的要慢得多。 有人對如何加快速度有任何想法嗎? 我對Pandas和DataFrames還是很陌生,所以我相信這會更好。 謝謝!

編輯:值得一提的是,如果我刪除了datetime列,它將把時間分成兩半(盡管不幸的是,我實際上無法刪除它)。

您可以使用以下方法將采樣重新采樣到2.4ms:

df['utc_time'] = pd.to_datetime(df['utc_time'])
df.set_index(df['utc_time'])[['val1','val2','val3']].resample('2.4ms', loffset='1.2ms').mean().reset_index()

可以加快速度的一些事情:

  1. 使用df.itertuples()代替df.iterrows() ,它可能會在一定程度上縮短執行時間。

如果您可以發布改進,我將不勝感激,但根據我的經驗,在我測試的案例中,這是一個巨大的差異(將10倍的改進,使循環內的指令更簡單)。

  1. 不要使用pd.concat將行放在一起,而是創建一個元組列表,然后僅在從該列表循環之后才生成DataFrame。

     for i, unix_time, utc_time, val1, val2, val3 in df.itertuples(): list_of_values = [] if i > 0: delta_t_unix = unix_time - prev_timestamp_unix delta_t_utc = utc_time - prev_timestamp_utc if delta_t_unix > allowed_gap: new_time_unix = unix_time - (delta_t_unix / 2.0) new_time_utc = utc_time - (delta_t_utc / 2.0) list_of_values.append((new_time_unix, new_time_utc, np.nan, np.nan, np.nan)) # Set the previous timestamp for use in the beginning of the loop. prev_timestamp_unix = unix_time prev_timestamp_utc = utc_time list_of_values.append(((unix_time , utc_time, val1, val2, val3)) df2 = pd.DataFrame(list_of_values, columns=['Unix Time', 'UTC', 'Val. 1', 'Val. 2', 'Val. 3']) 

那可能會大大加快速度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM