簡體   English   中英

迭代Pandas DataFrame並插入行的最快方法

[英]Fastest way to iterate over Pandas DataFrame and insert a Row

我正在構建一個工具,以幫助每周自動審查來自多個實驗室設置的數據。 每天生成制表符分隔的文本文件。 每行代表每2秒采集的數據,因此有43200行和多列(每個文件為75mb)

我正在使用pandas.readcsv加載七個文本文件,並且只將我需要的三個列提​​取到pandas數據幀中。 這比我想要的慢,但可以接受。 然后,我使用Plotly離線繪制數據以查看交互式繪圖。 這是一項計划任務,設置為每周運行一次。

數據與日期和時間相對應。 通常,測試設置暫時脫機,數據中會有間隙。 不幸的是,當繪制它時,所有數據都是按行連接的,即使測試離線數小時或數天。

防止這種情況的唯一方法是在兩個日期之間插入一行日期與實際數據和所有缺失數據的NaN。 我已經很容易地為缺失的數據文件實現了這個,但是我希望對大於某個時間段的數據中的任何間隙進行概括。 我提出了一個似乎有效的解決方案,但它真的很慢:

# alldata is a pandas dataframe with 302,000 rows and 4 columns
# one datetime column and three float32 columns

alldata_gaps  = pandas.DataFrame() #new dataframe with gaps in it

#iterate over all rows. If the datetime difference between 
#two consecutive rows is more than one minute, insert a gap row.

for i in range(0, len(alldata)):
    alldata_gaps = alldata_gaps.append(alldata.iloc[i])
    if alldata.iloc[i+1, 0]-alldata.iloc[i,0] > datetime.timedelta(minutes=1):
        Series = pandas.Series({'datetime' : alldata.iloc[i,0]
        +datetime.timedelta(seconds=3)})
        alldata_gaps = alldata_gaps.append(Series)
        print(Series)

有沒有人有一個建議,我怎么能加快這個操作,所以它不需要如此令人討厭的長時間?

這是一個只有100行的示例數據文件的保管箱鏈接

這是我當前腳本的鏈接,沒有添加間隙行

幾乎可以肯定,您的瓶頸來自pd.DataFrame.append

alldata_gaps = alldata_gaps.append(alldata.iloc[i])
alldata_gaps = alldata_gaps.append(Series)

pd.Series一下,你混淆地將變量命名為與Pandas對象pd.Series相同。 避免這種模糊性是一種很好的做法。

一個有效的解決方案是:

  1. 確定出現差距的時間。
  2. 使用這些時間+ 3秒的數據創建單個數據幀。
  3. 附加到現有數據框並按時間排序。

那么讓我們來看一個示例數據幀:

# example dataframe setup
df = pd.DataFrame({'Date': ['00:10:15', '00:15:20', '00:15:40', '00:16:50', '00:17:55',
                            '00:19:00', '00:19:10', '00:19:15', '00:19:55', '00:20:58'],
                   'Value': list(range(10))})

df['Date'] = pd.to_datetime('2018-11-06-' + df['Date'])

# find gaps greater than 1 minute
bools = (df['Date'].diff().dt.seconds > 60).shift(-1).fillna(False)
idx = bools[bools].index
# Int64Index([0, 2, 3, 4, 8], dtype='int64')

# construct dataframe to append
df_extra = df.loc[idx].copy().assign(Value=np.nan)

# add 3 seconds
df_extra['Date'] = df_extra['Date'] + pd.to_timedelta('3 seconds')

# append to original
res = df.append(df_extra).sort_values('Date')

結果:

print(res)

                 Date  Value
0 2018-11-06 00:10:15    0.0
0 2018-11-06 00:10:18    NaN
1 2018-11-06 00:15:20    1.0
2 2018-11-06 00:15:40    2.0
2 2018-11-06 00:15:43    NaN
3 2018-11-06 00:16:50    3.0
3 2018-11-06 00:16:53    NaN
4 2018-11-06 00:17:55    4.0
4 2018-11-06 00:17:58    NaN
5 2018-11-06 00:19:00    5.0
6 2018-11-06 00:19:10    6.0
7 2018-11-06 00:19:15    7.0
8 2018-11-06 00:19:55    8.0
8 2018-11-06 00:19:58    NaN
9 2018-11-06 00:20:58    9.0

我的一般想法與jpp的答案相同:不是迭代數據框(對於你擁有的數據量來說很慢),你應該只識別感興趣的行並使用它們。 主要區別在於1)將多列轉為NA和2)將NA行時間戳調整為周圍時間的一半

我在評論中添加了解釋......

# after you read in your data, make sure the time column is actually a datetime
df['datetime'] = pd.to_datetime(df['datetime'])

# calculate the (time) difference between a row and the previous row
df['time_diff'] = df['datetime'].diff()

# create a subset of your df where the time difference is greater than
# some threshold. This will be a dataframe of your empty/NA rows.
# I've set a 2 second threshold here because of the sample data you provided, 
# but could be any number of seconds
empty = df[df['time_diff'].dt.total_seconds() > 2].copy()

# calculate the correct timestamp for the NA rows (halfway and evenly spaced)
empty['datetime'] = empty['datetime'] - (empty['time_diff'].shift(-1) / 2)

# set all the columns to NA apart from the datetime column
empty.loc[:, ~empty.columns.isin(['datetime'])] = np.nan

# append this NA/empty dataframe to your original data, and sort by time
df = df.append(empty, ignore_index=True)
df = df.sort_values('datetime').reset_index(drop=True)

# optionally, remove the time_diff column we created at the beginning
df.drop('time_diff', inplace=True, axis=1)

這會給你這樣的東西:

在此輸入圖像描述

暫無
暫無

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

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