更改熊猫中的列类型

我从列表列表中创建了一个DataFrame:

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

如何将列转换为特定类型?在这种情况下,我想将列2和3转换为浮点数。

有没有办法在转换为DataFrame时指定类型?或者最好先创建DataFrame,然后循环遍历列以更改每列的类型?理想情况下,我希望以动态方式执行此操作,因为可以有数百个列,并且我不想确切指定哪些列属于哪种类型。我只能保证每列包含相同类型的值。

3191944 次浏览

使用这个:

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 three0   a  1.2   4.21   b   70  0.032   x    5     0
df.dtypes
Out[17]:one      objecttwo      objectthree    object
df[['two', 'three']] = df[['two', 'three']].astype(float)
df.dtypes
Out[19]:one       objecttwo      float64three    float64

在熊猫中转换类型有四个主要选项:

  1. #0-提供安全地将非数字类型(例如字符串)转换为合适的数字类型的功能。(另请参阅#1#2。)

  2. #0-将(几乎)任何类型转换为(几乎)任何其他类型(即使这样做不一定明智)。还允许您转换为分类类型(非常有用)。

  3. #0-如果可能,将包含Python对象的对象列转换为熊猫类型的实用方法。

  4. #0-将DataFrame列转换为支持pd.NA的“最佳”dtype(熊猫对象表示缺失值)。

请继续阅读这些方法的更详细解释和用法。


1.to_numeric()

将DataFrame的一个或多个列转换为数值的最佳方法是使用#0

此函数将尝试根据需要将非数字对象(例如字符串)更改为整数或浮点数。

基本用法

#0的输入是一个系列或一个DataFrame的单列。

>>> s = pd.Series(["8", 6, "7.5", 3, "0.9"]) # mixed string and numeric values>>> s0      81      62    7.53      34    0.9dtype: object
>>> pd.to_numeric(s) # convert everything to float values0    8.01    6.02    7.53    3.04    0.9dtype: float64

如您所见,返回了一个新的Series。请记住将此输出分配给变量或列名以继续使用它:

# convert Seriesmy_series = pd.to_numeric(my_series)
# convert column "a" of a DataFramedf["a"] = pd.to_numeric(df["a"])

您还可以使用它通过#0方法转换DataFrame的多列:

# convert all columns of DataFramedf = 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)

只要你的价值观都可以转换,这可能就是你所需要的。

错误处理

但是,如果某些值不能转换为数字类型怎么办?

#0还采用errors关键字参数,允许您强制非数字值为NaN,或者简单地忽略包含这些值的列。

这是一个使用具有对象dtype的字符串s系列的示例:

>>> s = pd.Series(['1', '2', '4.7', 'pandas', '10'])>>> s0         11         22       4.73    pandas4        10dtype: object

默认行为是如果它无法转换值则引发。在这种情况下,它无法处理字符串“熊猫”:

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

为了避免失败,我们可能希望“熊猫”被视为缺失/错误的数值。我们可以使用errors关键字参数将无效值强制为NaN,如下所示:

>>> pd.to_numeric(s, errors='coerce')0     1.01     2.02     4.73     NaN4    10.0dtype: float64

errors的第三个选项是在遇到无效值时忽略操作:

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

最后一个选项对于转换整个DataFrame特别有用,但不知道我们的哪些列可以可靠地转换为数字类型。在这种情况下,只需编写:

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

该函数将应用于DataFrame的每一列。可以转换为数字类型的列将被转换,而不能(例如它们包含非数字字符串或日期)的列将被单独保留。

下行

默认情况下,使用#0的转换将为您提供int64float64 dtype(或您的平台原生的任何整数宽度)。

这通常是你想要的,但是如果你想节省一些内存并使用更紧凑的dtype,比如float32int8呢?

#0为您提供了向下转换为'integer''signed''unsigned''float'的选项。这是一个简单的整数类型系列s的示例:

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

向下转换到'integer'使用可以保存值的最小整数:

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

向下转换到'float'类似地选择比正常浮动类型小的类型:

>>> pd.to_numeric(s, downcast='float')0    1.01    2.02   -7.0dtype: float32

2.astype()

#0方法使您能够明确您希望DataFrame或Series拥有的dtype。它非常通用,您可以尝试从一种类型切换到任何其他类型。

基本用法

只需选择一个类型:您可以使用NumPy dtype(例如np.int16)、一些Python类型(例如bool)或特定于熊猫的类型(如分类dtype)。

