数据分析之Pandas——数据结构

数据结构介绍

Pandas的数据对象中都包含最基本的属性,如数据类型,索引,标签等。
要使用Pandas的数据结构首先需要引入pandas和numpy:

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

有一个基本原则要牢记:数据对齐是默认的。数据和标签的关联不会被破坏,除非认为更改。
本章将做一个关于数据结构的简介,然后在其他章节中做更全面的介绍。

Series

Series 是一维标签数组,能够保存任何数据类型(整型,浮点型,字符串或其他Python对象类型)。轴标签被称为索引。创建一个最基本的Series结构,代码如下:

s = pd.Series(data, index=index)

data可以是很多类型:

  • 一个 Python 字典
  • 一个 ndarray 对象
  • 一个标量值(如5)

index是轴标签的列表。因此,这将根据data的不同分为几种情况:


由ndarray构造

如果传递的data是一个ndarray对象,index的长度必须和data的长度保持一致。如果没有对index参数赋值,那么索引值会默认为[0, … , len(data) -1],即由0开始,与data数据等长的递增列表。

In [3]: s = pd.Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])

这里构造了一个名为s的Serise对象,其data为5个随机数,那么对应的index长度也为5, 分别为a至e的小写字母。
那么s打印出来的结果如下:

In [4]: s
Out[4]: 
a   -1.317092
b    0.898475
c   -0.026741
d   -0.090660
e   -0.783084
dtype: float64

通过输入s.index可以查看索引

In [6]: s.index
Out[6]: Index([u'a', u'b', u'c', u'd', u'e'], dtype='object')

如果不为index参数赋值,那么构造的Series对象结果为

In [7]: s = pd.Series(np.random.randn(5))

In [8]: s
Out[8]: 
0   -2.750907
1    2.402623
2   -2.479244
3    1.826535
4   -1.270192
dtype: float64

注意:从v0.8.0开始,pandas可以支持索引值不唯一。
如:
In [6]: s = pd.Series(np.random.randn(5), index=[‘a’, ‘b’, ‘b’, ‘c’, ‘d’])
In [7]: s
Out[7]:
a 0.285951
b -0.153731
b 0.536586
c 2.156944
d -0.113776
dtype: float64


由dict 字典类型构造

如果传递的data是一个dict字典类型对象,并且传递了index参数,那么对应的值将从字典中取出。

In [8]: d = {
  'a':0, 'b':1, 'c':2}

In [11]: pd.Series(d, index=['b','c','d', 'a'])
Out[11]: 
b     1
c     2
d   NaN
a     0
dtype: float64

注意:NaN(not a number)是Pandas中使用的数据缺失的标记,由于data中没有包含key为’d’的数据,所以返回数据缺失,标记为NaN。

否则,index的值将由字典对象里的key值进行构造。

In [8]: d = {
  'a':0, 'b':1, 'c':2}

In [9]: pd.Series(d)
Out[9]: 
a    0
b    1
c    2
dtype: int64

由标量值构造

如果传递的data是一个标量值,那么Index参数必须提供。其构造的二维数组对象将根据索引的长度进行重复。

In [12]: pd.Series(5, index=['b', 'c', 'd', 'a'])
Out[12]: 
b    5
c    5
d    5
a    5
dtype: int64

Series类似于ndarray

Serise扮演的角色非常类似ndarray,并且它可以作为大多数Numpy函数的参数。也可以通过对索引切割来进行数据切片。

In [14]: s[0]
Out[14]: 0.28595142701029524

In [15]: s[:3]
Out[15]: 
a    0.285951
b   -0.153731
b    0.536586
dtype: float64

In [16]: s[s > s.median()]
Out[16]: 
b    0.536586
c    2.156944
dtype: float64

In [17]: s[[4, 3, 1]]
Out[17]: 
d   -0.113776
c    2.156944
b   -0.153731
dtype: float64

In [18]: np.exp(s)
Out[18]: 
a    1.331028
b    0.857502
b    1.710159
c    8.644678
d    0.892458
dtype: float64

Series类似于dict

Series类似于定长的字典对象,你可以通过index标签获取或设置值。

In [19]: s['a']
Out[19]: 0.28595142701029524

In [20]: s['c'] = 12

In [21]: s
Out[21]: 
a     0.285951
b    -0.153731
b     0.536586
c    12.000000
d    -0.113776

In [22]: 'b' in s
Out[22]: True

In [23]: 'e' in s
Out[23]: False

如果输入的标签不存在,那么将报异常:

In [24]: s['e']
KeyError: 'e'

如果使用get方法,不存在的标签将会返回空值或指定默认值:

In [25]: s.get('e')

In [26]: s.get('e', np.nan)
Out[26]: nan

向量操作和标签对齐

当做数据分析时, 和Numpy的数组一样,一个一个的循环遍历Series中的值通常是不必要的。Series对象也可以像ndarray一样,传递到大多数Numpy方法中。

In [27]: s + s
Out[27]: 
a     0.571903
b    -0.307463
b     1.073173
c    24.000000
d    -0.227552
dtype: float64

In [28]: s * 2
Out[28]: 
a     0.571903
b    -0.307463
b     1.073173
c    24.000000
d    -0.227552
dtype: float64

In [29]: np.exp(s)
Out[29]: 
a         1.331028
b         0.857502
b         1.710159
c    162754.791419
d         0.892458
dtype: float64

Series和ndarray关键的区别在于,Series间的操作会自动根据标签对齐数据。因此,你可以直接编写计算,而不用考虑所涉及到的Series是否具有相同的标签。

