ทำให้ข้อมูลปกติในแพนด้า


133

สมมติว่าฉันมีกรอบข้อมูลแพนด้าdf:

ฉันต้องการคำนวณค่าเฉลี่ยคอลัมน์ที่ชาญฉลาดของกรอบข้อมูล

มันง่ายมาก:

df.apply(average) 

จากนั้นคอลัมน์ที่ชาญฉลาดช่วงสูงสุด (col) - นาที (col) นี่เป็นเรื่องง่ายอีกครั้ง:

df.apply(max) - df.apply(min)

ตอนนี้สำหรับแต่ละองค์ประกอบฉันต้องการลบค่าเฉลี่ยของคอลัมน์และหารด้วยช่วงของคอลัมน์ ฉันไม่แน่ใจว่าจะทำอย่างไร

ความช่วยเหลือ / คำแนะนำใด ๆ จะได้รับการชื่นชมมาก

คำตอบ:


226
In [92]: df
Out[92]:
           a         b          c         d
A  -0.488816  0.863769   4.325608 -4.721202
B -11.937097  2.993993 -12.916784 -1.086236
C  -5.569493  4.672679  -2.168464 -9.315900
D   8.892368  0.932785   4.535396  0.598124

In [93]: df_norm = (df - df.mean()) / (df.max() - df.min())

In [94]: df_norm
Out[94]:
          a         b         c         d
A  0.085789 -0.394348  0.337016 -0.109935
B -0.463830  0.164926 -0.650963  0.256714
C -0.158129  0.605652 -0.035090 -0.573389
D  0.536170 -0.376229  0.349037  0.426611

In [95]: df_norm.mean()
Out[95]:
a   -2.081668e-17
b    4.857226e-17
c    1.734723e-17
d   -1.040834e-17

In [96]: df_norm.max() - df_norm.min()
Out[96]:
a    1
b    1
c    1
d    1

มีวิธีดำเนินการนี้หรือไม่หากคุณต้องการทำให้ชุดย่อยเป็นปกติ บอกว่าแถวนั้นAและBเป็นส่วนหนึ่งของปัจจัยการจัดกลุ่มขนาดใหญ่ที่คุณต้องการที่จะแยกต่างหากจากปกติและC D
Amyunimus

เลือกชุดย่อยและคำนวณเหมือนเดิม ดูpandas.pydata.org/pandas-docs/stable/indexing.htmlเกี่ยวกับวิธีการจัดทำดัชนีและเลือกข้อมูล
Wouter Overmeire

17
หากคุณต้องการให้ค่าของคุณเป็น> 0: df_norm = (df - df.min ()) / (df.max () - df.min ())
Dayvid Oliveira

1
ควรเป็น df_norm = (df - df.min ()) / (df.max () - df.min ()) แทนที่จะเป็น df.mean () ในวงเล็บแรกเพื่อให้ได้ค่าระหว่าง 0 ถึง 1
jnPy

2
หาก dataframe ของคุณมีสตริงในบางคอลัมน์ให้ดูคำตอบ
netskink

75

หากคุณไม่ทราบนำเข้าsklearnห้องสมุดฉันจะแนะนำวิธีการพูดคุยกันในนี้บล็อก

import pandas as pd
from sklearn import preprocessing

data = {'score': [234,24,14,27,-74,46,73,-18,59,160]}
cols = data.columns
df = pd.DataFrame(data)
df

min_max_scaler = preprocessing.MinMaxScaler()
np_scaled = min_max_scaler.fit_transform(df)
df_normalized = pd.DataFrame(np_scaled, columns = cols)
df_normalized

2
ลิงก์ไปยังบล็อกโพสต์นั้นตายแล้ว คุณมีที่ทำงานหรือไม่?
มาร์ท

3
วิธีการที่สอดคล้องกันในการสร้างข้อมูลปกติของหน่วยเรียกว่า StandardScaler
abeboparebop

ฉันพบวิธีแก้ปัญหาที่คล้ายกันในที่อื่น ปัญหาคือในส่วน np_scaled มันแสดงข้อผิดพลาดที่คาดหวังอาร์เรย์ 2D แต่อินพุตเป็นอาร์เรย์ 1D และแนะนำให้ใช้การปรับรูปร่างใหม่ (-1,1) ความคิดใด ๆ ในการแก้ปัญหานี้เนื่องจากการปรับรูปร่างใหม่ก็ใช้ไม่ได้เช่นกัน?
Deadcode

