เปลี่ยนค่าหากบรรลุเงื่อนไขบางอย่างติดต่อกันใน Pandas

ฉันจะเปลี่ยนค่าของค่า DataFrame บางค่าเฉพาะในกรณีที่ตรงตามเงื่อนไขบางประการ n จำนวนครั้งติดต่อกัน

ตัวอย่าง:

df = pd.DataFrame(np.random.randn(15, 3))
df.iloc[4:8,0]=40
df.iloc[12,0]=-40
df.iloc[10:12,1]=-40

ซึ่งให้ DF นี้แก่ฉัน:

            0          1         2
0    1.238892   0.802318 -0.013856
1   -1.136326  -0.527263 -0.260975
2    1.118771   0.031517  0.527350
3    1.629482  -0.158941 -1.045209
4   40.000000   0.598657 -1.268399
5   40.000000   0.442297 -0.016363
6   40.000000  -0.316817  1.744822
7   40.000000   0.193083  0.914172
8    0.322756  -0.680682  0.888702
9   -1.204531  -0.240042  1.416020
10  -1.337494 -40.000000 -1.195780
11  -0.703669 -40.000000  0.657519
12 -40.000000  -0.288235 -0.840145
13  -1.084869  -0.298030 -1.592004
14  -0.617568  -1.046210 -0.531523

ตอนนี้ถ้าฉันทำ

a=df.copy()
a[ abs(a) > abs(a.std()) ] = float('nan')

ฉันเข้าใจ

           0         1         2
0   1.238892  0.802318 -0.013856
1  -1.136326 -0.527263 -0.260975
2   1.118771  0.031517  0.527350
3   1.629482 -0.158941       NaN
4        NaN  0.598657       NaN
5        NaN  0.442297 -0.016363
6        NaN -0.316817       NaN
7        NaN  0.193083  0.914172
8   0.322756 -0.680682  0.888702
9  -1.204531 -0.240042       NaN
10 -1.337494       NaN       NaN
11 -0.703669       NaN  0.657519
12       NaN -0.288235 -0.840145
13 -1.084869 -0.298030       NaN
14 -0.617568 -1.046210 -0.531523

ซึ่งเป็นเรื่องยุติธรรม อย่างไรก็ตาม ฉันต้องการแทนที่ค่าด้วย NaN เท่านั้น หากตรงตามเงื่อนไขเหล่านี้ด้วยรายการติดต่อกันสูงสุด 2 รายการ (ดังนั้นฉันจึงสามารถแก้ไขได้ในภายหลัง) เช่น ฉันอยากให้ผลลัพธ์เป็น

            0          1         2
0    1.238892   0.802318 -0.013856
1   -1.136326  -0.527263 -0.260975
2    1.118771   0.031517  0.527350
3    1.629482  -0.158941       NaN
4   40.000000   0.598657       NaN
5   40.000000   0.442297 -0.016363
6   40.000000  -0.316817       NaN
7   40.000000   0.193083  0.914172
8    0.322756  -0.680682  0.888702
9   -1.204531  -0.240042       NaN
10  -1.337494        NaN       NaN
11  -0.703669        NaN  0.657519
12        NaN  -0.288235 -0.840145
13  -1.084869  -0.298030       NaN
14  -0.617568  -1.046210 -0.531523

เห็นได้ชัดว่าไม่มีวิธีที่พร้อมใช้งานในการดำเนินการนี้ วิธีแก้ไขที่ฉันพบว่าใกล้เคียงที่สุดกับปัญหาของฉันคืออันนี้ แต่ฉันไม่สามารถทำให้มันได้ผลสำหรับฉัน

มีความคิดอะไรบ้าง?


person TomCho    schedule 29.09.2015    source แหล่งที่มา


คำตอบ (1)


ดูด้านล่าง - ส่วนที่ยุ่งยากคือ (cond[c] != cond[c].shift(1)).cumsum() ซึ่งแบ่งข้อมูลออกเป็นส่วนต่อเนื่องกันของค่าเดียวกัน

