Thay đổi kiểu dữ liệu của các cột trong Pandas


805

Tôi muốn chuyển đổi một bảng, được trình bày dưới dạng một danh sách các danh sách, thành một Pandas DataFrame. Như một ví dụ cực kỳ đơn giản:

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a)

Cách tốt nhất để chuyển đổi các cột thành các loại thích hợp, trong trường hợp này là cột 2 và 3 thành phao? Có cách nào để chỉ định các loại trong khi chuyển đổi sang DataFrame không? Hoặc tốt hơn là tạo DataFrame trước rồi lặp qua các cột để thay đổi loại cho mỗi cột? Lý tưởng nhất là tôi muốn làm điều này một cách năng động bởi vì có thể có hàng trăm cột và tôi không muốn chỉ định chính xác cột nào thuộc loại nào. Tất cả những gì tôi có thể đảm bảo là mỗi cột chứa các giá trị cùng loại.


Tôi đã thấy các cách tiếp cận để chuyển đổi mọi cột và cách tiếp cận để chuyển đổi các cột được đặt tên cụ thể, nhưng làm thế nào về các cột nhất định đáp ứng một điều kiện nhất định khi bạn không thể liệt kê 100 cột mà bạn muốn chuyển đổi cùng một lúc? Tôi đang suy nghĩ ví dụ về tất cả float64 -> float32 hoặc các chiến thuật tiết kiệm bộ nhớ khác.
demongolem

@demongolem: bạn có thể làm một cái gì đó như df.apply(pd.to_numeric, downcast="integer", errors="ignore")để hạ thấp các cột số nguyên thành dtype (số nguyên) nhỏ nhất sẽ giữ các giá trị.
Alex Riley

Câu trả lời:


1190

Bạn có ba tùy chọn chính để chuyển đổi các loại trong gấu trúc:

  1. to_numeric()- cung cấp chức năng để chuyển đổi một cách an toàn các loại không phải số (ví dụ: chuỗi) sang loại số phù hợp. (Xem thêm to_datetime()to_timedelta().)

  2. astype()- chuyển đổi (gần như) bất kỳ loại nào sang (gần như) bất kỳ loại nào khác (ngay cả khi không nhất thiết phải làm như vậy). Cũng cho phép bạn chuyển đổi sang các loại chiến lược (rất hữu ích).

  3. infer_objects() - một phương thức tiện ích để chuyển đổi các cột đối tượng giữ các đối tượng Python thành một loại gấu trúc nếu có thể.

Đọc để giải thích chi tiết hơn và sử dụng từng phương pháp này.


1. to_numeric()

Cách tốt nhất để chuyển đổi một hoặc nhiều cột của DataFrame thành các giá trị số là sử dụng pandas.to_numeric().

Hàm này sẽ cố gắng thay đổi các đối tượng không phải là số (chẳng hạn như chuỗi) thành số nguyên hoặc số dấu phẩy động nếu thích hợp.

Sử dụng cơ bản

Đầu vào to_numeric()là một Sê-ri hoặc một cột của Khung dữ liệu.

>>> s = pd.Series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values
>>> s
0      8
1      6
2    7.5
3      3
4    0.9
dtype: object

>>> pd.to_numeric(s) # convert everything to float values
0    8.0
1    6.0
2    7.5
3    3.0
4    0.9
dtype: float64

Như bạn có thể thấy, một Series mới được trả về. Hãy nhớ gán đầu ra này cho một biến hoặc tên cột để tiếp tục sử dụng nó:

# convert Series
my_series = pd.to_numeric(my_series)

# convert column "a" of a DataFrame
df["a"] = pd.to_numeric(df["a"])

Bạn cũng có thể sử dụng nó để chuyển đổi nhiều cột của DataFrame thông qua apply()phương thức:

# convert all columns of DataFrame
df = df.apply(pd.to_numeric) # convert all columns of DataFrame

# convert just columns "a" and "b"
df[["a", "b"]] = df[["a", "b"]].apply(pd.to_numeric)

Miễn là tất cả các giá trị của bạn có thể được chuyển đổi, đó có thể là tất cả những gì bạn cần.

Xử lý lỗi

Nhưng nếu một số giá trị không thể được chuyển đổi thành một loại số thì sao?

