cột dataframe pandas mở rộng với sklearn


137

Tôi có một khung dữ liệu gấu trúc với các cột loại hỗn hợp và tôi muốn áp dụng min_max_scaler của sklearn cho một số cột. Lý tưởng nhất là tôi muốn thực hiện những biến đổi này tại chỗ, nhưng vẫn chưa tìm ra cách để làm điều đó. Tôi đã viết đoạn mã sau hoạt động:

import pandas as pd
import numpy as np
from sklearn import preprocessing

scaler = preprocessing.MinMaxScaler()

dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
min_max_scaler = preprocessing.MinMaxScaler()

def scaleColumns(df, cols_to_scale):
    for col in cols_to_scale:
        df[col] = pd.DataFrame(min_max_scaler.fit_transform(pd.DataFrame(dfTest[col])),columns=[col])
    return df

dfTest

    A   B   C
0    14.00   103.02  big
1    90.20   107.26  small
2    90.95   110.35  big
3    96.27   114.23  small
4    91.21   114.68  small

scaled_df = scaleColumns(dfTest,['A','B'])
scaled_df

A   B   C
0    0.000000    0.000000    big
1    0.926219    0.363636    small
2    0.935335    0.628645    big
3    1.000000    0.961407    small
4    0.938495    1.000000    small

Tôi tò mò liệu đây có phải là cách ưa thích / hiệu quả nhất để thực hiện chuyển đổi này. Có cách nào tôi có thể sử dụng df.apply sẽ tốt hơn không?

Tôi cũng ngạc nhiên khi tôi không thể làm cho đoạn mã sau hoạt động:

bad_output = min_max_scaler.fit_transform(dfTest['A'])

Nếu tôi chuyển toàn bộ khung dữ liệu cho bộ chia tỷ lệ thì nó hoạt động:

dfTest2 = dfTest.drop('C', axis = 1) good_output = min_max_scaler.fit_transform(dfTest2) good_output

Tôi bối rối tại sao vượt qua một loạt để mở rộng thất bại. Trong mã làm việc đầy đủ của tôi ở trên, tôi đã hy vọng chỉ cần truyền một chuỗi cho bộ chia tỷ lệ sau đó đặt cột dataframe = cho chuỗi được chia tỷ lệ. Tôi đã thấy câu hỏi này hỏi một vài nơi khác, nhưng không tìm thấy câu trả lời hay. Bất kỳ trợ giúp để hiểu những gì đang xảy ra ở đây sẽ được đánh giá rất cao!


1
Nó có hoạt động nếu bạn làm điều này bad_output = min_max_scaler.fit_transform(dfTest['A'].values)? truy cập valuesthuộc tính trả về một mảng numpy, vì một số lý do, đôi khi api học scikit sẽ gọi đúng phương thức làm cho gấu trúc trả về một mảng numpy và đôi khi không.
EdChum

Các datafram của Pandas là những đối tượng khá phức tạp với các quy ước không khớp với các quy ước của scikit-learn. Nếu bạn chuyển đổi mọi thứ thành mảng NumPy, scikit-learn sẽ dễ làm việc hơn rất nhiều.
Fred Foo

@edChum - bad_output = in_max_scaler.fit_transform(dfTest['A'].values)cũng không hoạt động. @larsmans - vâng tôi đã nghĩ về việc đi xuống tuyến đường này, nó có vẻ như là một rắc rối. Tôi không biết đó có phải là lỗi hay không mà Pandas có thể truyền toàn bộ khung dữ liệu cho hàm sklearn, nhưng không phải là một chuỗi. Sự hiểu biết của tôi về một khung dữ liệu là nó là một chuỗi của chuỗi. Đọc trong cuốn sách "Python để phân tích dữ liệu", nó nói rằng gấu trúc được xây dựng trên đỉnh của numpy để làm cho nó dễ sử dụng trong các ứng dụng NumPy-centric.
flymeatball

Câu trả lời:


213

Tôi không chắc chắn nếu các phiên bản trước pandasđã ngăn chặn điều này nhưng bây giờ đoạn mã sau hoạt động hoàn hảo với tôi và tạo ra chính xác những gì bạn muốn mà không phải sử dụngapply

>>> import pandas as pd
>>> from sklearn.preprocessing import MinMaxScaler


>>> scaler = MinMaxScaler()

>>> dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],
                           'B':[103.02,107.26,110.35,114.23,114.68],
                           'C':['big','small','big','small','small']})

>>> dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A', 'B']])

>>> dfTest
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

80
Khéo léo! Một phiên bản tổng quát hơndf[df.columns] = scaler.fit_transform(df[df.columns])
citynorman

6
@RajeshThevar Dấu ngoặc ngoài là dấu ngoặc chọn điển hình của gấu trúc, yêu cầu gấu trúc chọn một cột từ khung dữ liệu. Các dấu ngoặc trong cho biết một danh sách. Bạn đang chuyển một danh sách đến bộ chọn gấu trúc. Nếu bạn chỉ sử dụng dấu ngoặc đơn - với một tên cột được theo sau bởi một tên khác, được phân tách bằng dấu phẩy - gấu trúc sẽ diễn giải điều này như thể bạn đang cố chọn một cột từ một khung dữ liệu với các cột đa cấp (Đa chỉ số) và sẽ ném một phím bấm .
ken

1
để thêm vào câu trả lời của @ ken nếu bạn muốn xem chính xác cách gấu trúc thực hiện logic lập chỉ mục này và tại sao một bộ giá trị sẽ được diễn giải khác với danh sách bạn có thể xem cách DataFrames thực hiện __getitem__phương thức. Cụ thể bạn có thể mở ipython và làm pd.DataFrame.__getitem__??; sau khi bạn nhập gấu trúc dưới dạng pd tất nhiên;)
LetsPlayYahtzee