在您要转换的对象上调用该方法,#0将尝试为您转换它:

# convert all DataFrame columns to the int64 dtypedf = df.astype(int)
# convert column "a" to int64 dtype and "b" to complex typedf = df.astype({"a": int, "b": complex})
# convert Series to float16 types = s.astype(np.float16)
# convert Series to Python stringss = s.astype(str)
# convert Series to categorical type - see docs for more detailss = s.astype('category')

请注意,我说了“try”-如果#0不知道如何转换Series或DataFrame中的值,它将引发错误。例如,如果您有NaNinf值,您将在尝试将其转换为整数时收到错误。

从熊猫0.20.0开始,这个错误可以通过传递errors='ignore'来抑制。你的原始对象将原封不动地返回。

小心点

#0功能强大,但它有时会“错误地”转换值。例如:

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

这些是小整数,那么如何转换为无符号8位类型以节省内存?

>>> s.astype(np.uint8)0      11      22    249dtype: uint8

转换工作,但-7被包裹成249(即28-7)!

尝试使用pd.to_numeric(s, downcast='unsigned')向下转换可能有助于防止此错误。


3.infer_objects()

Pandas的0.21.0版引入了方法#0,用于将具有对象数据类型的DataFrame列转换为更具体的类型(软转换)。

例如,这是一个具有两列对象类型的DataFrame。一个包含实际整数,另一个包含表示整数的字符串:

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

使用#0,您可以将列'a'的类型更改为int64:

>>> df = df.infer_objects()>>> df.dtypesa     int64b    objectdtype: object

列'b'被单独保留,因为它的值是字符串,而不是整数。如果您想强制两列都为整数类型,您可以使用df.astype(int)代替。


4.convert_dtypes()

1.0及以上版本包含一个方法#0,用于将Series和DataFrame列转换为支持pd.NA缺失值的最佳dtype。

这里的“最佳可能”表示最适合保存值的类型。例如,这是一个熊猫整数类型,如果所有值都是整数(或缺失值):Python整数对象的对象列被转换为Int64,NumPyint32值的列将成为熊猫dtypeInt32

使用我们的object DataFramedf,我们得到以下结果:

>>> df.convert_dtypes().dtypesa     Int64b    stringdtype: object

由于列'a'保存了整数值,因此它被转换为Int64类型(与int64不同,它能够保存缺失值)。

列'b'包含字符串对象,因此更改为熊猫'string dtype。

默认情况下,此方法将从每列中的对象值推断类型。我们可以通过传递infer_objects=False来更改它:

>>> df.convert_dtypes(infer_objects=False).dtypesa    objectb    stringdtype: object

