为pandas数据框的列分配数据类型

170

我想在pd.DataFrame中设置多个列的dtype(由于该文件不适合使用pd.read_csv读取,所以我必须手动将其解析为列表的列表)

import pandas as pd
print pd.DataFrame([['a','1'],['b','2']],
                   dtype={'x':'object','y':'int'},
                   columns=['x','y'])

我明白了

ValueError: entry not a 2- or 3- tuple

我唯一可以设置它们的方式是通过循环遍历每个列变量并使用astype重新转换数据类型。

dtypes = {'x':'object','y':'int'}
mydata = pd.DataFrame([['a','1'],['b','2']],
                      columns=['x','y'])
for c in mydata.columns:
    mydata[c] = mydata[c].astype(dtypes[c])
print mydata['y'].dtype   #=> int64

有更好的方法吗?


这可能是一个不错的错误/功能请求,目前我不确定dtype参数在做什么(您可以传递标量,但它不是严格的)... - Andy Hayden
3
了解:df = pd.DataFrame([['a', '1'], ['b', '2']], dtype='int', columns=['x', 'y']) 是可行的,但是存在问题。 - Andy Hayden
1
是的,“能用”确实可以;但是结果却不可预测... - hatmatrix
2
这个 GitHub 问题可能很快就会变得相关:https://github.com/pydata/pandas/issues/9287 - Amelio Vazquez-Reina
7个回答

93
自0.17版本以来,您需要使用显式转换:
pd.to_datetime, pd.to_timedelta and pd.to_numeric

(如下所述,不再有“魔法”,convert_objects在0.17中已被弃用)
df = pd.DataFrame({'x': {0: 'a', 1: 'b'}, 'y': {0: '1', 1: '2'}, 'z': {0: '2018-05-01', 1: '2018-05-02'}})

df.dtypes

x    object
y    object
z    object
dtype: object

df

   x  y           z
0  a  1  2018-05-01
1  b  2  2018-05-02

您可以将这些应用于要转换的每一列:
df["y"] = pd.to_numeric(df["y"])
df["z"] = pd.to_datetime(df["z"])    
df

   x  y          z
0  a  1 2018-05-01
1  b  2 2018-05-02

df.dtypes

x            object
y             int64
z    datetime64[ns]
dtype: object

并确认 dtype 已更新。


旧版本/已弃用的 pandas 0.12 - 0.16 答案:您可以使用convert_objects来推断更好的数据类型:

In [21]: df
Out[21]: 
   x  y
0  a  1
1  b  2

In [22]: df.dtypes
Out[22]: 
x    object
y    object
dtype: object

In [23]: df.convert_objects(convert_numeric=True)
Out[23]: 
   x  y
0  a  1
1  b  2

In [24]: df.convert_objects(convert_numeric=True).dtypes
Out[24]: 
x    object
y     int64
dtype: object

魔法!(很遗憾看到它被弃用了。)


2
就像 R 语言中的 type.convert 函数一样,有点不错;但在某些情况下仍然希望能够得到明确的规范说明。 - hatmatrix
1
如果您有一个需要为字符串的列,但包含至少一个可以转换为整数的值,请小心。只需要一个值,整个字段就会被转换为float64。 - Michael David Watson
20
我注意到 convert_objects() 已被弃用......不确定有什么替代它的方法? - joefromct
6
使用DataFrame.infer_objects()重新推断对象列的数据类型。 - James Tobin
1
@smci 好的,我已经编辑了。有很多已过时的答案,我需要想办法找到它们。 - Andy Hayden
显示剩余5条评论

77

你可以使用pandas DataFrame.astype(dtype, copy=True, raise_on_error=True, **kwargs) 明确设置数据类型,并传入一个包含所需数据类型的字典作为参数dtype

以下是一个示例:

import pandas as pd
wheel_number = 5
car_name = 'jeep'
minutes_spent = 4.5

