簡體   English   中英

在 Pandas 中查找一系列分類數據的任意長度的重復區間

[英]Find Repeating Intervals of Arbitrary Length of a Series of Categorical Data in Pandas

有沒有辦法在Pandas中獲得任意長度重復間隔的開始和結束? 目前,我正在使用一種帶有shift()的 hacky 方式,我想知道是否有更好的方法來做到這一點。

例如,我有一個像這樣的DataFrame

index   category
0       blue
1       blue
2       blue
3       green
4       green
5       red
6       red
7       red
8       red
9       red
10      blue
11      blue
12      blue
13      blue
14      blue
15      blue
16      green
17      green
18      green
19      green

我想得到這個(或至少這個信息):

category    start   end
blue        0       2
green       3       4
red         5       9
blue        10      15
green       16      19

謝謝!

嘗試這個:

df.groupby((df['category'] != df['category'].shift()).cumsum(), 
            as_index=False)[['category', 'index']]\
  .agg(category=('category','first'),
       first=('index','first'),
       last=('index','last'))

Output:

  category  first  last
0     blue      0     2
1    green      3     4
2      red      5     9
3     blue     10    15
4    green     16    19

細節:

通過檢查類別的下一個值是否不等於當前類別並使用 cumsum 在數據中創建組來創建幫助器系列。 聚合這些組以獲得第一個和最后一個索引以及類別。

雖然cumsum + agg解決方案運行良好,但它的擴展性不是很好,也不能與DatetimeIndex一起使用,因此我針對掩碼方法對其進行了測試,並獲得了顯着的加速。 在這里為未來的訪客發布:

累積法

def get_interval_start_end_cumsum(df, col):

    if df.index.name:
        idx = df.index
        df = df.reset_index()
    else:
        idx = df.reset_index().index

    df = df.reset_index().groupby((df[col] != df[col].shift()).cumsum(), as_index = False) \
            .agg(category = (col, 'first'), first = ('index', 'first'), last=('index', 'last')
                ).rename(columns = {'category': col, 'first': 'start', 'last': 'end'})

    for c in ['start', 'end']:
        df[c] = df[c].apply(lambda x: idx[x])

    return df

蒙版法

def get_interval_start_end_mask(df, col):

    idx_name = df.index.name if df.index.name else 'index'
    mask = (df[col] != df[col].shift()) | (df[col] != df[col].shift(-1))
    df = deepcopy(df[mask].reset_index())

    return pd.concat([
        df.loc[df.index % 2 == 0].reset_index(drop = True).rename(columns = {idx_name: 'start'}),
        df.loc[df.index % 2 != 0].reset_index(drop = True).rename(columns = {idx_name: 'end'}).end
        ], axis = 1)[[col, 'start', 'end']]

結果

問題中的示例DataFrame

%timeit get_interval_start_end_cumsum(df, 'colors')
>> 10.8 ms ± 547 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit get_interval_start_end_mask(df, 'colors')
>> 4.84 ms ± 57.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

包含 350 萬行的真實數據

%timeit get_interval_start_end_cumsum(df, 'a_col')
>> 29.6 s ± 475 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit get_interval_start_end_mask(df, 'a_col')
>> 349 ms ± 9.64 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

如您所見,掩碼方法可以很好地擴展,並且在處理大量數據時,運行時間可以提高約 98.8%。

希望有幫助:)

暫無
暫無

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

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