Pandas 数据类型概览(上篇)

阿凡达2018-07-09 12:21

翻译自:Overview of Pandas Data Types

简介

在进行数据分析时,确保使用正确的数据类型非常重要,否则可能会得到意想不到的结果或错误。对 Pandas 而言,它会在很多情况下正确地作出数据类型推断,你可以继续进行分析工作,而无需深入思考该主题。

尽管 Pandas 工作得很好,但在数据分析过程中的某个时刻,你可能需要将数据从一种类型显式转换为另一种类型。本文将讨论 Pandas 的基本数据类型(即 dtypes),它们如何映射到 python 和 numpy 数据类型,以及从一种 Pandas 类型转换为另一种类型的几个方式。

Pandas 的数据类型

数据类型本质上是编程语言用来理解如何存储和操作数据的内部结构。例如,一个程序需要理解你可以将两个数字加起来,比如 5 + 10 得到 15。或者,如果是两个字符串,比如「cat」和「hat」,你可以将它们连接(加)起来得到「cathat」。

有关 Pandas 数据类型的一个可能令人困惑的地方是,Pandas、Python 和 numpy 的数据类型之间有一些重叠。下表总结了关键点:

Pandas dtype 映射:

Pandas dtype Python 类型 NumPy 类型 用途
object str string, unicode 文本
int64 int int_, int8, int16, int32, int64, uint8, uint16, uint32, uint64 整数
float64 float float_, float16, float32, float64 浮点数
bool bool bool_ 布尔值
datetime64 NA NA 日期时间
timedelta[ns] NA NA 时间差
category NA NA 有限长度的文本值列表

大多数情况下,你不必担心是否应该明确地将熊猫类型强制转换为对应的 NumPy 类型。一般来说使用 Pandas 的默认 int64float64 就可以。我列出此表的唯一原因是,有时你可能会在代码行间或自己的分析过程中看到 Numpy 的类型。

对于本文,我将重点关注以下 Pandas 类型:

  • object
  • int64
  • float64
  • datetime64
  • bool

如果你有兴趣,我会再写一篇文章来专门介绍 categorytimedelta 类型。不过本文中概述的基本方法也适用于这些类型。

我们为什么关心类型?

数据类型是在你遇到错误或意外结果之前并不会关心的事情之一。不过当你将新数据加载到 Pandas 进行进一步分析时,这也是你应该检查的第一件事情。

我将使用一个非常简单的 CSV文件 来说明在 Pandas 中可能会遇到的一些常见的由数据类型导致的错误。另外,在 github 上也一个示例 notbook

import numpy as np
import pandas as pd

df = pd.read_csv("sales_data_types.csv")
Customer Number Customer Name 2016 2017 Percent Growth Jan Units Month Day Year Active
0 10002.0 Quest Industries $125,000.00 $162500.00 30.00% 500 1 10 2015 Y
1 552278.0 Smith Plumbing $920,000.00 $101,2000.00 10.00% 700 6 15 2014 Y
2 23477.0 ACME Industrial $50,000.00 $62500.00 25.00% 125 3 29 2016 Y
3 24900.0 Brekke LTD $350,000.00 $490000.00 4.00% 75 10 27 2015 Y
4 651029.0 Harbor Co $15,000.00 $12750.00 -15.00% Closed 2 2 2014 N

乍一看,数据没什么问题,所以我们可以尝试做一些操作来分析数据。我们来试一下把 2016 和 2017 年的销售额加起来:

df['2016'] + df['2017']
0      $125,000.00$162500.00
1    $920,000.00$101,2000.00
2        $50,000.00$62500.00
3      $350,000.00$490000.00
4        $15,000.00$12750.00
dtype: object

这看起来就不对了。我们希望将总计加在一起,但 Pandas 只是将这两个值连接在一起创建了一个长字符串。这个问题的一个线索是 dtype:objectobject 在 Pandas 代表字符串,所以它执行的是字符串操作而不是数学操作。

如果我们想查看 dataframe 中的所有数据类型,使用 df.dtypes


df.dtypes
Customer Number    float64
Customer Name       object
2016                object
2017                object
Percent Growth      object
Jan Units           object
Month                int64
Day                  int64
Year                 int64
Active              object
dtype: object

