赞
踩
本文授权转载自Python大咖谈
禁止二次转载
大家好,我是老表
阅读文本大概需要 16 分钟
建议从头开始学习,本系列前四篇大多数情况下,pandas 使用 Numpy 数组、Series 或 DataFrame 里某列的数据类型。Numpy 支持 float
、int
、bool
、timedelta[ns]
、datetime64[ns]
,注意,Numpy 不支持带时区信息的 datetime
。
Pandas 与第三方支持库对 Numpy 类型系统进行了扩充,本节只介绍 pandas 的内部扩展。如需了解自行编写与 pandas 配合的扩展类型,请参阅扩展类型,参阅扩展数据类型了解第三方支持库提供的扩展类型。
下表列出了 pandas 扩展类型,参阅列出的文档内容,查看每种类型的详情。
数据种类 | 数据类型 | 标量 | 数组 | 文档 |
---|---|---|---|---|
带时区的 日期时间 | DatetimeTZ | Timestamp | arrays. | Time zone handling |
类别型 | Categorical | (无) | Categorical | Categorical data |
时间段 | Period | Period | arrays. | Time span representation |
稀疏数据 | Sparse | (无) | arrays. | Sparse data structures |
时间间隔 | Interval | Interval | arrays. | IntervalIndex |
空整型 | Int64... | (无) | arrays. | 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]: dft
- Out[329]:
- A B C D E F G
- 0 0.035962 1 foo 2001-01-02 1.0 False 1
- 1 0.701379 1 foo 2001-01-02 1.0 False 1
- 2 0.281885 1 foo 2001-01-02 1.0 False 1
-
- In [330]: dft.dtypes
- Out[330]:
- A float64
- B int64
- C object
- D datetime64[ns]
- E float32
- F bool
- G int8
- dtype: object
要查看 Series
的数据类型,用 dtype
属性。
- In [331]: dft['A'].dtype
- Out[331]: dtype('float64')
Pandas 对象单列中含多种类型的数据时,该列的数据类型为可适配于各类数据的数据类型,通常为 object
。
- # 整数被强制转换为浮点数
- In [332]: pd.Series([1, 2, 3, 4, 5, 6.])
- Out[332]:
- 0 1.0
- 1 2.0
- 2 3.0
- 3 4.0
- 4 5.0
- 5 6.0
- dtype: float64
-
- # 字符串数据决定了该 Series 的数据类型为 ``object``
- In [333]: pd.Series([1, 2, 3, 6., 'foo'])
- Out[333]:
- 0 1
- 1 2
- 2 3
- 3 6
- 4 foo
- dtype: object
DataFrame.dtypes.value_counts()
用于统计 DataFrame 里各列数据类型的数量。
- In [334]: dft.dtypes.value_counts()
- Out[334]:
- float32 1
- object 1
- bool 1
- int8 1
- float64 1
- datetime64[ns] 1
- int64 1
- dtype: int64
多种数值型数据类型可以在 DataFrame 里共存。如果只传递一种数据类型,不论是通过 dtype
关键字直接传递,还是通过 ndarray
或 Series
传递,都会保存至 DataFrame 操作。此外,不同数值型数据类型不会合并。示例如下:
- In [335]: df1 = pd.DataFrame(np.random.randn(8, 1), columns=['A'], dtype='float32')
-
- In [336]: df1
- Out[336]:
- A
- 0 0.224364
- 1 1.890546
- 2 0.182879
- 3 0.787847
- 4 -0.188449
- 5 0.667715
- 6 -0.011736
- 7 -0.399073
-
- In [337]: df1.dtypes
- Out[337]:
- A float32
- dtype: object
-
- In [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]: df2
- Out[339]:
- A B C
- 0 0.823242 0.256090 0
- 1 1.607422 1.426469 0
- 2 -0.333740 -0.416203 255
- 3 -0.063477 1.139976 0
- 4 -1.014648 -1.193477 0
- 5 0.678711 0.096706 0
- 6 -0.040863 -1.956850 1
- 7 -0.357422 -0.714337 0
-
- In [340]: df2.dtypes
- Out[340]:
- A float16
- B float64
- C uint8
- dtype: object
整数的默认类型为 int64
,浮点数的默认类型为 float64
,这里的默认值与系统平台无关,不管是 32 位系统,还是 64 位系统都是一样的。下列代码返回的结果都是 int64
:
- In [341]: pd.DataFrame([1, 2], columns=['a']).dtypes
- Out[341]:
- a int64
- dtype: object
-
- In [342]: pd.DataFrame({'a': [1, 2]}).dtypes
- Out[342]:
- a int64
- dtype: object
-
- In [343]: pd.DataFrame({'a': 1}, index=list(range(2))).dtypes
- Out[343]:
- a int64
- dtype: 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) + df2
-
- In [346]: df3
- Out[346]:
- A B C
- 0 1.047606 0.256090 0.0
- 1 3.497968 1.426469 0.0
- 2 -0.150862 -0.416203 255.0
- 3 0.724370 1.139976 0.0
- 4 -1.203098 -1.193477 0.0
- 5 1.346426 0.096706 0.0
- 6 -0.052599 -1.956850 1.0
- 7 -0.756495 -0.714337 0.0
-
- In [347]: df3.dtypes
- Out[347]:
- A float32
- B float64
- C float64
- dtype: object
DataFrame.to_numpy()
返回多个数据类型里用的最多的数据类型,这里指的是输出结果的数据类型是适用于所有同质 Numpy 数组的数据类型。这里会强制执行向上转型。
- In [348]: df3.to_numpy().dtype
- Out[348]: dtype('float64')
astype()
方法显式地把一种数据类型转换为另一种,默认返回的是复制数据,就算数据类型没有改变也会执行复制操作,copy=False
可以改变默认操作模式。此外,如果 astype
无效会触发异常。
向上转型一般都会遵循 numpy 的规则。如果操作中涉及两种不同类型的数据,返回的将是更通用的那种数据类型。
- In [349]: df3
- Out[349]:
- A B C
- 0 1.047606 0.256090 0.0
- 1 3.497968 1.426469 0.0
- 2 -0.150862 -0.416203 255.0
- 3 0.724370 1.139976 0.0
- 4 -1.203098 -1.193477 0.0
- 5 1.346426 0.096706 0.0
- 6 -0.052599 -1.956850 1.0
- 7 -0.756495 -0.714337 0.0
-
- In [350]: df3.dtypes
- Out[350]:
- A float32
- B float64
- C float64
- dtype: object
-
- # 转换数据类型
- In [351]: df3.astype('float32').dtypes
- Out[351]:
- A float32
- B float32
- C float32
- dtype: 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]: dft
- Out[354]:
- a b c
- 0 1 4 7
- 1 2 5 8
- 2 3 6 9
-
- In [355]: dft.dtypes
- Out[355]:
- a uint8
- b uint8
- c int64
- dtype: 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]: dft1
- Out[358]:
- a b c
- 0 True 4 7.0
- 1 False 5 8.0
- 2 True 6 9.0
-
- In [359]: dft1.dtypes
- Out[359]:
- a bool
- b int64
- c float64
- dtype: 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).dtypes
- Out[361]:
- a uint8
- b uint8
- dtype: object
-
- In [362]: dft.loc[:, ['a', 'b']] = dft.loc[:, ['a', 'b']].astype(np.uint8)
-
- In [363]: dft.dtypes
- Out[363]:
- a int64
- b int64
- c int64
- dtype: object
Pandas 提供了多种函数可以把 object
从一种类型强制转为另一种类型。这是因为,数据有时存储的是正确类型,但在保存时却存成了 object
类型,此时,用 DataFrame.infer_objects()
与 Series.infer_objects()
方法即可把数据软转换为正确的类型。
- In [364]: import datetime
-
- In [365]: df = pd.DataFrame([[1, 2],
- .....: ['a', 'b'],
- .....: [datetime.datetime(2016, 3, 2),
- .....: datetime.datetime(2016, 3, 2)]])
- .....:
-
- In [366]: df = df.T
-
- In [367]: df
- Out[367]:
- 0 1 2
- 0 1 a 2016-03-02
- 1 2 b 2016-03-02
-
- In [368]: df.dtypes
- Out[368]:
- 0 object
- 1 object
- 2 datetime64[ns]
- dtype: object
因为数据被转置,所以把原始列的数据类型改成了 object
,但使用 infer_objects
后就变正确了。
- In [369]: df.infer_objects().dtypes
- Out[369]:
- 0 int64
- 1 object
- 2 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 datetime
-
- In [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 datetime
-
- In [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 datetime
-
- In [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 dtype
- Out[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 dtype
- Out[394]: array([1, 2, 3], dtype=uint8)
-
- In [395]: pd.to_numeric(m, downcast='float') # smallest float dtype
- Out[395]: array([1., 2., 3.], dtype=float32)
上述方法仅能应用于一维数组、列表或标量;不能直接用于 DataFrame 等多维对象。不过,用 apply()
,可以快速为每列应用函数:
- In [396]: import datetime
-
- In [397]: df = pd.DataFrame([
- .....: ['2016-07-09', datetime.datetime(2016, 3, 2)]] * 2, dtype='O')
- .....:
-
- In [398]: df
- Out[398]:
- 0 1
- 0 2016-07-09 2016-03-02 00:00:00
- 1 2016-07-09 2016-03-02 00:00:00
-
- In [399]: df.apply(pd.to_datetime)
- Out[399]:
- 0 1
- 0 2016-07-09 2016-03-02
- 1 2016-07-09 2016-03-02
-
- In [400]: df = pd.DataFrame([['1.1', 2, 3]] * 2, dtype='O')
-
- In [401]: df
- Out[401]:
- 0 1 2
- 0 1.1 2 3
- 1 1.1 2 3
-
- In [402]: df.apply(pd.to_numeric)
- Out[402]:
- 0 1 2
- 0 1.1 2 3
- 1 1.1 2 3
-
- In [403]: df = pd.DataFrame([['5us', pd.Timedelta('1day')]] * 2, dtype='O')
-
- In [404]: df
- Out[404]:
- 0 1
- 0 5us 1 days 00:00:00
- 1 5us 1 days 00:00:00
-
- In [405]: df.apply(pd.to_timedelta)
- Out[405]:
- 0 1
- 0 00:00:00.000005 1 days
- 1 00:00:00.000005 1 days
对 integer
数据执行选择操作时,可以很轻而易举地把数据转换为 floating
。pandas 会保存输入数据的数据类型,以防未引入 nans
的情况。参阅 对整数 NA 空值的支持。
- In [406]: dfi = df3.astype('int32')
-
- In [407]: dfi['E'] = 1
-
- In [408]: dfi
- Out[408]:
- A B C E
- 0 1 0 0 1
- 1 3 1 0 1
- 2 0 0 255 1
- 3 0 1 0 1
- 4 -1 -1 0 1
- 5 1 0 0 1
- 6 0 -1 1 1
- 7 0 0 0 1
-
- In [409]: dfi.dtypes
- Out[409]:
- A int32
- B int32
- C int32
- E int64
- dtype: object
-
- In [410]: casted = dfi[dfi > 0]
-
- In [411]: casted
- Out[411]:
- A B C E
- 0 1.0 NaN NaN 1
- 1 3.0 1.0 NaN 1
- 2 NaN NaN 255.0 1
- 3 NaN 1.0 NaN 1
- 4 NaN NaN NaN 1
- 5 1.0 NaN NaN 1
- 6 NaN NaN 1.0 1
- 7 NaN NaN NaN 1
-
- In [412]: casted.dtypes
- Out[412]:
- A float64
- B float64
- C float64
- E int64
- dtype: object
浮点数类型未改变。
- In [413]: dfa = df3.copy()
-
- In [414]: dfa['A'] = dfa['A'].astype('float32')
-
- In [415]: dfa.dtypes
- Out[415]:
- A float32
- B float64
- C float64
- dtype: object
-
- In [416]: casted = dfa[df2 > 0]
-
- In [417]: casted
- Out[417]:
- A B C
- 0 1.047606 0.256090 NaN
- 1 3.497968 1.426469 NaN
- 2 NaN NaN 255.0
- 3 NaN 1.139976 NaN
- 4 NaN NaN NaN
- 5 1.346426 0.096706 NaN
- 6 NaN NaN 1.0
- 7 NaN NaN NaN
-
- In [418]: casted.dtypes
- Out[418]:
- A float32
- B float64
- C float64
- dtype: object
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]: df
- Out[424]:
- string int64 uint8 float64 bool1 bool2 dates category tdeltas uint64 other_dates tz_aware_dates
- 0 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:00
- 1 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:00
- 2 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.dtypes
- Out[425]:
- string object
- int64 int64
- uint8 uint8
- float64 float64
- bool1 bool
- bool2 bool
- dates datetime64[ns]
- category category
- tdeltas timedelta64[ns]
- uint64 uint64
- other_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 bool2
- 0 True False
- 1 False True
- 2 True False
该方法还支持输入 NumPy 数据类型的名称:
- In [427]: df.select_dtypes(include=['bool'])
- Out[427]:
- bool1 bool2
- 0 True False
- 1 False True
- 2 True False
select_dtypes()
还支持通用数据类型。
比如,选择所有数值型与布尔型的列,同时,排除无符号整数:
- In [428]: df.select_dtypes(include=['number', 'bool'], exclude=['unsignedinteger'])
- Out[428]:
- int64 float64 bool1 bool2 tdeltas
- 0 1 4.0 True False NaT
- 1 2 5.0 False True 1 days
- 2 3 6.0 True False 1 days
选择字符串型的列必须要用 object
:
- In [429]: df.select_dtypes(include=['object'])
- Out[429]:
- string
- 0 a
- 1 b
- 2 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 的架构里,因此,上面的函数没有显示。
大家好,我是老表
觉得本文不错的话,转发、留言、点赞,是对我最大的支持。
每日留言
说说你读完本文感受?
或者一句激励自己的话?
(字数不少于15字)
想进学习交流群
加微信:jjxksa888
备注:简说Python
2小时快速掌握Python基础知识要点。
完整Python基础知识要点
近期推荐阅读: 整理了我开始分享学习笔记到现在超过250篇优质文章,涵盖数据分析、爬虫、机器学习等方面,别再说不知道该从哪开始,实战哪里找了Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。