to_numeric()cũng có một errorsđối số từ khóa cho phép bạn buộc các giá trị không phải là số NaNhoặc đơn giản là bỏ qua các cột có chứa các giá trị này.

Dưới đây là một ví dụ sử dụng Chuỗi chuỗi scó dtype đối tượng:

>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])
>>> s
0         1
1         2
2       4.7
3    pandas
4        10
dtype: object

Hành vi mặc định là nâng cao nếu nó không thể chuyển đổi một giá trị. Trong trường hợp này, nó không thể đối phó với chuỗi 'gấu trúc':

>>> pd.to_numeric(s) # or pd.to_numeric(s, errors='raise')
ValueError: Unable to parse string

Thay vì thất bại, chúng tôi có thể muốn 'gấu trúc' được coi là một giá trị số bị thiếu / xấu. Chúng tôi có thể ép buộc các giá trị không hợp lệ NaNnhư sau bằng cách sử dụng errorsđối số từ khóa:

>>> pd.to_numeric(s, errors='coerce')
0     1.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

Tùy chọn thứ ba errorschỉ là bỏ qua thao tác nếu gặp phải giá trị không hợp lệ:

>>> pd.to_numeric(s, errors='ignore')
# the original Series is returned untouched

Tùy chọn cuối cùng này đặc biệt hữu ích khi bạn muốn chuyển đổi toàn bộ DataFrame của mình, nhưng không biết cột nào của chúng tôi có thể được chuyển đổi đáng tin cậy thành một loại số. Trong trường hợp đó chỉ cần viết:

df.apply(pd.to_numeric, errors='ignore')

Hàm này sẽ được áp dụng cho từng cột của DataFrame. Các cột có thể được chuyển đổi thành một loại số sẽ được chuyển đổi, trong khi các cột không thể (ví dụ: chúng chứa các chuỗi hoặc ngày không có chữ số) sẽ được để lại một mình.

Buồn bã

Theo mặc định, chuyển đổi với to_numeric()sẽ cung cấp cho bạn một int64hoặc float64dtype (hoặc bất kỳ chiều rộng số nguyên nào có nguồn gốc từ nền tảng của bạn).

Đó thường là những gì bạn muốn, nhưng nếu bạn muốn tiết kiệm bộ nhớ và sử dụng một loại dtype nhỏ gọn hơn, như float32, hoặc int8?

to_numeric()cung cấp cho bạn tùy chọn để downcast thành 'số nguyên', 'đã ký', 'không dấu', 'float'. Đây là một ví dụ cho một loạt scác kiểu số nguyên đơn giản :

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Downcasting đến 'số nguyên' sử dụng số nguyên nhỏ nhất có thể có thể chứa các giá trị:

>>> pd.to_numeric(s, downcast='integer')
0    1
1    2
2   -7
dtype: int8

Downcasting để 'float' tương tự chọn một kiểu nổi nhỏ hơn bình thường:

>>> pd.to_numeric(s, downcast='float')
0    1.0
1    2.0
2   -7.0
dtype: float32

2. astype()

Các astype()phương pháp cho phép bạn được rõ ràng về các dtype bạn muốn DataFrame hay Series của bạn để có. Nó rất linh hoạt ở chỗ bạn có thể thử và đi từ loại này sang loại khác.

Sử dụng cơ bản

Chỉ cần chọn một loại: bạn có thể sử dụng một loại dtype NumPy (ví dụ np.int16), một số loại Python (ví dụ bool) hoặc các loại dành riêng cho gấu trúc (như loại dtype phân loại).

Gọi phương thức trên đối tượng bạn muốn chuyển đổi và astype()sẽ thử và chuyển đổi nó cho bạn:

# convert all DataFrame columns to the int64 dtype
df = df.astype(int)

# convert column "a" to int64 dtype and "b" to complex type
df = df.astype({"a": int, "b": complex})

# convert Series to float16 type
s = s.astype(np.float16)

# convert Series to Python strings
s = s.astype(str)

# convert Series to categorical type - see docs for more details
s = s.astype('category')

Lưu ý rằng tôi đã nói "thử" - nếu astype()không biết cách chuyển đổi giá trị trong Sê-ri hoặc Khung dữ liệu, nó sẽ phát sinh lỗi. Ví dụ: nếu bạn có một NaNhoặc infgiá trị, bạn sẽ gặp lỗi khi chuyển đổi nó thành số nguyên.

