数据分析(四)--pandas入门

Pandas入门

在安装 Pandas 之前,确保你的操作系统中有 NumPy。如果你是从源代码直接编译,那么还需要相应的工具编译建立 Pandas 所需的 C 语言与 Cython 代码。如果你按照我的建议使用了 Anaconda,那么 Pandas 就已经安装好了。

和之前导入 NumPy 并使用别名 np 一样,我们将导入 Pandas 并使用别名 pd:

In[1]: import numpy as np
    import pandas as pd

1. Pandas对象简介

如果从底层视角观察 Pandas 对象,可以把它们看成增强版的 NumPy 结构化数组,行列都不再只是简单的整数索引,还可以带上标签。 Pandas 的三个基本数据结构: Series、 DataFrame 和 Index。

1.1 Pandas的 Series对象

Pandas 的 Series 对象是一个带索引数据构成的一维数组。可以用一个数组创建 Series 对象:

In[2]: data = pd.Series([0.25, 0.5, 0.75, 1.0])
    data

Out[2]: 0 0.25
        1 0.50
        2 0.75
        3 1.00
        dtype: float64

从上面的结果中,你会发现 Series 对象将一组数据和一组索引绑定在一起,我们可以通过values 属性和 index 属性获取数据。 values 属性返回的结果与 NumPy 数组类似:

In[3]: data.values

Out[3]: array([ 0.25, 0.5 , 0.75, 1. ])

# index 属性返回的结果是一个类型为 pd.Index 的类数组对象
In[4]: data.index

Out[4]: RangeIndex(start=0, stop=4, step=1)

# 和 NumPy 数组一样,数据可以通过 Python 的中括号索引标签获取:
In[5]: data[1]

Out[5]: 0.5

In[6]: data[1:3]

Out[6]: 1 0.50
        2 0.75
        dtype: float64

但是我们将会看到, Pandas 的 Series 对象比它模仿的一维NumPy数组更加通用、灵活。

1.1.1 Serise是通用的NumPy数组

NumPy 数组通过隐式定义的整数索引获取数值,而 Pandas 的Series 对象用一种显式定义的索引与数值关联。显式索引的定义让 Series 对象拥有了更强的能力。

索引不再仅仅是整数,还可以是任意想要的类型。如果需要,完全可以用字符串定义索引:

In[7]: data = pd.Series([0.25, 0.5, 0.75, 1.0],
    index=['a', 'b', 'c', 'd'])
    data

Out[7]: a 0.25
        b 0.50
        c 0.75
        d 1.00
        dtype: float64

获取数值的方式与之前一样:

In[8]: data['b']

Out[8]: 0.5

# 也可以使用不连续或不按顺序的索引:
In[9]: data = pd.Series([0.25, 0.5, 0.75, 1.0],
    index=[2, 5, 3, 7])
    data

Out[9]: 2 0.25
        5 0.50
        3 0.75
        7 1.00
        dtype: float64

In[10]: data[5]

Out[10]: 0.5

1.1.2 Series是特殊的字典

你可以把 Pandas 的 Series 对象看成一种特殊的 Python 字典。字典是一种将任意键映射到一组任意值的数据结构,而 Series 对象其实是一种将类型键映射到一组类型值的数据结构。类型至关重要:就像 NumPy 数组背后特定类型的经过编译的代码使得它在某些操作上比普通的 Python 列表更加高效一样, Pandas Series 的类型信息使得它在某些操作上比Python 的字典更高效。

我们可以直接用 Python 的字典创建一个 Series 对象,让 Series 对象与字典的类比更加清晰:

In[11]: population_dict = {'California': 38332521,
                        'Texas': 26448193,
                        'New York': 19651127,
                        'Florida': 19552860,
                        'Illinois': 12882135}
        population = pd.Series(population_dict)
        population

Out[11]: California 38332521
        Florida 19552860
        Illinois 12882135
        New York 19651127
        Texas 26448193
        dtype: int64

用字典创建 Series 对象时,其索引默认按照顺序排序。典型的字典数值获取方式仍然有效:

In[12]: population['California']

Out[12]: 38332521

和字典不同, Series 对象还支持数组形式的操作,比如切片:

In[13]: population['California':'Illinois']

