簡體   English   中英

有效計算數據框中元素的非連續出現次數

[英]Efficiently calculate non-consecutive number of appereances of element in data frame

考慮以下數據框

                                     Value
time
2020-02-14 14:16:10.769999872+00:00     74
2020-02-14 14:16:11.360999936+00:00     74
2020-02-14 14:16:11.970000128+00:00     72
2020-02-14 14:16:12.637000192+00:00     72
2020-02-14 14:16:13.210000128+00:00     74
...                                    ...
2020-02-28 08:15:20.340000+00:00        71
2020-02-28 08:15:20.890000128+00:00     71
2020-02-28 08:15:21.424000+00:00        71
2020-02-28 08:15:22.032999936+00:00     72
2020-02-28 08:15:22.594000128+00:00     72

我希望我的代碼遍歷值,找到每個值的開始索引和結束索引,並將這些信息保存到字典中。

results = {74: {start:2020-02-14 14:16:10.769999872+00:00, end:2020-02-14 14:16:11.360999936+00:00}, 
           72: {start: ..., end: ...},
           ...}

因為這很簡單,棘手的部分是一個或多個值可能以非連續的方式出現多次: 74, 74, 72, 72, 72, 74, 74, 74, 71, 71, 71, 72, 72, 71, 71

如果是這種情況,則應為每個 Value 生成一個包含開始和結束索引的新序列。

results = {74:
               {Sequence1: {start:2020-02-14 14:16:10.769999872+00:00, end:2020-02-14 14:16:11.360999936+00:00},
                Sequence2: {start: ... , end: ...}},
           72: 
               {Sequence1: {start: ..., end: ...},
                Seqeunce2: {start: ..., end: ...},
                Sequence3: {start: ..., end: ...}},
          71: ...,
          }

當然,我可以用很多 for 循環來編寫代碼,但我想知道是否有更簡潔、更聰明的解決方案可以讓我省心。 也許最重要的是代碼運行速度快是至關重要的。 數據框大約有 300.000 行。

這可以分兩部分完成。 第一個包括發現連續組。 第二個是找到每個組的最小/最大時間。

要查找組,您可以使用此處描述的解決方案。 這是適用於您的情況的解決方案:

groups = (df.Value != df.Value.shift()).cumsum()

然后你可以應用多個groupby來查找開始和結束日期。 但是,使用agg有一種更有效和直接的方法來做到這一點:

result = df.groupby(groups).agg(Value=('Value',min), startTime=('time',min), endTime=('time',max))

最后,如果你想要一個字典,你可以迭代結果數據幀。

這是經過測試的輸入:

                                  time  Value
0  2020-02-14 14:16:10.769999872+00:00     74
1  2020-02-14 14:16:11.360999936+00:00     74
2  2020-02-14 14:16:11.970000128+00:00     72
3  2020-02-14 14:16:12.637000192+00:00     72
4  2020-02-14 14:16:13.210000128+00:00     74
5     2020-02-28 08:15:20.340000+00:00     71
6  2020-02-28 08:15:20.890000128+00:00     71
7     2020-02-28 08:15:21.424000+00:00     71
8  2020-02-28 08:15:22.032999936+00:00     72
9  2020-02-28 08:15:22.594000128+00:00     72

這是輸出:

       Value                            startTime                              endTime
Value                                                                                 
1         74  2020-02-14 14:16:10.769999872+00:00  2020-02-14 14:16:11.360999936+00:00
2         72  2020-02-14 14:16:11.970000128+00:00  2020-02-14 14:16:12.637000192+00:00
3         74  2020-02-14 14:16:13.210000128+00:00  2020-02-14 14:16:13.210000128+00:00
4         71     2020-02-28 08:15:20.340000+00:00     2020-02-28 08:15:21.424000+00:00
5         72  2020-02-28 08:15:22.032999936+00:00  2020-02-28 08:15:22.594000128+00:00

請注意,我使用編碼為字符串的輸入日期進行了測試,這應該沒問題,因為它們是根據 ISO 8601 表示的。

我假設該索引實際上是一個DatetimeIndex 如果不是,請轉換它。

要完成您的任務,請從定義要應用於每組行的函數開始:

def fn(grp):
    tMin = grp.index.min()
    tMax = grp.index.max()
    v = grp.Value.iloc[0]
    return pd.Series([v, tMin, tMax], index=['val', 'start', 'end'])

然后,它適用於每個組具有相同的價值價值變動將打開一個新組)行:

df2 = df.groupby([(df.Value != df.Value.shift()).cumsum()])\
    .apply(fn).reset_index(drop=True)

下一步是生成一個帶有Sequence...內容的列(首先只有一個數字,然后將其轉換為字符串):

df2['Seq'] = df2.groupby('val').cumcount() + 1
df2['Seq'] = 'Sequence' + df2['Seq'].astype(str)

要計算最終結果,請運行:

result = {}
for key, grp in gr:
    result[key] = grp.set_index('Seq')[['start', 'end']].to_dict(orient='index')

對於您的示例數據,結果是:

{71: {'Sequence1': {'start': Timestamp('2020-02-28 08:15:20.340000+0000', tz='UTC'),
   'end': Timestamp('2020-02-28 08:15:21.424000+0000', tz='UTC')}},
 72: {'Sequence1': {'start': Timestamp('2020-02-14 14:16:11.970000128+0000', tz='UTC'),
   'end': Timestamp('2020-02-14 14:16:12.637000192+0000', tz='UTC')},
  'Sequence2': {'start': Timestamp('2020-02-28 08:15:22.032999936+0000', tz='UTC'),
   'end': Timestamp('2020-02-28 08:15:22.594000128+0000', tz='UTC')}},
 74: {'Sequence1': {'start': Timestamp('2020-02-14 14:16:10.769999872+0000', tz='UTC'),
   'end': Timestamp('2020-02-14 14:16:11.360999936+0000', tz='UTC')},
  'Sequence2': {'start': Timestamp('2020-02-14 14:16:13.210000128+0000', tz='UTC'),
   'end': Timestamp('2020-02-14 14:16:13.210000128+0000', tz='UTC')}}}

請注意,保存在開始結束鍵下的每個值都是一個實際的時間戳。 它也可以是一個普通字符串,但我認為此內容更易於進一步處理。

暫無
暫無

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

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