คุณอาจได้รับคำเตือนขึ้นอยู่กับเวอร์ชันของ numpy & sklearn ที่คุณทำงานด้วย แต่โดยทั่วไปแล้วสิ่งนี้ควรได้ผล np_scaled = min_max_scaler.fit_transform(df.score.astype(float).values.reshape(-1, 1))
Jaeyoung Chun

33

คุณสามารถใช้applyสำหรับสิ่งนี้และมันค่อนข้างดีกว่า:

import numpy as np
import pandas as pd

np.random.seed(1)

df = pd.DataFrame(np.random.randn(4,4)* 4 + 3)

          0         1         2         3
0  9.497381  0.552974  0.887313 -1.291874
1  6.461631 -6.206155  9.979247 -0.044828
2  4.276156  2.002518  8.848432 -5.240563
3  1.710331  1.463783  7.535078 -1.399565

df.apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

          0         1         2         3
0  0.515087  0.133967 -0.651699  0.135175
1  0.125241 -0.689446  0.348301  0.375188
2 -0.155414  0.310554  0.223925 -0.624812
3 -0.484913  0.244924  0.079473  0.114448

นอกจากนี้ยังใช้งานได้ดีgroupbyหากคุณเลือกคอลัมน์ที่เกี่ยวข้อง:

df['grp'] = ['A', 'A', 'B', 'B']

          0         1         2         3 grp
0  9.497381  0.552974  0.887313 -1.291874   A
1  6.461631 -6.206155  9.979247 -0.044828   A
2  4.276156  2.002518  8.848432 -5.240563   B
3  1.710331  1.463783  7.535078 -1.399565   B


df.groupby(['grp'])[[0,1,2,3]].apply(lambda x: (x - np.mean(x)) / (np.max(x) - np.min(x)))

     0    1    2    3
0  0.5  0.5 -0.5 -0.5
1 -0.5 -0.5  0.5  0.5
2  0.5  0.5  0.5 -0.5
3 -0.5 -0.5 -0.5  0.5

2

แก้ไขเล็กน้อยจาก: Python Pandas Dataframe: Normalize data ระหว่าง 0.01 ถึง 0.99? แต่จากความคิดเห็นบางส่วนคิดว่าเกี่ยวข้อง (ขออภัยหากถือว่าเป็นการรีโพสต์แม้ว่า ... )

ฉันต้องการปรับให้เป็นมาตรฐานที่กำหนดเองในเปอร์เซ็นไทล์ปกติของ datum หรือ z-score นั้นไม่เพียงพอ บางครั้งฉันรู้ว่าจำนวนสูงสุดและต่ำสุดที่เป็นไปได้ของประชากรคืออะไรดังนั้นจึงต้องการกำหนดค่านี้นอกเหนือจากกลุ่มตัวอย่างของฉันหรือจุดกึ่งกลางอื่นหรืออะไรก็ตาม! สิ่งนี้มักมีประโยชน์ในการปรับขนาดและปรับขนาดข้อมูลให้เป็นมาตรฐานสำหรับอวนประสาทซึ่งคุณอาจต้องการอินพุตทั้งหมดระหว่าง 0 ถึง 1 แต่ข้อมูลบางส่วนของคุณอาจต้องปรับขนาดด้วยวิธีที่กำหนดเองมากขึ้น ... เนื่องจากเปอร์เซ็นไทล์และ stdev ถือว่าตัวอย่างของคุณครอบคลุม ประชากร แต่บางครั้งเรารู้ว่าสิ่งนี้ไม่เป็นความจริง นอกจากนี้ยังมีประโยชน์มากสำหรับฉันเมื่อแสดงภาพข้อมูลในแผนที่ความร้อน ดังนั้นฉันจึงสร้างฟังก์ชันที่กำหนดเอง (ใช้ขั้นตอนพิเศษในโค้ดที่นี่เพื่อให้อ่านได้ง่ายที่สุด):