In [30]: s[1:] + s[:-1]
Out[30]: 
a          NaN
b    -0.307463
b     0.382855
b     0.382855
b     1.073173
c    24.000000
d          NaN
dtype: float64

在未对齐的Series间操作,结果将包含索引的集合。如果标签在一个或另一个Series中未找到,结果将标记为缺失NaN。所以可以在不进行任何显示数据对齐的情况下编写代码,在交互数据分析和研究中提供了巨大的自由度和灵活性。Pandas数据结构的综合数据排列特征使Pandas有别于大多数用于标记数据的相关工具。

Name 属性

Series也有Name属性

In [31]: s = pd.Series(np.random.randn(5), name='something')

In [32]: s
Out[32]: 
0    1.522774
1    0.733561
2   -0.702462
3    0.022205
4    1.704067
Name: something, dtype: float64

许多情况下,Series的Name将被自动分配,特别是下面即将看到的对于DataFrame的一维切片时。
可以通过方法pandas.Series.rename()对Series进行重命名。

In [33]: s2 = s.rename("different")

In [34]: s2.name
Out[35]: 'different'

注意s和s2分别引用的是两个不同的对象。

DataFrame

DataFrame是一个2维标签的数据结构,它的列可以存在不同的类型。你可以把它简单的想成Excel表格或SQL Table,或者是包含字典类型的Series。它是最常用的Pandas对象。和Series一样,DataFrame接受许多不同的类型输入:

  • 包含1维ndarray,列表对象,字典对象或者Series对象的字典对象
  • 2维的ndarray对象
  • 结构化或记录型的ndarray
  • Series对象
  • 另一个DataFrame对象

可以通过传递索引(行标签)和列(列标签)参数来操作数据。如果传递了索引和/或列,可以得到包含索引和/或列的DataFrame结果集。因此,一个字典类型的Series加上一个特定的索引,将会丢弃所有与传递的所以不匹配的数据。

如果没有传递轴标签,他们将基于常用规则的输入数据进行创建。

由包含Series的字典或嵌套字典构造

结果的索引将是各个Series索引的并集。如果有任何嵌套的字典对象,都将先转换成Series。如果没有传递任何列,那么列将是已排序的字典对象的Key值。

In [20]: d = {
  'one' : pd.Series([1., 2., 3.], index=['a', 'b', 'c']),
    ...: 'two': pd.Series([1., 2., 3., 4.], index=['a', 'b', 'c', 'd'])}

In [21]: df = pd.DataFrame(d)

In [22]: df
Out[22]: 
   one  two
a    1    1
b    2    2
c    3    3
d  NaN    4

In [23]: pd.DataFrame(d, index=['d', 'b', 'a'])
Out[23]: 
   one  two
d  NaN    4
b    2    2
a    1    1

In [24]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
Out[24]: 
   two three
d    4   NaN
b    2   NaN
a    1   NaN

通过访问索引和列属性,可以分别访问行和列标签:

In [25]: df.index
Out[25]: Index([u'a', u'b', u'c', u'd'], dtype='object')

df.columns
Out[26]: Index([u'one', u'two'], dtype='object')

由包含ndarray或列表的字典构造

ndarray的长度必须一致。如果一个索引被传递,它必须与数组的长度相同。如果没有索引被传递,结果将是range(n),n是数组的长度。

In [27]: d = {
  'one':[1., 2., 3., 4.],
    ...: 'two': [4., 3., 2., 1.]}

In [28]: pd.DataFrame(d)
Out[28]: 
   one  two
0    1    4
1    2    3
2    3    2
3    4    1

In [29]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
Out[29]: 
   one  two
a    1    4
b    2    3
c    3    2
d    4    1

由数组构造

这个例子的处理与数组字典的完全相同

In [39]: data = np.zeros((2,), dtype=[('A', 'i4'), ('B', 'f4'), ('C', 'a10')])

In [40]: data[:] = [(1, 2., 'Hello'), (2, 3., 'World')]

In [41]: pd.DataFrame(data)
Out[41]: 
   A  B      C
0  1  2  Hello
1  2  3  World

In [42]: pd.DataFrame(data, index=['first', 'second'])
Out[42]: 
        A  B      C
first   1  2  Hello
second  2  3  World

In [43]: pd.DataFrame(data, columns=['C', 'A', 'B'])
Out[43]: 
       C  A  B
0  Hello  1  2
1  World  2  3

注意:DataFrame的工作方式与2维的ndarray并不一样

由包含字典的列表构造

In [44]: data = [{
  'a': 1, 'b': 2}, {
  'a': 5, 'b': 10, 'c': 20}]

In [45]: pd.DataFrame(data)
Out[45]: 
   a   b   c
0  1   2 NaN
1  5  10  20

In [47]: pd.DataFrame(data, index=['first', 'second'])
Out[47]: 
        a   b   c
first   1   2 NaN
second  5  10  20

In [48]: pd.DataFrame(data, columns=['a', 'b'])
Out[48]: 
   a   b
0  1   2
1  5  10

由包含元组的字典构造

In [49]: pd.DataFrame({('a', 'b'): {('A', 'B'): 1, ('A', 'C'): 2},
    ...:               ('a', 'a'): {('A', 'C'): 3, ('A', 'B'): 4},
    ...:               ('a', 'c'): {('A', 'B'): 5, ('A', 'C'): 6},
    ...:               ('b', 'a'): {('A', 'C'): 7, ('A', 'B'): 8},
    ...:               ('b', 'b'): {('A', 'D'): 9, ('A', 'B'): 10}})
Out[49]: 
      a           b    
      a   b   c   a   b
A B   4   1   5   8  10
  C   3   2   6   7
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值