4
Một lưu ý thực tế: đối với những người sử dụng phân tách dữ liệu thử nghiệm / đào tạo, bạn sẽ chỉ muốn phù hợp với dữ liệu đào tạo của bạn chứ không phải dữ liệu thử nghiệm của bạn.
David J.

1
Để chia tỷ lệ trừ cột dấu thời gian, hãy kết hợp với columns =df.columns.drop('timestamps') df[df.columns] = scaler.fit_transform(df[df.columns]
intotecho

19

Như thế này?

dfTest = pd.DataFrame({
           'A':[14.00,90.20,90.95,96.27,91.21],
           'B':[103.02,107.26,110.35,114.23,114.68], 
           'C':['big','small','big','small','small']
         })
dfTest[['A','B']] = dfTest[['A','B']].apply(
                           lambda x: MinMaxScaler().fit_transform(x))
dfTest

    A           B           C
0   0.000000    0.000000    big
1   0.926219    0.363636    small
2   0.935335    0.628645    big
3   1.000000    0.961407    small
4   0.938495    1.000000    small

3
Tôi nhận được một loạt các khoản khấu hao khi tôi chạy tập lệnh này. Nó nên được cập nhật như thế nào?
cướp biển

Xem câu trả lời của @ LetsPlayYahtzee bên dưới
AJP

2
Phiên bản đơn giản hơn: dfTest [['A', 'B']] = dfTest [['A', 'B']]. Áp dụng (MinMaxScaler (). Fit_transform)
Alexandre V.

12

Vì nó đang được đề cập trong bình luận của hải tặc - .apply(lambda el: scale.fit_transform(el))phương pháp sẽ đưa ra cảnh báo sau:

DeprecationWarning: Vượt qua mảng 1d khi dữ liệu bị phản đối trong 0.17 và sẽ tăng ValueError trong 0.19. Định hình lại dữ liệu của bạn bằng X.reshape (-1, 1) nếu dữ liệu của bạn có một tính năng duy nhất hoặc X.reshape (1, -1) nếu nó chứa một mẫu.

Chuyển đổi các cột của bạn thành các mảng numpy sẽ thực hiện công việc (tôi thích StandardScaler):

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()

dfTest[['A','B','C']] = scale.fit_transform(dfTest[['A','B','C']].as_matrix())

- Chỉnh sửa tháng 11 năm 2018 (Đã thử nghiệm cho gấu trúc 0.23.4 ) -

Như Rob Murray đã đề cập trong các bình luận, trong phiên bản hiện tại (v0.23.4) của gấu trúc .as_matrix()trở lại FutureWarning. Do đó, cần được thay thế bằng .values:

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

scaler.fit_transform(dfTest[['A','B']].values)

- Chỉnh sửa tháng 5 năm 2019 (Đã thử nghiệm cho gấu trúc 0.24.2 ) -

Như joelostblom đề cập trong các ý kiến, "Kể từ 0.24.0đó, nên sử dụng .to_numpy()thay vì .values."

Ví dụ cập nhật:

import pandas as pd
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
dfTest = pd.DataFrame({
               'A':[14.00,90.20,90.95,96.27,91.21],
               'B':[103.02,107.26,110.35,114.23,114.68],
               'C':['big','small','big','small','small']
             })
dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A','B']].to_numpy())
dfTest
      A         B      C
0 -1.995290 -1.571117    big
1  0.436356 -0.603995  small
2  0.460289  0.100818    big
3  0.630058  0.985826  small
4  0.468586  1.088469  small

1
sử dụng .valuesthay cho .as_matrix()như as_matrix()bây giờ cho a FutureWarning.
Rob Murray


10
df = pd.DataFrame(scale.fit_transform(df.values), columns=df.columns, index=df.index)

Điều này sẽ làm việc mà không có cảnh báo khấu hao.


7

Bạn chỉ có thể làm điều đó bằng cách sử dụng pandas:

In [235]:
dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
df = dfTest[['A', 'B']]
df_norm = (df - df.min()) / (df.max() - df.min())
print df_norm
print pd.concat((df_norm, dfTest.C),1)

          A         B
0  0.000000  0.000000
1  0.926219  0.363636
2  0.935335  0.628645
3  1.000000  0.961407
4  0.938495  1.000000
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

6
Tôi biết rằng tôi có thể làm điều đó chỉ trong gấu trúc, nhưng cuối cùng tôi có thể muốn áp dụng một phương pháp sklearn khác mà không dễ để tự viết. Tôi quan tâm nhiều hơn đến việc tìm ra lý do tại sao áp dụng cho một loạt không hoạt động như tôi mong đợi hơn là tôi đưa ra một giải pháp đơn giản hơn. Bước tiếp theo của tôi sẽ là chạy RandomForestRegressor và tôi muốn chắc chắn rằng tôi hiểu cách Pandas và sklearn phối hợp với nhau.
flymeatball

5
Câu trả lời này là nguy hiểmdf.max() - df.min()có thể là 0, dẫn đến một ngoại lệ. Hơn nữa, df.min()được tính hai lần mà không hiệu quả. Lưu ý rằng df.ptp()tương đương với df.max() - df.min().
Acumenus

3

Tôi biết đó là một nhận xét rất cũ, nhưng vẫn:

Thay vì sử (dfTest['A'])dụng dấu ngoặc đơn, hãy sử dụng dấu ngoặc kép (dfTest[['A']]).

tức là : min_max_scaler.fit_transform(dfTest[['A']]).

Tôi tin rằng điều này sẽ cho kết quả mong muốn.

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.