簡體   English   中英

Pandas DataFrame 中的 bin 數量意外

[英]Unexpected number of bins in Pandas DataFrame resample

問題

I need to reduce the length of a DataFrame to some externally defined integer (could be two rows, 10,000 rows, etc., but will always be a reduction in overall length), but I also want to keep the resulting DataFrame representative of the original . 原始 DataFrame(我們稱之為df )有一個datetime時間列( utc_time )和一個數據值列( data_value )。 日期時間始終是連續的、不重復的,盡管間隔不均勻(即,數據可能“丟失”)。 對於此示例中的 DataFrame,時間戳以十分鍾為間隔(當數據存在時)。

嘗試

為了做到這一點,我立即想到了用以下邏輯重新采樣:找到第一個和最后一個時間戳之間的秒差,將其除以所需的最終長度,這就是重新采樣因子。 我在這里設置:

# Define the desired final length.
final_length = 2
# Define the first timestamp.
first_timestamp = df['utc_time'].min().timestamp()
# Define the last timestamp.
last_timestamp = df['utc_time'].max().timestamp()
# Define the difference in seconds between the first and last timestamps.
delta_t = last_timestamp - first_timestamp
# Define the resampling factor.
resampling_factor = np.ceil(delta_t / final_length)

# Set the index from the `utc_time` column so that we can resample nicely.
df.set_index('utc_time', drop=True, inplace=True)
# Do the resampling.
resamp = df.resample(f'{resampling_factor}S')

要查看resamp ,我只是循環並打印:

for i in resamp:
    print(i)

這產生了(我進行了一些清理)以下內容:

 utc_time                  data_value
 2016-09-28 21:10:00       140.0
 2016-09-28 21:20:00       250.0
 2016-09-28 21:30:00       250.0
 2016-09-28 21:40:00       240.0
 2016-09-28 21:50:00       240.0
 ...                         ...
 2018-08-06 13:00:00       240.0
 2018-08-06 13:10:00       240.0
 2018-08-06 13:20:00       240.0
 2018-08-06 13:30:00       240.0
 2018-08-06 13:40:00       230.0
 
 [69889 rows x 1 columns])

 utc_time                  data_value
 2018-08-06 13:50:00       230.0
 2018-08-06 14:00:00       230.0
 2018-08-06 14:10:00       230.0
 2018-08-06 14:20:00       230.0
 2018-08-06 14:30:00       230.0
 ...                         ...
 2020-06-14 02:50:00       280.0
 2020-06-14 03:00:00       280.0
 2020-06-14 03:10:00       280.0
 2020-06-14 03:20:00       280.0
 2020-06-14 03:30:00       280.0
 
 [97571 rows x 1 columns])

 utc_time                  data_value
 2020-06-14 03:40:00       280.0
 2020-06-14 03:50:00       280.0
 2020-06-14 04:00:00       280.0
 2020-06-14 04:10:00       280.0
 2020-06-14 04:20:00       280.0
 ...                         ...
 2020-06-15 00:10:00       280.0
 2020-06-15 00:20:00       270.0
 2020-06-15 00:30:00       270.0
 2020-06-15 00:40:00       270.0
 2020-06-15 00:50:00       280.0

 [128 rows x 1 columns])

可以看到,這產生了三個垃圾箱,而不是我預期的兩個垃圾箱。

我可以做一些不同的事情,比如改變我選擇重采樣因子的方式(例如,找到時間戳之間的平均時間,並將其乘以(DataFrame / final_length的長度)應該會產生一個更保守的重采樣因子),但這會我的想法,成為潛在問題的面具。 主要是,我很想了解為什么會發生這種情況。 這導致...

問題

有誰知道為什么會發生這種情況,以及我可能會采取哪些步驟來確保我們獲得所需數量的垃圾箱? 我想知道這是否是一個抵消問題 - 也就是說,盡管我們將第一個 bin 中的第一個時間戳視為 DataFrame 的第一個時間戳,但也許 pandas 實際上是在那之前開始 bin 的?

對於任何想在家一起玩的人,測試 DataFrame 可以在這里找到a.csv。 以 DataFrame 的形式獲取它:

df = pd.read_csv('test.csv', parse_dates=[0])