Out[13]: California 38332521
        Florida 19552860
        Illinois 12882135
        dtype: int64

1.1.3 创建Serise对象

我们已经见过几种创建 Pandas 的 Series 对象的方法,都是像这样的形式:

pd.Series(data, index=index)
# 其中, index 是一个可选参数, data 参数支持多种数据类型。

data 可以是列表或 NumPy 数组,这时 index 默认值为整数序列:

In[14]: pd.Series([2, 4, 6])
Out[14]: 0 2
        1 4
        2 6
        dtype: int64

# data 也可以是一个标量,创建 Series 对象时会重复填充到每个索引上:
In[15]: pd.Series(5, index=[100, 200, 300])
Out[15]: 100 5
        200 5
        300 5
        dtype: int64

# data 还可以是一个字典, index 默认是排序的字典键:
In[16]: pd.Series({2:'a', 1:'b', 3:'c'})
Out[16]: 1 b
        2 a
        3 c
        dtype: object

# 每一种形式都可以通过显式指定索引筛选需要的结果:
In[17]: pd.Series({2:'a', 1:'b', 3:'c'}, index=[3, 2])
Out[17]: 3 c
        2 a
        dtype: object

这里需要注意的是, Series 对象只会保留显式定义的键值对。

1.2 Pandas的DataFrame对象

1.2.1 DataFrame是通用的NumPy数组

如果将 Series 类比为带灵活索引的一维数组,那么 DataFrame 就可以看作是一种既有灵活的行索引,又有灵活列名的二维数组。

In[18]:
area_dict = {'California': 423967, 'Texas': 695662, 'New York': 141297,
'Florida': 170312, 'Illinois': 149995}
area = pd.Series(area_dict)
area

Out[18]: California 423967
        Florida 170312
        Illinois 149995
        New York 141297
        Texas 695662
        dtype: int64
# 再结合之前创建的 population 的 Series 对象,用一个字典创建一个包含这些信息的二维对象:
In[19]: states = pd.DataFrame({'population': population,'area': area})
        states
Out[19]:             area     population
        California   423967   38332521
        Florida      170312   19552860
        Illinois     149995   12882135
        New York     141297   19651127
        Texas        695662   26448193

和 Series 对象一样, DataFrame 也有一个 index 属性可以获取索引标签:

In[20]: states.index
Out[20]:
Index(['California', 'Florida', 'Illinois', 'New York', 'Texas'], dtype='object')

# 另外, DataFrame 还有一个 columns 属性,是存放列标签的 Index 对象:
In[21]: states.columns
Out[21]: Index(['area', 'population'], dtype='object')

因此 DataFrame 可以看作一种通用的 NumPy 二维数组,它的行与列都可以通过索引获取。

1.2.2 DataFrame是特殊的字典

与 Series 类似,我们也可以把 DataFrame 看成一种特殊的字典。字典是一个键映射一个值,而DataFrame 是一列映射一个 Series 的数据。例如,通过 ‘area’ 的列属性可以返回包含面积数据的 Series 对象:

In[22]: states['area']
Out[22]: California   423967
        Florida      170312
        Illinois     149995
        New York     141297
        Texas        695662
        Name: area, dtype: int64

这里需要注意的是,在 NumPy 的二维数组里, data[0] 返回第一行;而在 DataFrame 中,data[‘col0’] 返回第一列。因此,最好把 DataFrame 看成一种通用字典,而不是通用数组,即使这两种看法在不同情况下都是有用的。

1.2.3 创建DataFrame对象

(1)通过单个 Series 对象创建。 DataFrame 是一组 Series 对象的集合,可以用单个 Series创建一个单列的 DataFrame:

In[23]: pd.DataFrame(population, columns=['population'])
Out[23]:               population
        California     38332521
        Florida        19552860
        Illinois       12882135
        New York       19651127
        Texas          26448193

(2) 通过字典列表创建。任何元素是字典的列表都可以变成 DataFrame。用一个简单的列表综合来创建一些数据:

In[24]: data = [{'a': i, 'b': 2 * i} for i in range(3)]
        pd.DataFrame(data)
Out[24]:   a b
        0 0 0
        1 1 2
        2 2 4