# set the columns
data_columns = ['wheel_number', 'car_name', 'minutes_spent']

# create an empty dataframe
data_df = pd.DataFrame(columns = data_columns)
df_temp = pd.DataFrame([[wheel_number, car_name, minutes_spent]],columns = data_columns)
data_df = data_df.append(df_temp, ignore_index=True) 

你得到了

In [11]: data_df.dtypes
Out[11]:
wheel_number     float64
car_name          object
minutes_spent    float64
dtype: object

data_df = data_df.astype(dtype= {"wheel_number":"int64",
        "car_name":"object","minutes_spent":"float64"})

现在你可以看到它已经改变了

In [18]: data_df.dtypes
Out[18]:
wheel_number       int64
car_name          object
minutes_spent    float64

这是将另一个数据框的“dtypes”定义的整个字典传递到新数据框的最佳方法。谢谢! - Andreas L.
太棒了!这相当于在read_csv构造期间能够传递模式。 - oneextrafact

71

对于像我这样从Google(等等)进来的人:

convert_objects自0.17版本开始已经被弃用,如果您使用它,会收到如下警告:

FutureWarning: convert_objects is deprecated.  Use the data-type specific converters 
pd.to_datetime, pd.to_timedelta and pd.to_numeric.

您应该执行以下操作:


如果您加入了一些 pd.to_datetime,to_timedelta,to_numeric 的示例,那么这应该是被接受的答案。 - smci

19

另一种设置列类型的方式是首先构建带有所需类型的NumPy记录数组,填充数据,然后将其传递给DataFrame构造函数。

import pandas as pd
import numpy as np    

x = np.empty((10,), dtype=[('x', np.uint8), ('y', np.float64)])
df = pd.DataFrame(x)

df.dtypes ->

x      uint8
y    float64

6

最好使用类型化的np.arrays,然后将数据和列名作为字典传递。

import numpy as np
import pandas as pd
# Feature: np arrays are 1: efficient, 2: can be pre-sized
x = np.array(['a', 'b'], dtype=object)
y = np.array([ 1 ,  2 ], dtype=np.int32)
df = pd.DataFrame({
   'x' : x,    # Feature: column name is near data array
   'y' : y,
   }
 )

0
import pandas as pd
df = pd.DataFrame([['a', '1'], ['b', '2']], columns=['x', 'y'])
# Cast a pandas object to a specified dtype
df = df.astype({'x': 'object', 'y': int})
# Check
print(df.dtypes)

2
您的回答仅包含代码。我建议您不要仅发布代码作为答案,还应该提供解释您的代码是如何解决问题的,并且如何工作的。附有解释的答案通常更有帮助和更高质量,并且更有可能获得点赞。 - Mark Rotteveel

-1

我和你面临着类似的问题。在我的情况下,我需要手动解析来自思科日志的数千个文件。

为了灵活处理字段和类型,我已经成功地使用StringIO + read_cvs进行了测试,它确实接受dtype规范的字典。

我通常将每个文件(5k-20k行)放入缓冲区,并动态创建dtype字典。

最终,我将这些数据帧(有分类...感谢0.19)连接成一个大数据帧,然后将其转储到hdf5中。

大致如此。

import pandas as pd
import io 

output = io.StringIO()
output.write('A,1,20,31\n')
output.write('B,2,21,32\n')
output.write('C,3,22,33\n')
output.write('D,4,23,34\n')

output.seek(0)


df=pd.read_csv(output, header=None,
        names=["A","B","C","D"],
        dtype={"A":"category","B":"float32","C":"int32","D":"float64"},
        sep=","
       )

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 4 columns):
A    5 non-null category
B    5 non-null float32
C    5 non-null int32
D    5 non-null float64
dtypes: category(1), float32(1), float64(1), int32(1)
memory usage: 205.0 bytes
None

不是很符合Python风格...但能完成任务

希望有所帮助。

JC


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