概括

  • 問題 1 和修復:您形成垃圾箱的方式會產生一個額外的垃圾箱,因為使用df.resample()創建的垃圾箱將僅在一端(左側或右側)關閉。 使用“1.”中列出的選項之一修復此問題。

  • 問題 2 和修復:第一個 bin 左邊緣位於當天開始時('2016-09-28 00:00:00')(參見“2.”)。 您可以使用kind='period'作為resample()的參數來修復它。 (見“3”)

1. 瀏覽輸入數據(以及我們需要什么樣的 bin)

輸入數據是從2016-09-28 21:10:002020-06-15 00:50:00 ,使用你擁有的resampling_factor ,我們得到:

In [63]: df.index.min()
Out[63]: Timestamp('2016-09-28 21:10:00')

In [64]: df.index.min() + pd.Timedelta(f'{resampling_factor}S')
Out[64]: Timestamp('2018-08-07 11:00:00')

In [65]: _ + pd.Timedelta(f'{resampling_factor}S')
Out[65]: Timestamp('2020-06-15 00:50:00')

要使用這些時間戳將數據分成兩部分,我們需要將 bin

  • ['2016-09-28 21:10:00', '2018-08-07 11:00:00')
  • ['2018-08-07 11:00:00', '2020-06-15 00:50:00']

[表示封閉端, (表示開放端)

  • 這是一個問題:您不能形成從兩端封閉的垃圾箱。 您必須決定是否要從左側或右側關閉垃圾箱(參數closed='left'|'right' ,)。 使用closed='left'你會有
    • ['2016-09-28 21:10:00', '2018-08-07 11:00:00')
    • ['2018-08-07 11:00:00', '2020-06-15 00:50:00')
    • ['2020-06-15 00:50:00', '2022-04-23 14:40:00') (這里只有一個條目)

可能的修復

  1. 通過在其中添加一些時間來調整您的最后一個時間戳:
    last_timestamp = (df['utc_time'].max() +
                      pd.Timedelta('10 minutes')).timestamp()
  1. 使resampling_factor比你第一次計算的大一點。
  2. 只需使用df.resample中的前兩個數據幀,而忽略只有一個或幾個條目的第三個數據幀

選擇在您的應用程序中最有意義的選項。

2. 看看我們現在擁有的

  • df.resample文檔中,我們知道返回的標簽是左 bin 邊緣
  • 如果我們查看數據,我們會看到現在有什么樣的標簽。

In [67]: resamp = df.resample(f'{resampling_factor}S')

In [68]: itr = iter(resamp)

In [69]: next(itr)
Out[69]:
(Timestamp('2016-09-28 00:00:00', freq='58542600S'),
                      data_value
 utc_time
 2016-09-28 21:10:00       140.0
 ...                         ...
 2018-08-06 13:40:00       230.0

 [69889 rows x 1 columns])

In [70]: next(itr)
Out[70]:
(Timestamp('2018-08-06 13:50:00', freq='58542600S'),
                      data_value
 utc_time
 2018-08-06 13:50:00       230.0
 ...                         ...
 2020-06-14 03:30:00       280.0

 [97571 rows x 1 columns])

In [71]: next(itr)
Out[71]:
(Timestamp('2020-06-14 03:40:00', freq='58542600S'),
                      data_value
 utc_time
 2020-06-14 03:40:00       280.0
 ...                         ...
 2020-06-15 00:50:00       280.0

 [128 rows x 1 columns])

  • 因此,這些垃圾箱是
    • ['2016-09-28 00:00:00', '2018-08-06 13:50:00')
    • ['2018-08-06 13:50:00', '2020-06-14 03:40:00')
    • ['2020-06-14 03:40:00', '2022-04-22 17:30:00') (通過將resampling_factor添加到 bin 的開頭來計算端點。)
  • 我們看到第一個 bin 不是從df['utc_time'].min ( 2016-09-28 21:10:00 ) 開始的,而是從那天開始的時候開始的(正如你猜到的)
  • 由於第一個 bin 在預期之前開始,我們有兩個 bin 之外的數據,在第三個bin 中。

3.固定起始bin左邊緣

kind參數可以是'timestamp''period' 如果將其更改為'period' ,您將擁有以下垃圾箱(使用closed='left' ):

  • ['2016-09-28 21:10:00', '2018-08-07 11:00:00') <-- 固定
  • ['2018-08-07 11:00:00', '2020-06-15 00:50:00')
  • ['2020-06-15 00:50:00', '2022-04-23 14:40:00') (使用“1.”中給出的選項刪除)

暫無
暫無

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

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