In [23]: cond = abs(df) > abs(df.std())

In [24]: for c in df.columns:
    ...:     grouper = (cond[c] != cond[c].shift(1)).cumsum() * cond[c]
    ...:     fill = (df.groupby(grouper)[c].transform('size') <= 2)
    ...:     df.loc[fill, c] = np.nan

In [25]: df
Out[25]: 
            0         1         2
0    1.238892  0.802318 -0.013856
1   -1.136326 -0.527263 -0.260975
2    1.118771  0.031517  0.527350
3    1.629482 -0.158941       NaN
4   40.000000  0.598657       NaN
5   40.000000  0.442297 -0.016363
6   40.000000 -0.316817       NaN
7   40.000000  0.193083  0.914172
8    0.322756 -0.680682  0.888702
9   -1.204531 -0.240042       NaN
10  -1.337494       NaN       NaN
11  -0.703669       NaN  0.657519
12        NaN -0.288235 -0.840145
13  -1.084869 -0.298030       NaN
14  -0.617568 -1.046210 -0.531523

เพื่ออธิบายเพิ่มเติมอีกเล็กน้อย cond[c] เป็นชุดบูลีนที่ระบุว่าเงื่อนไขของคุณเป็นจริงหรือไม่

cond[c] != cond[c].shift(1) เปรียบเทียบเงื่อนไขของแถวปัจจุบันกับเงื่อนไขของแถวถัดไป สิ่งนี้มีผลเหมือน 'การทำเครื่องหมาย' โดยที่การเรียกใช้ค่าเริ่มต้นด้วยค่า True

.cumsum() แปลงบูลเป็นจำนวนเต็มและรับผลรวมสะสม อาจไม่สามารถเข้าใจได้ง่ายในทันที แต่ 'ตัวเลข' นี้เป็นกลุ่มของค่าที่อยู่ติดกัน ในที่สุด * cond[c] จะกำหนดกลุ่มทั้งหมดที่ไม่ตรงตามเกณฑ์ให้เป็น 0 ใหม่ (โดยใช้ False == 0)

ตอนนี้ คุณมีกลุ่มตัวเลขที่อยู่ติดกันซึ่งตรงกับเงื่อนไขของคุณแล้ว ขั้นตอนถัดไปจะดำเนินการ groupby เพื่อนับจำนวนค่าในแต่ละกลุ่ม (transform('size')

ในที่สุด เงื่อนไขบูลใหม่จะถูกนำมาใช้เพื่อกำหนดค่าที่หายไปให้กับกลุ่มที่มีค่า 2 หรือน้อยกว่าที่ตรงตามเงื่อนไข

person chrisb    schedule 29.09.2015
comment
ฉันไม่เข้าใจจริงๆว่ามันทำงานอย่างไร ถ้าจะอธิบายให้ละเอียดจะยากเกินไปไหม? มันทำงานได้ดีจริงๆ ตอนนี้ฉันกำลังพยายามเพิ่มประสิทธิภาพ แต่จะยากเมื่อคุณไม่เข้าใจจริงๆ ว่ากำลังทำอะไรอยู่ - person TomCho; 30.09.2015
comment
ฉันได้เพิ่มภาษาอีกเล็กน้อย - วิธีที่เป็นประโยชน์มากที่สุดในการทำความเข้าใจคือการทำตามขั้นตอนแต่ละขั้นตอนใน REPL และดูค่ากลาง - person chrisb; 30.09.2015
comment
เยี่ยมมาก ฉันคิดว่าฉันเข้าใจแล้ว บรรทัดแรกของวงวนนั้นซับซ้อนมาก! +1 - person TomCho; 30.09.2015
comment
เฮ้ เพิ่งคิดว่าคุณต้องการ df.loc[fill & cond[c], c] = np.nan ในบรรทัดสุดท้ายจริง ๆ หรือไม่ก็ใช้ไม่ได้กับดาต้าเฟรมขนาดเล็ก - person TomCho; 24.04.2016