Kể từ gấu trúc 0.20.0, lỗi này có thể được loại bỏ bằng cách vượt qua errors='ignore'. Đối tượng ban đầu của bạn sẽ được trả lại không bị ảnh hưởng.

Hãy cẩn thận

astype()là mạnh mẽ, nhưng đôi khi nó sẽ chuyển đổi các giá trị "không chính xác". Ví dụ:

>>> s = pd.Series([1, 2, -7])
>>> s
0    1
1    2
2   -7
dtype: int64

Đây là các số nguyên nhỏ, vậy làm thế nào về việc chuyển đổi sang loại 8 bit không dấu để tiết kiệm bộ nhớ?

>>> s.astype(np.uint8)
0      1
1      2
2    249
dtype: uint8

Việc chuyển đổi đã hoạt động, nhưng -7 đã được bao quanh để trở thành 249 (tức là 2 8 - 7)!

pd.to_numeric(s, downcast='unsigned')Thay vào đó, cố gắng để downcast sử dụng có thể giúp ngăn ngừa lỗi này.


3. infer_objects()

Phiên bản 0.21.0 của gấu trúc đã giới thiệu phương thức infer_objects()chuyển đổi các cột của DataFrame có kiểu dữ liệu đối tượng thành một loại cụ thể hơn (chuyển đổi mềm).

Ví dụ: đây là một DataFrame có hai cột loại đối tượng. Một số giữ số nguyên thực tế và số còn lại giữ các chuỗi đại diện cho số nguyên:

>>> df = pd.DataFrame({'a': [7, 1, 5], 'b': ['3','2','1']}, dtype='object')
>>> df.dtypes
a    object
b    object
dtype: object

Sử dụng infer_objects(), bạn có thể thay đổi loại cột 'a' thành int64:

>>> df = df.infer_objects()
>>> df.dtypes
a     int64
b    object
dtype: object

Cột 'b' đã bị bỏ lại một mình vì các giá trị của nó là các chuỗi, không phải là số nguyên. Nếu bạn muốn thử và buộc chuyển đổi cả hai cột thành một kiểu số nguyên, bạn có thể sử dụng df.astype(int)thay thế.


8
Ngoài ra, không giống như .astype (float), điều này sẽ chuyển đổi chuỗi thành NaN thay vì gây ra lỗi
Rob

11
.convert_objectsbị tước quyền kể từ khi 0.17- sử dụng df.to_numericthay thế
Matti Lyra

4
Cảm ơn - Tôi nên cập nhật câu trả lời này. Có thể đáng lưu ý rằng pd.to_numericvà các phương thức đồng hành của nó sẽ chỉ hoạt động trên một cột tại một thời điểm, không giống như convert_objects. Thảo luận về một chức năng thay thế trong API dường như đang diễn ra ; Tôi hy vọng một phương thức hoạt động trên toàn bộ DataFrame sẽ vẫn còn vì nó rất hữu ích.
Alex Riley

Cách tốt nhất để bạn chuyển đổi tất cả các cột hiện đang nói int64int32gì?
RoyalTS

4
@RoyaltyTS: có lẽ tốt nhất để sử dụng astype(như trong câu trả lời khác), tức là .astype(numpy.int32).
Alex Riley

447

Còn cái này thì sao?

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['one', 'two', 'three'])
df
Out[16]: 
  one  two three
0   a  1.2   4.2
1   b   70  0.03
2   x    5     0

df.dtypes
Out[17]: 
one      object
two      object
three    object

df[['two', 'three']] = df[['two', 'three']].astype(float)

df.dtypes
Out[19]: 
one       object
two      float64
three    float64

10
Đúng! pd.DataFramecó một dtypeđối số có thể cho phép bạn làm w / bạn đang tìm kiếm. df = pd.DataFrame (a, Cột = ['một', 'hai', 'ba'], dtype = float) Trong [2]: df.dtypes Out [2]: một đối tượng hai float64 ba float64 dtype: object
hernamesbarbara

