ChatGPT解决这个技术问题 Extra ChatGPT

更改熊猫中的列类型

我想将表示为列表列表的表转换为 pandas DataFrame。作为一个极其简化的示例:

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

将列转换为适当类型的最佳方法是什么,在这种情况下,第 2 列和第 3 列转换为浮点数?有没有办法在转换为 DataFrame 时指定类型?还是先创建 DataFrame 然后遍历列以更改每列的类型更好?理想情况下,我想以动态方式执行此操作,因为可能有数百列,我不想准确指定哪些列属于哪种类型。我只能保证每一列都包含相同类型的值。


H
Henry Ecker

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

to_numeric() - 提供安全地将非数字类型(例如字符串)转换为合适的数字类型的功能。 (另请参阅 to_datetime() 和 to_timedelta()。) astype() - 将(几乎)任何类型转换为(几乎)任何其他类型(即使这样做不一定明智)。还允许您转换为分类类型(非常有用)。 infer_objects() - 如果可能的话,一种实用方法,用于将保存 Python 对象的对象列转换为 pandas 类型。 convert_dtypes() - 将 DataFrame 列转换为支持 pd.NA 的“最佳”dtype(pandas 的对象表示缺失值)。

请继续阅读以了解每种方法的更详细说明和用法。

1. to_numeric()

将 DataFrame 的一列或多列转换为数值的最佳方法是使用 pandas.to_numeric()

此函数将尝试将非数字对象(如字符串)更改为适当的整数或浮点数。

基本用法

to_numeric() 的输入是一个系列或 DataFrame 的单列。

>>> 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

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

# convert Series
my_series = pd.to_numeric(my_series)

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

您还可以通过 apply() 方法使用它来转换 DataFrame 的多个列:

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

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

错误处理

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

to_numeric() 还接受一个 errors 关键字参数,允许您将非数字值强制为 NaN,或者只是忽略包含这些值的列。

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

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

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

>>> 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.0
1     2.0
2     4.7
3     NaN
4    10.0
dtype: float64

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

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

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

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

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

垂头丧气

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

这通常是您想要的,但是如果您想节省一些内存并使用更紧凑的 dtype,例如 float32int8,该怎么办?

to_numeric() 让您可以选择向下转换为 'integer''signed''unsigned''float'。以下是整数类型的简单系列 s 的示例:

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

向下转换为 'integer' 使用可以容纳这些值的最小可能整数:

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

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

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

2. astype()

astype() 方法使您能够明确说明您希望 DataFrame 或 Series 具有的 dtype。它非常通用,您可以尝试从一种类型转换为任何其他类型。

基本用法

只需选择一种类型:您可以使用 NumPy dtype(例如 np.int16)、一些 Python 类型(例如 bool)或 pandas 特定的类型(例如 categorical dtype)。

调用您要转换的对象的方法,astype() 将尝试为您转换它:

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

请注意,我说的是“尝试” - 如果 astype() 不知道如何转换 Series 或 DataFrame 中的值,则会引发错误。例如,如果您有 NaNinf 值,则在尝试将其转换为整数时会出错。

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

当心

astype() 功能强大,但有时会“错误地”转换值。例如:

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

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

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

转换成功了,但是 -7 被环绕成 249(即 28 - 7)!

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

3. infer_objects()

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

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

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

使用 infer_objects(),您可以将列“a”的类型更改为 int64:

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

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

4. 转换_dtypes()

1.0 及更高版本包括一个方法 convert_dtypes(),用于将 Series 和 DataFrame 列转换为支持 pd.NA 缺失值的最佳数据类型。

这里“最好的”是指最适合保存这些值的类型。例如,这是一个 pandas 整数类型,如果所有值都是整数(或缺失值):Python 整数对象的对象列转换为 Int64,NumPy int32 值的列将成为 pandas dtype Int32

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

>>> df.convert_dtypes().dtypes                                             
a     Int64
b    string
dtype: object

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

列“b”包含字符串对象,因此已更改为 pandas 的 string dtype。

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

>>> df.convert_dtypes(infer_objects=False).dtypes                          
a    object
b    string
dtype: object

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


此外,与 .astype(float) 不同,这会将字符串转换为 NaN,而不是引发错误
0.17 起已弃用 .convert_objects - 改用 df.to_numeric
有没有办法在 astype()error=coerce
@fogx 不,没有。您可以refer here
J
Jay

这个怎么样?

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