此外,df.info() 函数可以显示更有用的信息。

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5 entries, 0 to 4
Data columns (total 10 columns):
Customer Number    5 non-null float64
Customer Name      5 non-null object
2016               5 non-null object
2017               5 non-null object
Percent Growth     5 non-null object
Jan Units          5 non-null object
Month              5 non-null int64
Day                5 non-null int64
Year               5 non-null int64
Active             5 non-null object
dtypes: float64(1), int64(3), object(6)
memory usage: 480.0+ bytes

查看自动分配的数据类型后,有几个问题:

  • Customer Number 被归为 float64 但它应该是 int64
  • 20162017 这两列被存储为 object,但应该是 float64int64 这样的数值类型
  • Percent GrowthJan Units 也被存储为 object 而不是数值类型
  • MonthDayYear 这三列应该被转换为 datetime64
  • Active 列应该是布尔型

在我们清洗这些数据类型之前,要对这些数据做更多的附加分析是非常困难的。

为了在 Pandas 中转换数据类型,有三个基本选项:

  • 使用 astype() 来强制转换到合适的 dtype
  • 创建一个自定义函数来转换数据
  • 使用 Pandas 的函数,例如 to_numeric()to_datetime()

使用 astype() 函数

将 Pandas 数据列转换为不同类型的最简单方法就是用 astype()。例如,要将 Customer Number 转换为整数,我们可以这样调用:

df['Customer Number'].astype('int')
0     10002
1    552278
2     23477
3     24900
4    651029
Name: Customer Number, dtype: int64

为了真正修改原始 dataframe 中的客户编号(Customer Number),记得把 astype() 函数的返回值重新赋值给 dataframe,因为 astype() 仅返回数据的副本而不原地修改。

df["Customer Number"] = df['Customer Number'].astype('int')
df.dtypes
Customer Number     int64
Customer Name      object
2016               object
2017               object
Percent Growth     object
Jan Units          object
Month               int64
Day                 int64
Year                int64
Active             object
dtype: object

以下是客户编号(Customer Number)为整数的新 dataframe:

Customer Number Customer Name 2016 2017 Percent Growth Jan Units Month Day Year Active
0 10002 Quest Industries $125,000.00 $162500.00 30.00% 500 1 10 2015 Y
1 552278 Smith Plumbing $920,000.00 $101,2000.00 10.00% 700 6 15 2014 Y
2 23477 ACME Industrial $50,000.00 $62500.00 25.00% 125 3 29 2016 Y
3 24900 Brekke LTD $350,000.00 $490000.00 4.00% 75 10 27 2015 Y
4 651029 Harbor Co $15,000.00 $12750.00 -15.00% Closed 2 2 2014 N

这一切看起来不错,并且似乎很简单。让我们尝试对 2016 列做同样的事情并将其转换为浮点数:

df['2016'].astype('float')
ValueError       Traceback (most recent call last)
<ipython-input-45-999869d577b0> in <module>()
----> 1 df['2016'].astype('float')

[一些错误信息]

ValueError: could not convert string to float: '$15,000.00'

以类似的方式,我们可以尝试将 Jan Units 列转换为整数:

df['Jan Units'].astype('int')
ValueError         Traceback (most recent call last)

<ipython-input-44-31333711e4a4> in <module>()
----> 1 df['Jan Units'].astype('int')

[一些错误信息]


ValueError: invalid literal for int() with base 10: 'Closed'

这两个都返回 ValueError 异常,这意味着转换不起作用。

在这两个例子中,数据都包含不能被解释为数字的值。在销售额(2016)列中,数据包括货币符号以及每个值中的逗号。在 Jan Units 列中,最后一个值是 "Closed",它不是一个数字;所以我们得到了异常。

到目前为止,astype() 作为工具看起来并不怎么好。我们在 Active 列中再试一次。

df['Active'].astype('bool')
0    True
1    True
2    True
3    True
4    True
Name: Active, dtype: bool

第一眼,这看起来不错,但经过仔细检查,存在一个大问题。所有的值都被解释为 True,但最后一个客户有一个 N 的活动(Active)标志,所以这并不正确。

这一节的重点是 astype() 只有在下列情况下才能工作:

  • 数据是干净的,可以简单地解释为一个数字
  • 你想要将一个数值转换为一个字符串对象

如果数据具有非数字字符或它们间不同质(homogeneous),那么 astype() 并不是类型转换的好选择。你需要进行额外的变换才能完成正确的类型转换。

相关阅读:Pandas 数据类型概览(下篇)

本文来自网易实践者社区,经作者徐子航授权发布。