
本文共 15344 字,大约阅读时间需要 51 分钟。

呆鸟云:“这一系列长篇终于连载完了,还请大家关注 Python 大咖谈,这里专注 Python 数据分析,后期呆鸟还会给大家分享更多 Pandas 好文。”
数据类型
大多数情况下,pandas 使用 Numpy 数组、Series 或 DataFrame 里某列的数据类型。Numpy 支持 float
、int
、bool
、timedelta[ns]
、datetime64[ns]
,注意,Numpy 不支持带时区信息的 datetime
。
Pandas 与第三方支持库对 Numpy 类型系统进行了扩充,本节只介绍 pandas 的内部扩展。如需了解自行编写与 pandas 配合的扩展类型,请参阅扩展类型,参阅扩展数据类型了解第三方支持库提供的扩展类型。
下表列出了 pandas 扩展类型,参阅列出的文档内容,查看每种类型的详情。
数据种类 | 数据类型 | 标量 | 数组 | 文档 |
---|---|---|---|---|
带时区的日期时间 | DatetimeTZ | Timestamp | arrays.DatetimeArray | Time zone handling |
类别型 | Categorical | (无) | Categorical | Categorical data |
时间段 | Period | Period | arrays.PeriodArray | Time span representation |
稀疏数据 | Sparse | (无) | arrays.SparseArray | Sparse data structures |
时间间隔 | Interval | Interval | arrays.IntervalArray | IntervalIndex |
空整型 | Int64... | (无) | arrays.IntegerArray | Nullable integer data type |
比表要横屏看
Pandas 用 object
存储字符串。
虽然, object
数据类型能够存储任何对象,但应尽量避免这种操作,要了解与其它支持库与方法的性能与交互操作,参阅 对象转换。
DataFrame 的 dtypes
属性用起来很方便,以 Series 形式返回每列的数据类型。
In [328]: dft = pd.DataFrame({'A': np.random.rand(3), .....: 'B': 1, .....: 'C': 'foo', .....: 'D': pd.Timestamp('20010102'), .....: 'E': pd.Series([1.0] * 3).astype('float32'), .....: 'F': False, .....: 'G': pd.Series([1] * 3, dtype='int8')}) .....: In [329]: dftOut[329]: A B C D E F G0 0.035962 1 foo 2001-01-02 1.0 False 11 0.701379 1 foo 2001-01-02 1.0 False 12 0.281885 1 foo 2001-01-02 1.0 False 1In [330]: dft.dtypesOut[330]: A float64B int64C objectD datetime64[ns]E float32F boolG int8dtype: object
要查看 Series
的数据类型,用 dtype
属性。
In [331]: dft['A'].dtypeOut[331]: dtype('float64')
Pandas 对象单列中含多种类型的数据时,该列的数据类型为可适配于各类数据的数据类型,通常为 object
。
# 整数被强制转换为浮点数In [332]: pd.Series([1, 2, 3, 4, 5, 6.])Out[332]: 0 1.01 2.02 3.03 4.04 5.05 6.0dtype: float64# 字符串数据决定了该 Series 的数据类型为 ``object``In [333]: pd.Series([1, 2, 3, 6., 'foo'])Out[333]: 0 11 22 33 64 foodtype: object
DataFrame.dtypes.value_counts()
用于统计 DataFrame 里各列数据类型的数量。
In [334]: dft.dtypes.value_counts()Out[334]: float32 1object 1bool 1int8 1float64 1datetime64[ns] 1int64 1dtype: int64
多种数值型数据类型可以在 DataFrame 里共存。如果只传递一种数据类型,不论是通过 dtype
关键字直接传递,还是通过 ndarray
或 Series
传递,都会保存至 DataFrame 操作。此外,不同数值型数据类型不会合并。示例如下:
In [335]: df1 = pd.DataFrame(np.random.randn(8, 1), columns=['A'], dtype='float32')In [336]: df1Out[336]: A0 0.2243641 1.8905462 0.1828793 0.7878474 -0.1884495 0.6677156 -0.0117367 -0.399073In [337]: df1.dtypesOut[337]: A float32dtype: objectIn [338]: df2 = pd.DataFrame({'A': pd.Series(np.random.randn(8), dtype='float16'), .....: 'B': pd.Series(np.random.randn(8)), .....: 'C': pd.Series(np.array(np.random.randn(8), .....: dtype='uint8'))}) .....: In [339]: df2Out[339]: A B C0 0.823242 0.256090 01 1.607422 1.426469 02 -0.333740 -0.416203 2553 -0.063477 1.139976 04 -1.014648 -1.193477 05 0.678711 0.096706 06 -0.040863 -1.956850 17 -0.357422 -0.714337 0In [340]: df2.dtypesOut[340]: A float16B float64C uint8dtype: object
默认值
整数的默认类型为 int64
,浮点数的默认类型为 float64
,这里的默认值与系统平台无关,不管是 32 位系统,还是 64 位系统都是一样的。下列代码返回的结果都是 int64
:
In [341]: pd.DataFrame([1, 2], columns=['a']).dtypesOut[341]: a int64dtype: objectIn [342]: pd.DataFrame({'a': [1, 2]}).dtypesOut[342]: a int64dtype: objectIn [343]: pd.DataFrame({'a': 1}, index=list(range(2))).dtypesOut[343]: a int64dtype: object
注意,Numpy 创建数组时,会根据系统选择类型。下列代码在 32 位系统上将返回 int32
。
In [344]: frame = pd.DataFrame(np.array([1, 2]))
向上转型
与其它类型合并时,要用到向上转型,这里指的是从现有类型转换为另一种类型,如int
变为 float
。
In [345]: df3 = df1.reindex_like(df2).fillna(value=0.0) + df2In [346]: df3Out[346]: A B C0 1.047606 0.256090 0.01 3.497968 1.426469 0.02 -0.150862 -0.416203 255.03 0.724370 1.139976 0.04 -1.203098 -1.193477 0.05 1.346426 0.096706 0.06 -0.052599 -1.956850 1.07 -0.756495 -0.714337 0.0In [347]: df3.dtypesOut[347]: A float32B float64C float64dtype: object
DataFrame.to_numpy()
返回多个数据类型里用的最多的数据类型,这里指的是输出结果的数据类型是适用于所有同质 Numpy 数组的数据类型。这里会强制执行向上转型。
In [348]: df3.to_numpy().dtypeOut[348]: dtype('float64')
astype
astype()
方法显式地把一种数据类型转换为另一种,默认返回的是复制数据,就算数据类型没有改变也会执行复制操作,copy=False
可以改变默认操作模式。此外,如果 astype
无效会触发异常。
向上转型一般都会遵循 numpy 的规则。如果操作中涉及两种不同类型的数据,返回的将是更通用的那种数据类型。
In [349]: df3Out[349]: A B C0 1.047606 0.256090 0.01 3.497968 1.426469 0.02 -0.150862 -0.416203 255.03 0.724370 1.139976 0.04 -1.203098 -1.193477 0.05 1.346426 0.096706 0.06 -0.052599 -1.956850 1.07 -0.756495 -0.714337 0.0In [350]: df3.dtypesOut[350]: A float32B float64C float64dtype: object# 转换数据类型In [351]: df3.astype('float32').dtypesOut[351]: A float32B float32C float32dtype: object
用 astype()
把一列或多列转换为指定类型 。
In [352]: dft = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]})In [353]: dft[['a', 'b']] = dft[['a', 'b']].astype(np.uint8)In [354]: dftOut[354]: a b c0 1 4 71 2 5 82 3 6 9In [355]: dft.dtypesOut[355]: a uint8b uint8c int64dtype: object
0.19.0 版新增。
astype()
通过字典指定哪些列转换为哪些类型。
In [356]: dft1 = pd.DataFrame({'a': [1, 0, 1], 'b': [4, 5, 6], 'c': [7, 8, 9]})In [357]: dft1 = dft1.astype({'a': np.bool, 'c': np.float64})In [358]: dft1Out[358]: a b c0 True 4 7.01 False 5 8.02 True 6 9.0In [359]: dft1.dtypesOut[359]: a boolb int64c float64dtype: object
用
astype()
与loc()
为部分列转换指定类型时,会发生向上转型。
loc()
尝试分配当前的数据类型,而[]
则会从右方获取数据类型并进行覆盖。因此,下列代码会产出意料之外的结果:
In [360]: dft = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]})In [361]: dft.loc[:, ['a', 'b']].astype(np.uint8).dtypesOut[361]: a uint8b uint8dtype: objectIn [362]: dft.loc[:, ['a', 'b']] = dft.loc[:, ['a', 'b']].astype(np.uint8)In [363]: dft.dtypesOut[363]: a int64b int64c int64dtype: object
对象转换
Pandas 提供了多种函数可以把 object
从一种类型强制转为另一种类型。这是因为,数据有时存储的是正确类型,但在保存时却存成了 object
类型,此时,用 DataFrame.infer_objects()
与 Series.infer_objects()
方法即可把数据软转换为正确的类型。
In [364]: import datetimeIn [365]: df = pd.DataFrame([[1, 2], .....: ['a', 'b'], .....: [datetime.datetime(2016, 3, 2), .....: datetime.datetime(2016, 3, 2)]]) .....: In [366]: df = df.TIn [367]: dfOut[367]: 0 1 20 1 a 2016-03-021 2 b 2016-03-02In [368]: df.dtypesOut[368]: 0 object1 object2 datetime64[ns]dtype: object
因为数据被转置,所以把原始列的数据类型改成了 object
,但使用 infer_objects
后就变正确了。
In [369]: df.infer_objects().dtypesOut[369]: 0 int641 object2 datetime64[ns]dtype: object
下列函数可以应用于一维数组与标量,执行硬转换,把对象转换为指定类型。
`to_numeric()`,转换为数值型
In [370]: m = ['1.1', 2, 3]In [371]: pd.to_numeric(m)Out[371]: array([1.1, 2. , 3. ])
`to_datetime()`,转换为
datetime
对象
In [372]: import datetimeIn [373]: m = ['2016-07-09', datetime.datetime(2016, 3, 2)]In [374]: pd.to_datetime(m)Out[374]: DatetimeIndex(['2016-07-09', '2016-03-02'], dtype='datetime64[ns]', freq=None)
`to_timedelta()`,转换为
timedelta
对象。
In [375]: m = ['5us', pd.Timedelta('1day')]In [376]: pd.to_timedelta(m)Out[376]: TimedeltaIndex(['0 days 00:00:00.000005', '1 days 00:00:00'], dtype='timedelta64[ns]', freq=None)
如需强制转换,则要加入 error
参数,指定 pandas 怎样处理不能转换为成预期类型或对象的数据。errors
参数的默认值为 False
,指的是在转换过程中,遇到任何问题都触发错误。设置为 errors='coerce'
时,pandas 会忽略错误,强制把问题数据转换为 pd.NaT
(datetime
与 timedelta
),或 np.nan
(数值型)。读取数据时,如果大部分要转换的数据是数值型或 datetime
,这种操作非常有用,但偶尔也会有非制式数据混合在一起,可能会导致展示数据缺失:
In [377]: import datetimeIn [378]: m = ['apple', datetime.datetime(2016, 3, 2)]In [379]: pd.to_datetime(m, errors='coerce')Out[379]: DatetimeIndex(['NaT', '2016-03-02'], dtype='datetime64[ns]', freq=None)In [380]: m = ['apple', 2, 3]In [381]: pd.to_numeric(m, errors='coerce')Out[381]: array([nan, 2., 3.])In [382]: m = ['apple', pd.Timedelta('1day')]In [383]: pd.to_timedelta(m, errors='coerce')Out[383]: TimedeltaIndex([NaT, '1 days'], dtype='timedelta64[ns]', freq=None)
error
参数还有第三个选项,error='ignore'
。转换数据时会忽略错误,直接输出问题数据:
In [384]: import datetimeIn [385]: m = ['apple', datetime.datetime(2016, 3, 2)]In [386]: pd.to_datetime(m, errors='ignore')Out[386]: Index(['apple', 2016-03-02 00:00:00], dtype='object')In [387]: m = ['apple', 2, 3]In [388]: pd.to_numeric(m, errors='ignore')Out[388]: array(['apple', 2, 3], dtype=object)In [389]: m = ['apple', pd.Timedelta('1day')]In [390]: pd.to_timedelta(m, errors='ignore')Out[390]: array(['apple', Timedelta('1 days 00:00:00')], dtype=object)
执行转换操作时,to_numeric()
还有一个参数,downcast
,即向下转型,可以把数值型转换为减少内存占用的数据类型:
In [391]: m = ['1', 2, 3]In [392]: pd.to_numeric(m, downcast='integer') # smallest signed int dtypeOut[392]: array([1, 2, 3], dtype=int8)In [393]: pd.to_numeric(m, downcast='signed') # same as 'integer'Out[393]: array([1, 2, 3], dtype=int8)In [394]: pd.to_numeric(m, downcast='unsigned') # smallest unsigned int dtypeOut[394]: array([1, 2, 3], dtype=uint8)In [395]: pd.to_numeric(m, downcast='float') # smallest float dtypeOut[395]: array([1., 2., 3.], dtype=float32)
上述方法仅能应用于一维数组、列表或标量;不能直接用于 DataFrame 等多维对象。不过,用 apply()
,可以快速为每列应用函数:
In [396]: import datetimeIn [397]: df = pd.DataFrame([ .....: ['2016-07-09', datetime.datetime(2016, 3, 2)]] * 2, dtype='O') .....: In [398]: dfOut[398]: 0 10 2016-07-09 2016-03-02 00:00:001 2016-07-09 2016-03-02 00:00:00In [399]: df.apply(pd.to_datetime)Out[399]: 0 10 2016-07-09 2016-03-021 2016-07-09 2016-03-02In [400]: df = pd.DataFrame([['1.1', 2, 3]] * 2, dtype='O')In [401]: dfOut[401]: 0 1 20 1.1 2 31 1.1 2 3In [402]: df.apply(pd.to_numeric)Out[402]: 0 1 20 1.1 2 31 1.1 2 3In [403]: df = pd.DataFrame([['5us', pd.Timedelta('1day')]] * 2, dtype='O')In [404]: dfOut[404]: 0 10 5us 1 days 00:00:001 5us 1 days 00:00:00In [405]: df.apply(pd.to_timedelta)Out[405]: 0 10 00:00:00.000005 1 days1 00:00:00.000005 1 days
各种坑
对 integer
数据执行选择操作时,可以很轻而易举地把数据转换为 floating
。pandas 会保存输入数据的数据类型,以防未引入 nans
的情况。参阅 对整数 NA 空值的支持。
In [406]: dfi = df3.astype('int32')In [407]: dfi['E'] = 1In [408]: dfiOut[408]: A B C E0 1 0 0 11 3 1 0 12 0 0 255 13 0 1 0 14 -1 -1 0 15 1 0 0 16 0 -1 1 17 0 0 0 1In [409]: dfi.dtypesOut[409]: A int32B int32C int32E int64dtype: objectIn [410]: casted = dfi[dfi > 0]In [411]: castedOut[411]: A B C E0 1.0 NaN NaN 11 3.0 1.0 NaN 12 NaN NaN 255.0 13 NaN 1.0 NaN 14 NaN NaN NaN 15 1.0 NaN NaN 16 NaN NaN 1.0 17 NaN NaN NaN 1In [412]: casted.dtypesOut[412]: A float64B float64C float64E int64dtype: object
浮点数类型未改变。
In [413]: dfa = df3.copy()In [414]: dfa['A'] = dfa['A'].astype('float32')In [415]: dfa.dtypesOut[415]: A float32B float64C float64dtype: objectIn [416]: casted = dfa[df2 > 0]In [417]: castedOut[417]: A B C0 1.047606 0.256090 NaN1 3.497968 1.426469 NaN2 NaN NaN 255.03 NaN 1.139976 NaN4 NaN NaN NaN5 1.346426 0.096706 NaN6 NaN NaN 1.07 NaN NaN NaNIn [418]: casted.dtypesOut[418]: A float32B float64C float64dtype: object
基于 `dtype` 选择列
select_dtypes()
方法基于 dtype
选择列。
首先,创建一个由多种数据类型组成的 DataFrame:
In [419]: df = pd.DataFrame({'string': list('abc'), .....: 'int64': list(range(1, 4)), .....: 'uint8': np.arange(3, 6).astype('u1'), .....: 'float64': np.arange(4.0, 7.0), .....: 'bool1': [True, False, True], .....: 'bool2': [False, True, False], .....: 'dates': pd.date_range('now', periods=3), .....: 'category': pd.Series(list("ABC")).astype('category')}) .....: In [420]: df['tdeltas'] = df.dates.diff()In [421]: df['uint64'] = np.arange(3, 6).astype('u8')In [422]: df['other_dates'] = pd.date_range('20130101', periods=3)In [423]: df['tz_aware_dates'] = pd.date_range('20130101', periods=3, tz='US/Eastern')In [424]: dfOut[424]: string int64 uint8 float64 bool1 bool2 dates category tdeltas uint64 other_dates tz_aware_dates0 a 1 3 4.0 True False 2019-08-22 15:49:01.870038 A NaT 3 2013-01-01 2013-01-01 00:00:00-05:001 b 2 4 5.0 False True 2019-08-23 15:49:01.870038 B 1 days 4 2013-01-02 2013-01-02 00:00:00-05:002 c 3 5 6.0 True False 2019-08-24 15:49:01.870038 C 1 days 5 2013-01-03 2013-01-03 00:00:00-05:00
该 DataFrame 的数据类型:
In [425]: df.dtypesOut[425]: string objectint64 int64uint8 uint8float64 float64bool1 boolbool2 booldates datetime64[ns]category categorytdeltas timedelta64[ns]uint64 uint64other_dates datetime64[ns]tz_aware_dates datetime64[ns, US/Eastern]dtype: object
select_dtypes()
有两个参数,include
与 exclude
,用于实现“提取这些数据类型的列” (include
)或 “提取不是这些数据类型的列”(exclude
)。
选择 bool
型的列,示例如下:
In [426]: df.select_dtypes(include=[bool])Out[426]: bool1 bool20 True False1 False True2 True False
该方法还支持输入 NumPy 数据类型的名称:
In [427]: df.select_dtypes(include=['bool'])Out[427]: bool1 bool20 True False1 False True2 True False
select_dtypes()
还支持通用数据类型。
比如,选择所有数值型与布尔型的列,同时,排除无符号整数:
In [428]: df.select_dtypes(include=['number', 'bool'], exclude=['unsignedinteger'])Out[428]: int64 float64 bool1 bool2 tdeltas0 1 4.0 True False NaT1 2 5.0 False True 1 days2 3 6.0 True False 1 days
选择字符串型的列必须要用 object
:
In [429]: df.select_dtypes(include=['object'])Out[429]: string0 a1 b2 c
要查看 numpy.number
等通用 dtype
的所有子类型,可以定义一个函数,返回子类型树:
In [430]: def subdtypes(dtype): .....: subs = dtype.__subclasses__() .....: if not subs: .....: return dtype .....: return [dtype, [subdtypes(dt) for dt in subs]] .....:
所有 Numpy 数据类型都是 numpy.generic
的子类:
In [431]: subdtypes(np.generic)Out[431]: [numpy.generic, [[numpy.number, [[numpy.integer, [[numpy.signedinteger, [numpy.int8, numpy.int16, numpy.int32, numpy.int64, numpy.int64, numpy.timedelta64]], [numpy.unsignedinteger, [numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64, numpy.uint64]]]], [numpy.inexact, [[numpy.floating, [numpy.float16, numpy.float32, numpy.float64, numpy.float128]], [numpy.complexfloating, [numpy.complex64, numpy.complex128, numpy.complex256]]]]]], [numpy.flexible, [[numpy.character, [numpy.bytes_, numpy.str_]], [numpy.void, [numpy.record]]]], numpy.bool_, numpy.datetime64, numpy.object_]]
注意:Pandas 支持
category
与datetime64[ns, tz]
类型,但这两种类型未整合到 Numpy 的架构里,因此,上面的函数没有显示。
发表评论
最新留言
关于作者