是的! pd.DataFrame 有一个 dtype 参数,可以让您按照您的要求进行操作。 df = pd.DataFrame(a, columns=['one', 'two', 'three'], dtype=float) In [2]: df.dtypes Out[2]: 一个对象 两个 float64 三个 float64 dtype: object
当我按照建议尝试时,我收到警告 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。这可能是在较新版本的 pandas 中引入的,因此我没有发现任何问题,但我只是想知道这个警告是关于什么的。任何想法?
@orange 警告是提醒用户注意潜在的与链式操作混淆的行为,以及 pandas 返回的副本而不是编辑数据帧。请参阅 stackoverflow.com/questions/20625582/… 和相关内容。
这是一个很好的方法,但是当列中有 NaN 时它不起作用。不知道为什么 NaN 在将 float 转换为 int 时不能保持 NaN:ValueError: Cannot convert NA to integer
@GillBates 是的,在字典中。 df = pd.DataFrame(a, columns=['one', 'two', 'three'], dtype={'one': str, 'two': int, 'three': float})。不过,我很难找到可接受的“dtype”值的规范。一个列表会很好(目前我做dict(enumerate(my_list)))。
A
Akash Nayak

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

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

代替数据类型,您可以提供数据类型。您想要什么,例如 str、float、int 等。


请注意,当使用 data_type bool 将其应用于包含字符串 ``` 'True' ``` 和 ``` 'False' ``` 的列时,所有内容都会更改为 True
此选项您还可以转换为类型“类别”
T
Thom Ives

当我只需要指定特定列并且想要明确时,我使用过(每个 DOCS LOCATION):

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

H
Harry Stevens

这是一个函数,它接受一个 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'])

如果您想使用列索引而不是列名怎么办?
c
cs95

熊猫 >= 1.0

这是一张图表,总结了 pandas 中一些最重要的转换。

https://i.stack.imgur.com/tUcdp.jpg

到字符串的转换是微不足道的 .astype(str) 并且未在图中显示。

“硬”与“软”转换

请注意,此上下文中的“转换”可以指将文本数据转换为其实际数据类型(硬转换),或者为对象列中的数据推断更合适的数据类型(软转换)。为了说明差异,请看一下

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                                                     

M
MikeyE

如何创建两个数据框,每个数据框的列具有不同的数据类型,然后将它们附加在一起?

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

结果

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

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


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

#eg - 用于将列类型更改为字符串 #df 是您的数据框


根据 Flag Duplicate Answers on the same Question,此重复已被标记为版主。虽然这是一个答案,但它在 accepted answer 和其他答案中是 duplicates code。 SO 使用相同的解决方案保留许多答案并没有额外的价值,并且不需要为每个 type 提供一个示例。相反,赞成现有的答案。
k
kristianp

df.info() 为我们提供了 temp 的初始数据类型,即 float64

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

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

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

如果您再次执行 df.info(),您将看到:

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

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


我喜欢 df.info() 在最后一行中提供内存使用的方式。
S
Sohail

从 pandas 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]: 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

r
rubengavidia0x

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

import pandas as pd 
import 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 water
0   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 g
1   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 g
2   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 g
3 rows × 76 columns

nutrition.dtypes
name             object
serving_size     object
calories          int64
total_fat        object
saturated_fat    object
                  ...  
alcohol          object
ash              object
caffeine         object
theobromine      object
water            object
Length: 76, dtype: object

nutrition.dtypes.value_counts()
object    74
int64      2
dtype: int64

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

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 water
name                                                                                    
Cornstarch  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.32
Nuts, 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.52
Eggplant, 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.30
3 rows × 75 columns

nutrition.dtypes
serving_size     float64
calories         float64
total_fat        float64
saturated_fat    float64
cholesterol      float64
                  ...   
alcohol          float64
ash              float64
caffeine         float64
theobromine      float64
water            float64
Length: 75, dtype: object

nutrition.dtypes.value_counts()
float64    75
dtype: 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)

t
tdy

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

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

后者有时是 avoid memory errors with big data 所必需的。

1.DataFrame.from_records

从所需列类型的 structured array 创建 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. read_csv(dtype=...)

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

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

lines = '''
foo,biography,5
bar,crime,4
baz,fantasy,3
qux,history,2
quux,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

这是avoid memory errors with big data的一种方法。 加载后更改数据类型并不总是可能的,因为我们可能没有足够的内存来首先加载默认类型的数据。


S
SarahD

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

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     2
0  a  1.2   4.2
1  b   70  0.03
2  x    5     0

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

给出与问题相同的数据框,其中第 1 列和第 2 列中的条目被视为字符串。然而做

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

实际上确实给出了一个数据框,其中的列格式正确


L
Laurent T

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

就我而言,我只是将其应用于第一列

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

希望对某人有所帮助!