17
Khi tôi cố gắng theo đề nghị, tôi nhận được một cảnh báo SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame. Try using .loc[row_index,col_indexer] = value instead. Điều này có thể đã được giới thiệu trong một phiên bản mới hơn của gấu trúc và kết quả là tôi không thấy có gì sai, nhưng tôi chỉ tự hỏi cảnh báo này là gì. Bất kỳ ý tưởng?
màu cam

2
@orange cảnh báo là để cảnh báo người dùng về hành vi có thể gây nhầm lẫn với các hoạt động bị xiềng xích và với gấu trúc trả lại các bản sao thay vì chỉnh sửa các tệp dữ liệu. xem stackoverflow.com/questions/20625582/ và liên quan.
A.Wan

19
Đó là một phương pháp tốt, nhưng nó không hoạt động khi có NaN trong một cột. Không biết tại sao NaN chỉ không thể ở lại NaN khi chuyển float sang int:ValueError: Cannot convert NA to integer
Vitaly Isaev

7
@GillBates có, trong một từ điển. df = pd.DataFrame(a, columns=['one', 'two', 'three'], dtype={'one': str, 'two': int, 'three': float}). Tôi đang gặp khó khăn trong việc tìm kiếm đặc điểm kỹ thuật cho các giá trị "dtype" được chấp nhận. Một danh sách sẽ là tốt đẹp (hiện tại tôi làm dict(enumerate(my_list))).
FichteFoll 7/07/2016

39

mã dưới đây sẽ thay đổi kiểu dữ liệu của cột.

df[['col.name1', 'col.name2'...]] = df[['col.name1', 'col.name2'..]].astype('data_type')

thay cho kiểu dữ liệu, bạn có thể cung cấp kiểu dữ liệu của mình. Bạn muốn gì như str, float, int, v.v.


Xin lưu ý rằng khi áp dụng điều này trên một cột có chứa các chuỗi `` `'True'` `` và `` `'false'` `` bằng cách sử dụng data_type bool, mọi thứ được thay đổi thành True.
H. Vabri

Tùy chọn này bạn cũng có thể chuyển đổi thành loại "thể loại"
Neves

17

Khi tôi chỉ cần xác định các cột cụ thể và tôi muốn rõ ràng, tôi đã sử dụng (theo VỊ TRÍ DOCS ):

dataframe = dataframe.astype({'col_name_1':'int','col_name_2':'float64', etc. ...})

Vì vậy, bằng cách sử dụng câu hỏi ban đầu, nhưng cung cấp tên cột cho nó ...

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col_name_1', 'col_name_2', 'col_name_3'])
df = df.astype({'col_name_2':'float64', 'col_name_3':'float64'})

15

Đây là một hàm lấy tham số DataFrame và danh sách các cột và ép tất cả dữ liệu trong các cột thành số.

# df is the DataFrame, and column_list is a list of columns as strings (e.g ["col1","col2","col3"])
# dependencies: pandas

def coerce_df_columns_to_numeric(df, column_list):
    df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')

Vì vậy, ví dụ của bạn:

import pandas as pd

def coerce_df_columns_to_numeric(df, column_list):
    df[column_list] = df[column_list].apply(pd.to_numeric, errors='coerce')

a = [['a', '1.2', '4.2'], ['b', '70', '0.03'], ['x', '5', '0']]
df = pd.DataFrame(a, columns=['col1','col2','col3'])

coerce_df_columns_to_numeric(df, ['col2','col3'])

Điều gì nếu bạn muốn sử dụng chỉ mục cột thay vì tên cột?
jvalenti

8

Làm thế nào về việc tạo hai datafram, mỗi loại có các kiểu dữ liệu khác nhau cho các cột của chúng và sau đó nối chúng lại với nhau?

d1 = pd.DataFrame(columns=[ 'float_column' ], dtype=float)
d1 = d1.append(pd.DataFrame(columns=[ 'string_column' ], dtype=str))

Các kết quả

In[8}:  d1.dtypes
Out[8]: 
float_column     float64
string_column     object
dtype: object

Sau khi khung dữ liệu được tạo, bạn có thể điền vào đó các biến dấu phẩy động trong cột thứ 1 và chuỗi (hoặc bất kỳ loại dữ liệu nào bạn muốn) trong cột thứ 2.


4

gấu trúc> = 1.0

Dưới đây là biểu đồ tóm tắt một số chuyển đổi quan trọng nhất trong gấu trúc.

