如何在pandas DataFrame中按列设置数据类型

54

我想将一些数据导入到 pandas DataFrame 中,并在导入时为每个列分配数据类型。 我希望能够对具有许多不同列的较大数据集执行此操作,但作为示例:

myarray = np.random.randint(0,5,size=(2,2))
mydf = pd.DataFrame(myarray,columns=['a','b'], dtype=[float,int])
mydf.dtypes

结果为:

类型错误:数据类型无法识别

我尝试了一些其他方法,例如:

mydf = pd.DataFrame(myarray,columns=['a','b'], dtype={'a': int})

类型错误:'type'对象没有len()

如果我使用dtype=(float,int),它会将浮点格式应用于两个列。

最终我希望能够像传递列名列表那样传递数据类型列表。


dtype 的参数应该是一个有效的 numpy dtype(不支持结构化 dtype),因此列表或字典将无法使用。一种可能的方法是分别对每列进行 astype。或者先创建一个结构化的 numpy 数组,然后将其提供给 DataFrame。 - joris
3
我知道我可以在循环中分别分配每个变量,但我很惊讶 dtype= 没有足够的灵活性来容纳一个列表。不过还是谢谢你的答案,确认一下感觉很好 :) - Chris
4
这是一个开放问题,可以通过提交请求来解决(如果您想提交请求的话),链接为https://github.com/pydata/pandas/issues/4464。 - Jeff
只是为了好玩:有人使用read_csv绕过了这个问题:https://dev59.com/klkT5IYBdhLWcg3wfvin#38524255 :D - krassowski
6个回答

28

我刚遇到这个问题,而且 pandas 的问题仍未解决,所以我要发布我的解决方法。假设 df 是我的 DataFrame,dtype 是将列名映射到类型的字典:

for k, v in dtype.items():
    df[k] = df[k].astype(v)

(注意:在Python 2中使用dtype.iteritems())

参考资料:


4
为了使这个工作起来,我需要使用 for k, v in dtype.iteritems(): - Khris
4
这可以改为 df.astype(dtype) - DJK
1
这种方法在某些类型转换方面会失败得很惨:https://dev59.com/PbHma4cB1Zd3GeqPLGus - user48956

13
你可以尝试向DataFrame构造函数传递一个Series对象的字典-这将使你对创建过程具有更精细的控制,并且应该能够更清晰地理解正在发生的事情。 模板版本(data1可以是一个数组等):
df = pd.DataFrame({'column1':pd.Series(data1, dtype='type1'),
                   'column2':pd.Series(data2, dtype='type2')})

带有数据的示例:

df = pd.DataFrame({'A':pd.Series([1,2,3], dtype='int'),
                   'B':pd.Series([7,8,9], dtype='float')})

print (df)
   A  B
0  1  7.0
1  2  8.0
2  3  9.0

print (df.dtypes)
A     int32
B    float64
dtype: object

11

截至pandas版本0.24.2(当前稳定版),无法像文档中所述那样向DataFrame构造函数传递显式数据类型列表:

dtype : dtype, default None

    Data type to force. Only a single dtype is allowed. If None, infer

然而,dataframe类具有一种静态方法,允许您将numpy结构化数组转换为dataframe,因此您可以执行以下操作:

>>> myarray = np.random.randint(0,5,size=(2,2))
>>> record = np.array(map(tuple,myarray),dtype=[('a',np.float),('b',np.int)])
>>> mydf = pd.DataFrame.from_records(record)
>>> mydf.dtypes
a    float64
b      int64
dtype: object

2

在 Pandas 版本 1.5.3 中,可以传递显式数据类型:

import pandas as pd
data = (['Alex', 10],["Bob",12],["Clarke",11.05])
df = pd.DataFrame(data,columns=("Name", "Age"),dtype=(str, float))
print(df)

0
在较新版本的pandas(目前为2.X)中,有一种解决方案是将DataFrame.astype()传递一个字典,其中列名作为键,列值应该是字典中的值。
其他评论和答案表示,在过去的版本中可能不可行,但至少在2.X版本中可以实现。
df = pd.DataFrame(
    {'some_ints': [1, 2, 3], 'some_strs': ['a', 'b', 'c']},
    dtype={'some_ints': 'str', 'some_strs': 'str'}
)

df.dtypes.to_dict()

>>> {'some_ints': dtype('O'), 'some_strs': dtype('O')}

df = df.astype({'some_ints': 'int64', 'some_strs': 'str'})

df.dtypes.to_dict()

>>> {'some_ints': dtype('int64'), 'some_strs': dtype('O')}

如果您将可能导致类型转换的操作链接在一起,另一个可用的技巧是在df.dtypes.to_dict()的输出上调用.astype
示例:
df = (
    df
    .some_type_changing_method()
    .astype(df.dtypes.to_dict()
)

这将确保您在链接操作的首尾处使用相同的数据类型,如果无法转换类型(例如将NaN转换为整数),则会引发错误。

-3

在处理数据类型时,它们应该被传递为字符串。

例如,您遵循的后续方法应该修改为:

mydf = pd.DataFrame(myarray,columns=['a','b'], dtype={'a': 'int'})

而不是

mydf = pd.DataFrame(myarray,columns=['a','b'], dtype={'a': int})

dtype(int、float等)应该以字符串形式给出。

否则,作为替代方法(如果您不想以字符串形式传递)导入numpy as np并使用mydf = pd.DataFrame(myarray,columns=['a','b'], dtype={'a': np.int})


4
无法将字典传递给dtype参数。 - simon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接