现在列'a'仍然是一个对象列:熊猫知道它可以被描述为一个'整数'列(内部运行#0),但没有准确推断它应该有什么整数dtype,所以没有转换它。列'b'再次被转换为'string'dtype,因为它被识别为保存'string'值。

这是一个函数,它将DataFrame和列列表作为参数,并将列中的所有数据强制转换为数字。

# 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')

对于你的例子:

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'])

创建两个数据帧,每个数据帧的列都有不同的数据类型,然后将它们附加在一起:

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

搜索结果

In[8}:  d1.dtypesOut[8]:float_column     float64string_column     objectdtype: object

创建数据帧后,您可以在第1列中使用浮点变量填充它,在第2列中使用字符串(或您想要的任何数据类型)填充它。

下面的代码将更改列的数据类型。

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

代替数据类型,您可以为您的数据类型提供您想要的数据类型,例如str、浮点数、int等。

当我只需要指定特定列,并且我想明确表示时,我使用了(perpandas.DataFrame.astype):

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

所以,使用原始问题,但为其提供列名…

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'})

我以为我也有同样的问题,但实际上我有一个细微的区别,这使得问题更容易解决。对于其他人看这个问题,值得检查你的输入列表的格式。在我的情况下,数字最初是浮点数,而不是问题中的字符串:

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

但是在创建数据帧之前处理列表太多,我失去了类型,一切都变成了字符串。

通过NumPy数组创建数据帧:

df = pd.DataFrame(np.array(a))df
Out[5]:0    1     20  a  1.2   4.21  b   70  0.032  x    5     0
df[1].dtypeOut[7]: dtype('O')

给出与问题中相同的数据帧,其中第1列和第2列中的条目被视为字符串。但是这样做

df = pd.DataFrame(a)
dfOut[10]:0     1     20  a   1.2  4.201  b  70.0  0.032  x   5.0  0.00
df[1].dtypeOut[11]: dtype('float64')

确实给出了具有正确格式的列的数据帧。

熊猫>=1.0

这张图表总结了熊猫的一些最重要的转化。

在此处输入图片描述

转换为字符串是微不足道的.astype(str),图中没有显示。

“硬”与“软”转换

请注意,在此上下文中的“转换”可以指将文本数据转换为其实际数据类型(硬转换),也可以指为对象列中的数据推断更合适的数据类型(软转换)

df = pd.DataFrame({'a': ['1', '2', '3'], 'b': [4, 5, 6]}, dtype=object)df.dtypes
a    objectb    objectdtype: object
# Actually converts string to numeric - hard conversiondf.apply(pd.to_numeric).dtypes
a    int64b    int64dtype: object
# Infers better data types for object data - soft conversiondf.infer_objects().dtypes
a    object  # no changeb     int64dtype: object
# Same as infer_objects, but converts to equivalent ExtensionTypedf.convert_dtypes().dtypes

从熊猫1.0.0开始,我们有pandas.DataFrame.convert_dtypes。您甚至可以控制要转换的类型!

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]: dfOut[42]:a  b      c    d     e      f0  1  x   True    h  10.0    NaN1  2  y  False    i   NaN  100.52  3  z    NaN  NaN  20.0  200.0
In [43]: df.dtypesOut[43]:a      int32b     objectc     objectd     objecte    float64f    float64dtype: object
In [44]: df = df.convert_dtypes()
In [45]: df.dtypesOut[45]:a      Int32b     stringc    booleand     stringe      Int64f    float64dtype: object
In [46]: dff = dff.convert_dtypes(convert_boolean = False)
In [47]: dff.dtypesOut[47]:a      Int32b     stringc     objectd     stringe      Int64f    float64dtype: object

df.info()给出了temp的初始数据类型,即Float64

 #   Column  Non-Null Count  Dtype---  ------  --------------  -----0   date    132 non-null    object1   temp    132 non-null    float64

现在,使用此代码将数据类型更改为int64:

df['temp'] = df['temp'].astype('int64')

如果你再次df.info(),你会看到:

  #   Column  Non-Null Count  Dtype---  ------  --------------  -----0   date    132 non-null    object1   temp    132 non-null    int64

这表明您已成功更改列临时的数据类型。编码愉快!

df = df.astype({"columnname": str})

#例如-将列类型更改为字符串#df是你的数据框

如果您有各种对象列,例如由74个对象列和2个Int列组成的Dataframe,其中每个值都有表示单位的字母:

import pandas as pdimport numpy as np
dataurl = 'https://raw.githubusercontent.com/RubenGavidia/Pandas_Portfolio.py/main/Wes_Mckinney.py/nutrition.csv'nutrition = pd.read_csv(dataurl,index_col=[0])nutrition.head(3)

输出:

    name    serving_size    calories    total_fat    saturated_fat    cholesterol    sodium    choline    folate    folic_acid    ...    fat    saturated_fatty_acids    monounsaturated_fatty_acids    polyunsaturated_fatty_acids    fatty_acids_total_trans    alcohol    ash    caffeine    theobromine    water0    Cornstarch    100 g    381    0.1g    NaN    0    9.00 mg    0.4 mg    0.00 mcg    0.00 mcg    ...    0.05 g    0.009 g    0.016 g    0.025 g    0.00 mg    0.0 g    0.09 g    0.00 mg    0.00 mg    8.32 g1    Nuts, pecans    100 g    691    72g    6.2g    0    0.00 mg    40.5 mg    22.00 mcg    0.00 mcg    ...    71.97 g    6.180 g    40.801 g    21.614 g    0.00 mg    0.0 g    1.49 g    0.00 mg    0.00 mg    3.52 g2    Eggplant, raw    100 g    25    0.2g    NaN    0    2.00 mg    6.9 mg    22.00 mcg    0.00 mcg    ...    0.18 g    0.034 g    0.016 g    0.076 g    0.00 mg    0.0 g    0.66 g    0.00 mg    0.00 mg    92.30 g3 rows × 76 columns
nutrition.dtypesname             objectserving_size     objectcalories          int64total_fat        objectsaturated_fat    object...alcohol          objectash              objectcaffeine         objecttheobromine      objectwater            objectLength: 76, dtype: object
nutrition.dtypes.value_counts()object    74int64      2dtype: int64