def NormData(s,low='min',center='mid',hi='max',insideout=False,shrinkfactor=0.):    
    if low=='min':
        low=min(s)
    elif low=='abs':
        low=max(abs(min(s)),abs(max(s)))*-1.#sign(min(s))
    if hi=='max':
        hi=max(s)
    elif hi=='abs':
        hi=max(abs(min(s)),abs(max(s)))*1.#sign(max(s))

    if center=='mid':
        center=(max(s)+min(s))/2
    elif center=='avg':
        center=mean(s)
    elif center=='median':
        center=median(s)

    s2=[x-center for x in s]
    hi=hi-center
    low=low-center
    center=0.

    r=[]

    for x in s2:
        if x<low:
            r.append(0.)
        elif x>hi:
            r.append(1.)
        else:
            if x>=center:
                r.append((x-center)/(hi-center)*0.5+0.5)
            else:
                r.append((x-low)/(center-low)*0.5+0.)

    if insideout==True:
        ir=[(1.-abs(z-0.5)*2.) for z in r]
        r=ir

    rr =[x-(x-0.5)*shrinkfactor for x in r]    
    return rr

สิ่งนี้จะใช้ในซีรีส์แพนด้าหรือแม้แต่รายการและปรับให้เป็นจุดต่ำกลางและสูงที่คุณระบุ นอกจากนี้ยังมีปัจจัยหดตัว! เพื่อให้คุณสามารถย่อขนาดข้อมูลให้ห่างจากจุดสิ้นสุด 0 และ 1 (ฉันต้องทำสิ่งนี้เมื่อรวม colormaps ใน matplotlib: Single pcolormesh ที่มี colormap มากกว่าหนึ่ง colormap โดยใช้ Matplotlib ) ดังนั้นคุณจึงสามารถเห็นว่าโค้ดทำงานอย่างไร แต่โดยทั่วไปแล้วคุณจะพูดว่า มีค่า [-5,1,10] ในตัวอย่าง แต่ต้องการทำให้เป็นมาตรฐานตามช่วง -7 ถึง 7 (ดังนั้นอะไรก็ตามที่สูงกว่า 7 "10" ของเราจะถือว่าเป็น 7 อย่างมีประสิทธิภาพ) โดยมีจุดกึ่งกลาง 2 แต่ย่อขนาดให้พอดีกับ colormap 256 RGB:

#In[1]
NormData([-5,2,10],low=-7,center=1,hi=7,shrinkfactor=2./256)
#Out[1]
[0.1279296875, 0.5826822916666667, 0.99609375]

นอกจากนี้ยังสามารถเปลี่ยนข้อมูลของคุณจากภายใน ... สิ่งนี้อาจดูแปลก แต่ฉันพบว่ามีประโยชน์สำหรับการทำแผนที่ความร้อน สมมติว่าคุณต้องการสีเข้มขึ้นสำหรับค่าที่ใกล้เคียงกับ 0 แทนที่จะเป็น hi / low คุณสามารถแผนที่ความร้อนตามข้อมูลที่ทำให้เป็นมาตรฐานโดยที่ insideout = True:

#In[2]
NormData([-5,2,10],low=-7,center=1,hi=7,insideout=True,shrinkfactor=2./256)
#Out[2]
[0.251953125, 0.8307291666666666, 0.00390625]

ตอนนี้ "2" ซึ่งอยู่ใกล้จุดศูนย์กลางมากที่สุดโดยกำหนดให้ "1" เป็นค่าสูงสุด

อย่างไรก็ตามฉันคิดว่าแอปพลิเคชันของฉันมีความเกี่ยวข้องหากคุณต้องการลดขนาดข้อมูลด้วยวิธีอื่นที่อาจมีแอปพลิเคชันที่มีประโยชน์กับคุณ


คุณสามารถแทนที่ทั้งหมดหาก / งบอื่นกับพจนานุกรมที่มีฟังก์ชั่น ดูสะอาดขึ้นเล็กน้อยแล้ว
Roald

ค่อนข้างเรียบร้อยฉันจะจำไว้ในครั้งต่อไปขอบคุณ!
Vlox

0

นี่คือวิธีที่คุณทำคอลัมน์อย่างชาญฉลาด:

[df[col].update((df[col] - df[col].min()) / (df[col].max() - df[col].min())) for col in df.columns]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.