Bình thường hóa dữ liệu trong gấu trúc


131

Giả sử tôi có khung dữ liệu gấu trúc df:

Tôi muốn tính toán trung bình của cột dữ liệu.

Điều này thật dễ dàng:

df.apply(average) 

sau đó cột thông minh phạm vi max (col) - min (col). Điều này lại dễ dàng:

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

Bây giờ với mỗi phần tử tôi muốn trừ đi giá trị trung bình của cột và chia cho phạm vi của cột. Tôi không chắc làm thế nào để làm điều đó

Bất kỳ trợ giúp / con trỏ được nhiều đánh giá cao.

Câu trả lời:


225
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

Có cách nào để làm điều này nếu bạn muốn bình thường hóa một tập hợp con? Nói hàng đó ABlà một phần của một yếu tố nhóm lớn hơn mà bạn muốn bình thường hóa riêng biệt từ CD.
Amyunimus

Chọn tập hợp con và tính toán như trước. Xem pandas.pydata.org/pandas-docs/urdy/indexing.html về cách lập chỉ mục và chọn dữ liệu
Wouter Overmeire

17
Nếu bạn cần các giá trị của mình là> 0: df_norm = (df - df.min ()) / (df.max () - df.min ())
Dayvid Oliveira

1
nên là df_norm = (df - df.min ()) / (df.max () - df.min ()) thay vì df.mean () trong ngoặc đầu tiên để nhận các giá trị trong khoảng từ 0 đến 1
jnPy

2
Nếu khung dữ liệu của bạn có các chuỗi trong một số cột, hãy xem câu trả lời
netskink

73

Nếu bạn không ngại nhập sklearnthư viện, tôi sẽ đề xuất phương pháp được nói trên blog này .

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
liên kết đến bài viết trên blog đã chết. bạn có làm việc không
siêu thị

3
Phương pháp tương ứng để tạo dữ liệu chuẩn hóa đơn vị được gọi là StandardScaler.
abeboparebop

Tôi tìm thấy một giải pháp tương tự ở một nơi khác. Vấn đề là ở phần np_scaled, nó đã hiển thị một lỗi mong đợi mảng 2D nhưng đầu vào là mảng 1D và chúng tôi khuyên chúng ta nên sử dụng định hình lại (-1,1). Bất kỳ ý tưởng làm thế nào để giải quyết điều này như định hình lại cũng không hoạt động.?
deadcode

Bạn có thể nhận được các cảnh báo tùy thuộc vào phiên bản của numpy & sklearn mà bạn làm việc cùng, nhưng nói chung, điều này sẽ hoạt động np_scaled = min_max_scaler.fit_transform(df.score.astype(float).values.reshape(-1, 1))
Jaeyoung Chun

33

Bạn có thể sử dụng applycho việc này và nó gọn gàng hơn một chút:

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

Ngoài ra, nó hoạt động độc đáo với groupby, nếu bạn chọn các cột có liên quan:

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

Sửa đổi một chút từ: Python Pandas Dataframe: Bình thường hóa dữ liệu trong khoảng từ 0,01 đến 0,99?nhưng từ một số ý kiến ​​cho rằng nó có liên quan (xin lỗi nếu được coi là repost mặc dù ...)

Tôi muốn chuẩn hóa tùy chỉnh trong phần trăm thông thường của điểm chuẩn hoặc điểm z là không đủ. Đôi khi tôi biết tối đa và tối thiểu khả thi của dân số là gì, và do đó muốn xác định nó khác với mẫu của tôi, hoặc một điểm giữa khác, hoặc bất cứ điều gì! Điều này thường có thể hữu ích cho việc định cỡ lại và chuẩn hóa dữ liệu cho các mạng lưới thần kinh nơi bạn có thể muốn tất cả các đầu vào trong khoảng từ 0 đến 1, nhưng một số dữ liệu của bạn có thể cần được thu nhỏ theo cách tùy chỉnh hơn ... bởi vì phần trăm và stdevs giả định bìa của bạn dân số, nhưng đôi khi chúng ta biết điều này không đúng. Nó cũng rất hữu ích cho tôi khi trực quan hóa dữ liệu trong các bản đồ nhiệt. Vì vậy, tôi đã xây dựng một chức năng tùy chỉnh (sử dụng các bước bổ sung trong mã ở đây để làm cho nó dễ đọc nhất có thể):

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

Điều này sẽ đưa vào một loạt gấu trúc, hoặc thậm chí chỉ là một danh sách và bình thường hóa nó đến các điểm thấp, trung tâm và điểm cao được chỉ định của bạn. cũng có một yếu tố thu nhỏ! để cho phép bạn thu nhỏ dữ liệu khỏi các điểm cuối 0 và 1 (Tôi đã phải làm điều này khi kết hợp các bản đồ màu trong matplotlib: pcolormesh đơn với nhiều hơn một bản đồ màu bằng Matplotlib ) Vì vậy, bạn có thể thấy cách mã hoạt động có các giá trị [-5,1,10] trong một mẫu, nhưng muốn bình thường hóa dựa trên phạm vi từ -7 đến 7 (vì vậy, bất cứ điều gì trên 7, "10" của chúng tôi được coi là 7 một cách hiệu quả) với trung điểm là 2, nhưng thu nhỏ nó để phù hợp với một bản đồ màu 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]

Nó cũng có thể biến dữ liệu của bạn từ trong ra ngoài ... điều này có vẻ kỳ lạ, nhưng tôi thấy nó hữu ích cho việc lập bản đồ nhiệt. Giả sử bạn muốn màu tối hơn cho các giá trị gần bằng 0 hơn là hi / low. Bạn có thể lập bản đồ nhiệt dựa trên dữ liệu đã chuẩn hóa trong khioutout = 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]

Vì vậy, bây giờ "2" gần trung tâm nhất, được định nghĩa là "1" là giá trị cao nhất.

Dù sao, tôi nghĩ rằng ứng dụng của tôi có liên quan nếu bạn đang tìm cách hủy dữ liệu theo những cách khác có thể có các ứng dụng hữu ích cho bạn.


Bạn có thể thay thế tất cả các câu lệnh if / other bằng một từ điển bằng các hàm . Có vẻ sạch sẽ hơn một chút rồi.
Roald

Điều đó khá gọn gàng, tôi sẽ ghi nhớ điều đó vào lần tới, cảm ơn!
Vlox

0

Đây là cách bạn thực hiện nó một cách khôn ngoan:

[df[col].update((df[col] - df[col].min()) / (df[col].max() - df[col].min())) for col in df.columns]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.