簡體   English   中英

如何使用.shift()根據條件過濾數據框

[英]How to filter a Dataframe based on a criteria using .shift()

我正在嘗試從groupby的第一個非順序“句點”開始刪除數據框中的任何行。 如果可能,我寧願避免循環。

import pandas as pd


data = {'Country': ['DE', 'DE', 'DE', 'DE', 'DE', 'US', 'US', 'US', 'US','US'],
    'Product': ['Blue', 'Blue', 'Blue', 'Blue','Blue','Green', 'Green', 'Green', 'Green','Green'],
    'Period': [1, 2, 3,5,6, 1, 2, 4, 5, 6]}

df = pd.DataFrame(data, columns= ['Country','Product', 'Period'])
print df

輸出:

  Country Product  Period
0      DE    Blue       1
1      DE    Blue       2
2      DE    Blue       3
3      DE    Blue       5
4      DE    Blue       6
5      US   Green       1
6      US   Green       2
7      US   Green       4
8      US   Green       5
9      US   Green       6

因此,例如,我想要的最終輸出如下:

  Country Product  Period
0      DE    Blue       1
1      DE    Blue       2
2      DE    Blue       3
5      US   Green       1
6      US   Green       2

下面是我嘗試執行此操作的方法,以便為您提供一個想法,但我有很多錯誤。 但是您可能會看到我正在嘗試做的邏輯。

df = df.groupby(['Country','Product']).apply(lambda x: x[x.Period.shift(x.Period - 1) == 1]).reset_index(drop=True)

棘手的部分不是僅僅使用.shift(1)或我試圖將值輸入.shift()的東西,即如果該行的Period為5,那么我想說.shift(5-1)以便它移動最多4個位置,並檢查該期間的值。 如果等於1,則表示它仍然是順序的。 我想在這種情況下,它將進入南疆。

除了使用shift()還可以使用diff()cumsum()

result = grouped['Period'].apply(
    lambda x: x.loc[(x.diff() > 1).cumsum() == 0])

import pandas as pd

data = {'Country': ['DE', 'DE', 'DE', 'DE', 'DE', 'US', 'US', 'US', 'US','US'],
    'Product': ['Blue', 'Blue', 'Blue', 'Blue','Blue','Green', 'Green', 'Green', 'Green','Green'],
    'Period': [1, 2, 3,5,6, 1, 2, 4, 5, 6]}

df = pd.DataFrame(data, columns= ['Country','Product', 'Period'])
print(df)
grouped = df.groupby(['Country','Product'])
result = grouped['Period'].apply(
    lambda x: x.loc[(x.diff() > 1).cumsum() == 0])
result.name = 'Period'
result = result.reset_index(['Country', 'Product'])
print(result)

產量

  Country Product  Period
0      DE    Blue       1
1      DE    Blue       2
2      DE    Blue       3
5      US   Green       1
6      US   Green       2

說明

一系列數字的相鄰差異為1。例如,如果我們目前將df['Period']視為所有一組的一部分,

In [41]: df['Period'].diff()
Out[41]: 
0   NaN
1     1
2     1
3     2
4     1
5    -5
6     1
7     2
8     1
9     1
Name: Period, dtype: float64

In [42]: df['Period'].diff() > 1
Out[42]: 
0    False
1    False
2    False
3     True       <--- We want to cut off before here
4    False
5    False
6    False
7     True
8    False
9    False
Name: Period, dtype: bool

要找到截止位置cumsum() df['Period'].diff() > 1的第一個True ,我們可以使用cumsum() ,然后選擇等於0的那些行:

In [43]: (df['Period'].diff() > 1).cumsum()
Out[43]: 
0    0
1    0
2    0
3    1
4    1
5    1
6    1
7    2
8    2
9    2
Name: Period, dtype: int64

In [44]: (df['Period'].diff() > 1).cumsum() == 0
Out[44]: 
0     True
1     True
2     True
3    False
4    False
5    False
6    False
7    False
8    False
9    False
Name: Period, dtype: bool

diff()cumsum()可能看起來很浪費,因為這些操作可能正在計算很多不需要的值-尤其是x很大且第一次順序運行很短時。

盡管存在浪費,但通過調用NumPy或Pandas方法(在C / Cython / C ++或Fortran中實現)獲得的速度通常會超過純Python編碼的浪費較少的算法。

但是,您可以取代呼叫cumsum通過調用argmax

result = grouped['Period'].apply(
    lambda x: x.loc[:(x.diff() > 1).argmax()].iloc[:-1])

對於非常大的x這可能會更快一些:

x = df['Period']
x = pd.concat([x]*1000)
x = x.reset_index(drop=True)

In [68]: %timeit x.loc[:(x.diff() > 1).argmax()].iloc[:-1]
1000 loops, best of 3: 884 µs per loop

In [69]: %timeit x.loc[(x.diff() > 1).cumsum() == 0]
1000 loops, best of 3: 1.12 ms per loop

但是請注意, argmax返回索引級別值,而不是順序索引位置。 因此,如果x.index包含重復值,則無法使用argmax。 (這就是為什么我必須設置x = x.reset_index(drop=True) 。)

因此,盡管在某些情況下使用argmax會快一些,但這種選擇並不那么健壯。

對不起..我不知道熊貓..但是一般來說,它可以直接在python中實現。

zip(data['Country'],data['Product'],data['Period'])
and the result will be a list ..
[('DE', 'Blue', 1), ('DE', 'Blue', 2), ('DE', 'Blue', 3), ('DE', 'Blue', 5), 
('DE', 'Blue', 6), ('US', 'Green', 1), ('US', 'Green', 2), ('US', 'Green', 4),
('US', 'Green', 5), ('US', 'Green', 6)]

之后,結果可以很容易地輸入到您的函數中

暫無
暫無

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

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