# 即使字典中有些键不存在, Pandas 也会用缺失值 NaN(不是数字, not a number)来表示:
In[25]: pd.DataFrame([{'a': 1, 'b': 2}, {'b': 3, 'c': 4}])
Out[25]:    a   b  c
        0  1.0  2  NaN
        1  NaN  3  4.0

(3) 通过 Series 对象字典创建。就像之前见过的那样, DataFrame也可以用一个由Series对象构成的字典创建:

In[26]: pd.DataFrame({'population': population,'area': area})
Out[26]:             area     population
        California   423967   38332521
        Florida      170312   19552860
        Illinois     149995   12882135
        New York     141297   19651127
        Texas        695662   26448193

(4) 通过 NumPy 二维数组创建。假如有一个二维数组,就可以创建一个可以指定行列索引值DataFrame。如果不指定行列索引值,那么行列默认都是整数索引值:

In[27]: pd.DataFrame(np.random.rand(3, 2),
                    columns=['foo', 'bar'],
                    index=['a', 'b', 'c'])
Out[27]:    foo         bar
        a   0.865257   0.213169
        b   0.442759   0.108267
        c   0.047110   0.905718

(5) 通过 NumPy 结构化数组创建。

1.3 Pandas的index对象

Series 和 DataFrame 对象都使用便于引用和调整的显式索引。 Pandas 的Index 对象是一个很有趣的数据结构,可以将它看作是一个不可变数组或有序集合(实际上是一个多集,因为 Index 对象可能会包含重复值)。这两种观点使得 Index 对象能呈现一些有趣的功能。让我们用一个简单的整数列表来创建一个 Index 对象:

In[30]: ind = pd.Index([2, 3, 5, 7, 11])
        ind
Out[30]: Int64Index([2, 3, 5, 7, 11], dtype='int64')

1.3.1 将Index看作不可变数组

Index 对象的许多操作都像数组。例如,可以通过标准 Python 的取值方法获取数值,也可以通过切片获取数值:

In[7]: x = np.array([2, 1, 4, 3, 5])
    i = np.argsort(x)
    print(i)
[1 0 3 2 4]

以上结果的第一个元素是数组中最小元素的索引值,第二个值给出的是次小元素的索引值,以此类推。这些索引值可以被用于(通过花哨的索引)创建有序的数组:

In[31]: ind[1]
Out[31]: 3

In[32]: ind[::2]
Out[32]: Int64Index([2, 5, 11], dtype='int64')

# Index 对象还有许多与 NumPy 数组相似的属性:
In[33]: print(ind.size, ind.shape, ind.ndim, ind.dtype)
5 (5,) 1 int64

Index 对象与 NumPy 数组之间的不同在于, Index 对象的索引是不可变的,也就是说不能通过通常的方式进行调整:

In[34]: ind[1] = 0
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-34-40e631c82e8a> in <module>()
----> 1 ind[1] = 0
/Users/jakevdp/anaconda/lib/python3.5/site-packages/pandas/indexes/base.py ...
   1243
   1244 def __setitem__(self, key, value):
-> 1245 raise TypeError("Index does not support mutable operations")
   1246
   1247 def __getitem__(self, key):
TypeError: Index does not support mutable operations

Index 对象的不可变特征使得多个 DataFrame 和数组之间进行索引共享时更加安全,尤其是可以避免因修改索引时粗心大意而导致的副作用。

1.3.2 将Index看作有序集合

Pandas 对象被设计用于实现许多操作,如连接(join)数据集,其中会涉及许多集合操作。

Index 对象遵循 Python 标准库的集合(set)数据结构的许多习惯用法,包括并集、交集、差集等:

In[35]: indA = pd.Index([1, 3, 5, 7, 9])
        indB = pd.Index([2, 3, 5, 7, 11])
In[36]: indA & indB # 交集
Out[36]: Int64Index([3, 5, 7], dtype='int64')

In[37]: indA | indB # 并集
Out[37]: Int64Index([1, 2, 3, 5, 7, 9, 11], dtype='int64')

In[38]: indA ^ indB # 异或
Out[38]: Int64Index([1, 2, 9, 11], dtype='int64')

这些操作还可以通过调用对象方法来实现,例如 indA.intersection(indB)。

猜你喜欢

转载自blog.csdn.net/u014793102/article/details/80849510