将所有列转换为数字的一个好方法是使用正则表达式替换无单位和astype(浮点数)将列数据类型更改为浮点数:

nutrition.index = pd.RangeIndex(start = 0, stop = 8789, step= 1)nutrition.set_index('name',inplace = True)nutrition.replace('[a-zA-Z]','', regex= True, inplace=True)nutrition=nutrition.astype(float)nutrition.head(3)

输出:

serving_size    calories    total_fat    saturated_fat    cholesterol    sodium    choline    folate    folic_acid    niacin    ...    fat    saturated_fatty_acids    monounsaturated_fatty_acids    polyunsaturated_fatty_acids    fatty_acids_total_trans    alcohol    ash    caffeine    theobromine    waternameCornstarch    100.0    381.0    0.1    NaN    0.0    9.0    0.4    0.0    0.0    0.000    ...    0.05    0.009    0.016    0.025    0.0    0.0    0.09    0.0    0.0    8.32Nuts, pecans    100.0    691.0    72.0    6.2    0.0    0.0    40.5    22.0    0.0    1.167    ...    71.97    6.180    40.801    21.614    0.0    0.0    1.49    0.0    0.0    3.52Eggplant, raw    100.0    25.0    0.2    NaN    0.0    2.0    6.9    22.0    0.0    0.649    ...    0.18    0.034    0.016    0.076    0.0    0.0    0.66    0.0    0.0    92.303 rows × 75 columns
nutrition.dtypesserving_size     float64calories         float64total_fat        float64saturated_fat    float64cholesterol      float64...alcohol          float64ash              float64caffeine         float64theobromine      float64water            float64Length: 75, dtype: object
nutrition.dtypes.value_counts()float64    75dtype: int64

现在数据集是干净的,您只能使用regex和astype()对这个Dataframe进行数值操作。

如果您想收集单位并粘贴在标题上,如cholesterol_mg,您可以使用以下代码:

nutrition.index = pd.RangeIndex(start = 0, stop = 8789, step= 1)nutrition.set_index('name',inplace = True)nutrition.astype(str).replace('[^a-zA-Z]','', regex= True)units = nutrition.astype(str).replace('[^a-zA-Z]','', regex= True)units = units.mode()units = units.replace('', np.nan).dropna(axis=1)mapper = { k: k + "_" + units[k].at[0] for k in units}nutrition.rename(columns=mapper, inplace=True)nutrition.replace('[a-zA-Z]','', regex= True, inplace=True)nutrition=nutrition.astype(float)

有没有办法在转换为DataFrame时指定类型?

是的。其他答案在创建DataFrame后转换dtype,但我们可以在创建时指定类型。根据输入格式使用DataFrame.from_recordsread_csv(dtype=...)

后者有时需要使用大数据避免内存错误


1.#0

从所需列类型的结构化数组创建DataFrame:

x = [['foo', '1.2', '70'], ['bar', '4.2', '5']]
df = pd.DataFrame.from_records(np.array([tuple(row) for row in x], # pass a list-of-tuples (x can be a list-of-lists or 2D array)'object, float, int'       # define the column types))

输出:

>>> df.dtypes# f0     object# f1    float64# f2      int64# dtype: object

2.#0

如果您正在从文件中读取数据,请使用read_csvdtype参数在加载时设置列类型。

例如,这里我们读取30M行,其中rating为8位整数,genre为分类:

lines = '''foo,biography,5bar,crime,4baz,fantasy,3qux,history,2quux,horror,1'''columns = ['name', 'genre', 'rating']csv = io.StringIO(lines * 6_000_000) # 30M lines
df = pd.read_csv(csv, names=columns, dtype={'rating': 'int8', 'genre': 'category'})

在这种情况下,我们在加载时将内存使用量减半:

>>> df.info(memory_usage='deep')# memory usage: 1.8 GB
>>> pd.read_csv(io.StringIO(lines * 6_000_000)).info(memory_usage='deep')# memory usage: 3.7 GB

这是使用大数据避免内存错误的一种方法。由于我们可能没有足够的内存来加载默认类型的数据,因此并不总是可以更改dtype之后加载。

我也有同样的问题。

我找不到任何令人满意的解决方案。我的解决方案只是将这些浮点数转换为str并以这种方式删除“.0”。

在我的例子中,我只是将其应用于第一列:

firstCol = list(df.columns)[0]df[firstCol] = df[firstCol].fillna('').astype(str).apply(lambda x: x.replace('.0', ''))