nhập mô tả hình ảnh ở đây

Chuyển đổi thành chuỗi là tầm thường .astype(str)và không được hiển thị trong hình.

Chuyển đổi "Cứng" so với "Mềm"

Lưu ý rằng "chuyển đổi" trong ngữ cảnh này có thể đề cập đến việc chuyển đổi dữ liệu văn bản thành loại dữ liệu thực tế của chúng (chuyển đổi cứng) hoặc suy ra các loại dữ liệu phù hợp hơn cho dữ liệu trong các cột đối tượng (chuyển đổi mềm). Để minh họa sự khác biệt, hãy xem

df = pd.DataFrame({'a': ['1', '2', '3'], 'b': [4, 5, 6]}, dtype=object)
df.dtypes                                                                  

a    object
b    object
dtype: object

# Actually converts string to numeric - hard conversion
df.apply(pd.to_numeric).dtypes                                             

a    int64
b    int64
dtype: object

# Infers better data types for object data - soft conversion
df.infer_objects().dtypes                                                  

a    object  # no change
b     int64
dtype: object

# Same as infer_objects, but converts to equivalent ExtensionType
df.convert_dtypes().dtypes                                                     

1

Tôi nghĩ rằng tôi có cùng một vấn đề nhưng thực sự tôi có một sự khác biệt nhỏ làm cho vấn đề dễ giải quyết hơn. Đối với những người khác đang xem câu hỏi này, đáng để kiểm tra định dạng của danh sách đầu vào của bạn. Trong trường hợp của tôi, các số ban đầu nổi không phải là chuỗi như trong câu hỏi:

a = [['a', 1.2, 4.2], ['b', 70, 0.03], ['x', 5, 0]]

nhưng bằng cách xử lý danh sách quá nhiều trước khi tạo dataframe, tôi mất các kiểu và mọi thứ trở thành một chuỗi.

Tạo khung dữ liệu thông qua một mảng numpy

df = pd.DataFrame(np.array(a))

df
Out[5]: 
   0    1     2
0  a  1.2   4.2
1  b   70  0.03
2  x    5     0

df[1].dtype
Out[7]: dtype('O')

đưa ra khung dữ liệu giống như trong câu hỏi, trong đó các mục trong cột 1 và 2 được coi là chuỗi. Tuy nhiên

df = pd.DataFrame(a)

df
Out[10]: 
   0     1     2
0  a   1.2  4.20
1  b  70.0  0.03
2  x   5.0  0.00

df[1].dtype
Out[11]: dtype('float64')

thực sự đưa ra một khung dữ liệu với các cột ở định dạng đúng


0

Bắt đầu pandas 1.0.0, chúng tôi có pandas.DataFrame.convert_dtypes. Bạn thậm chí có thể kiểm soát những loại để chuyển đổi!

In [40]: df = pd.DataFrame(
    ...:     {
    ...:         "a": pd.Series([1, 2, 3], dtype=np.dtype("int32")),
    ...:         "b": pd.Series(["x", "y", "z"], dtype=np.dtype("O")),
    ...:         "c": pd.Series([True, False, np.nan], dtype=np.dtype("O")),
    ...:         "d": pd.Series(["h", "i", np.nan], dtype=np.dtype("O")),
    ...:         "e": pd.Series([10, np.nan, 20], dtype=np.dtype("float")),
    ...:         "f": pd.Series([np.nan, 100.5, 200], dtype=np.dtype("float")),
    ...:     }
    ...: )

In [41]: dff = df.copy()

In [42]: df 
Out[42]: 
   a  b      c    d     e      f
0  1  x   True    h  10.0    NaN
1  2  y  False    i   NaN  100.5
2  3  z    NaN  NaN  20.0  200.0

In [43]: df.dtypes
Out[43]: 
a      int32
b     object
c     object
d     object
e    float64
f    float64
dtype: object

In [44]: df = df.convert_dtypes()

In [45]: df.dtypes
Out[45]: 
a      Int32
b     string
c    boolean
d     string
e      Int64
f    float64
dtype: object

In [46]: dff = dff.convert_dtypes(convert_boolean = False)

In [47]: dff.dtypes
Out[47]: 
a      Int32
b     string
c     object
d     string
e      Int64
f    float64
dtype: object
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.