Pandas的数据结构

目录

 

概述

Series

Series的创建

like-array类型数据创建Series

Dict创建Series

标量创建Series

Series的特点

Series is ndarray-like

Series is dict-like

矢量化操作和标签自动对齐

Name属性 

DataFrame

DataFrame的创建

From dict of Series or dicts

From dict of ndarrays / lists

From structured or record array

From a list of dicts

From a dict of tuples

From a Series

DataFrame.from_dict构造函数

DataFrame.from_records构造函数 

列标签的选取、增加、删除

方法链中分配新列(Assigning New Columns in Method Chains)

索引/选择(Indexing / Selection)

数据的对齐和算法(Data alignment and arithmetic)

转置(Transposing) 

与Numpy函数的互操作性(DataFrame interoperability with NumPy functions)

显示控制(Console display)

IPython在DataFrame列属性访问时的自动补全

(DataFrame column attribute access and IPython completion)

小结


概述

Pandas库的数据结构是依赖于Numpy库的ndarray发展而来的.

Pandas中只有三种类型的数据结构,对比如下:

类型 维度(dim) 形状(shape) 元素类型 说明
ndarray(Numpy) 1或2 1×0或者n×m 同构 一维的数组或者多维的矩阵,无索引
Series 1 m×1 非同构 带索引的一维数组
DataFrame 2 m×n 非同构 由多个Series组成的二维表,可以理解为Series容器
Panel 3 m×n×h 非同构 三维,可以理解为DataFrame容器(将被更高版本的Pandas遗弃

鉴于Pandas官方已经声明在以后更高版本的Pandas中,因为使用率低的问题,将抛弃对Pannel的支持,所以本文将不在对Pannel结构进行介绍,仅仅介绍常用的Series和DataFrame. Series和DataFrame数据结构的主要属性:

属性 说明
index 返回索引
columns 返回字段名(列名),Series无该属性,但有name属性
values 返回索引元素组成的array
dtypes 返回元素类型
ndim 返回维度
shape 返回形状
size 返回所有元素个数
itemsize 返回每个元素所占大小(字节为单位),DataFrame无该属性

构造一个用于演示的DataFrame来看看主要的属性:

import pandas as pd
import numpy as np

#制造数据:
np.random.seed(100)
data=np.random.randint(1,10,40).reshape(8,-1)
index=pd.date_range('20180901',periods=8)
col=list('ABCDE')
df=pd.DataFrame(data,index=index,columns=col)
print(df)
#输出:
            A  B  C  D  E
2018-09-01  7  8  1  1  8
2018-09-02  1  5  6  3  2
2018-09-03  3  6  6  1  5
2018-09-04  5  8  6  3  3
2018-09-05  9  9  7  1  1
2018-09-06  8  1  4  5  8
2018-09-07  8  1  2  1  9
2018-09-08  7  8  4  1  6

 查看该对象的属性:

print('index属性: ',df.index)
print('我是分割线'.center(80,'='))
print('columns属性:',df.columns)
print('我是分割线'.center(80,'='))
print('values属性:',df.values)
print('我是分割线'.center(80,'='))
print('dtypes属性:',df.dtypes)
print('我是分割线'.center(80,'='))
print('ndim属性:',df.ndim)
print('我是分割线'.center(80,'='))
print('shape属性:',df.shape)
print('我是分割线'.center(80,'='))
print('size属性:',df.size)
-------------------------------------------------------------------------------------
index属性:  DatetimeIndex(['2018-09-01', '2018-09-02', '2018-09-03', '2018-09-04',
               '2018-09-05', '2018-09-06', '2018-09-07', '2018-09-08'],
              dtype='datetime64[ns]', freq='D')
=====================================我是分割线======================================
columns属性: Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
=====================================我是分割线======================================
values属性: [[9 9 4 8 8]
 [1 5 3 6 3]
 [3 3 2 1 9]
 [5 1 7 3 5]
 [2 6 4 5 5]
 [4 8 2 2 8]
 [8 1 3 4 3]
 [6 9 2 1 8]]
=====================================我是分割线======================================
dtypes属性: A    int32
B    int32
C    int32
D    int32
E    int32
dtype: object
=====================================我是分割线======================================
ndim属性: 2
=====================================我是分割线======================================
shape属性: (8, 5)
=====================================我是分割线======================================
size属性: 40

Series

Series是一维的数据结构,可以理解为继承于的一维的ndarray.

Series同时也是Pandas中的基础性的数据结构,DataFrame的每一列数据都是Series,也就是说Series构成了DataFrame.

Series的创建

Series的创建主要使用pd.Series(data, index)方法

其中data参数可以是数组,字典,列表等等类序列数据,甚至也可以是标量值(比如数字5,字母A)

index参数表示的是Series的索引列表,根据data参数的不同设定不同的index参数.

下面介绍几种主要的Series的创建方式.

like-array类型数据创建Series

如果data参数是like-array(类数组)类型,那么index参数的长度必须与data参数的数组长度一致.

如果不指定index参数的话,那么Pandas将按照[0, ..., len(data) - 1]的原则自动创建index索引

pd.Series(np.random.randint(1,10,4),index=list('abcd'))
Out[4]: 
a    7
b    1
c    4
d    4
dtype: int32

pd.Series([1,2,3],index=['A','B','C'])
Out[5]: 
A    1
B    2
C    3
dtype: int64

Dict创建Series

从dict创建Series若不指定index参数则默认为dict的key

若指定index参数,则指定的index序列与dict.keys序列的交集作有value的索引

而在dict.keys需要中匹配不到的index元素的value值为NaN

NaN是Pandas中的一个标准的缺失值代表,表示not a number的意思

#高版本:
pd.Series({'b' : 1, 'a' : 0, 'c' : 2})
Out[7]: 
b    1
a    0
c    2
dtype: int64

#低版本:
pd.Series({'b' : 1, 'a' : 0, 'c' : 2})
Out[7]: 
a    0
b    1
c    2
dtype: int64

pd.Series({'b' : 1, 'a' : 0, 'c' : 2},index=list('abK'))
Out[8]: 
a    0.0
b    1.0
K    NaN
dtype: float64

从Dcit数据创建的Series对象的数据排列顺序与使用的Python和Pandas版本相关.

Python版本高于3.6,Pandas版本高于0.23,那么数据排列顺序与dict数据插入的顺序一致

若 Python版本低于3.6,Pandas版本低于0.23,那么数据排列顺序以dict中键值的字符顺序为标准.

标量创建Series

如果以标量来创建Series,则必须指定index参数,且Series的value值会自动重复到index参数的长度.

pd.Series(5,index=list('abc'))
Out[9]: 
a    5
b    5
c    5
dtype: int64

Series的特点

Series is ndarray-like

Series数据结构与Numpy的ndarray数据结构是是非相类似的

可以运用绝大部分的Numpy方法和函数,只是切片是针对索引而不是针对数据.

Series切片不仅可以像ndarray一样,同时还可以使用索引进行切片:

s=pd.Series(np.random.randint(1,10,4),index=list('abcdefgh'))

Out[11]: 
a    7
b    6
c    9
d    9
dtype: int32

s[0]
Out[12]: 7

s['a']
Out[13]: 7

s[0:2]
Out[14]: 
a    7
b    6
dtype: int32

s['a':'c']
Out[15]: 
a    7
b    6
c    9
dtype: int32

s[s>8]
Out[16]: 
c    9
d    9
dtype: int32

s[[0,2]]
Out[17]: 
a    7
c    9
dtype: int32


s[['a','c']]
Out[18]: 
a    7
c    9
dtype: int32

np.mean(s)
Out[19]: 6.0

注意:使用索引切片是包含末端,而使用位置切片时不包含末端.

Series is dict-like

Series对象同时也是like-dict类型.也可类似dict一样取值,赋值,删除值和判断.

s['a']
Out[20]: 7

s['pp']=100
s
Out[21]: 
a    7
b    6
c    9
d    9
pp   100
dtype: int32

del s['pp']
s
Out[22]: 
a    7
b    6
c    9
d    9
dtype: int32

'b' in s
Out[23]: True

Series对象也支持字典的get方法

s.get('p',np.NaN)
Out[24]: nan

矢量化操作和标签自动对齐

我们知道在使用Numpy的ndarray数据结构时,因为ndarray支持矢量化,所以对ndarray中的数据进行循环时没必要的

同样在Series中,也支持矢量化.

s+s
Out[25]: 
a    16
b     2
c     4
d    14
dtype: int32

s*2
Out[26]: 
a    16
b     2
c     4
d    14
dtype: int32

同样,我们知道ndarray进行矢量化操作时必须是同形状的,既shape属性一致.

而由于标签自动对齐功能的存在,Series的矢量化再可以直接计算未进行过标签对齐的Series.

在Series中未找到的索引标签将被标记为NaN,这为数据分析带了极大的自由和灵活性.

s[1:]+s[0:-1]
Out[27]: 
a     NaN
b    16.0
c    18.0
d     NaN
dtype: float64

当然产生的缺失值也是可以处理的,参阅Pandas缺失值的处理.

Name属性 

Series的name属性也是很重要的,该属性可以直接修改,也可以重新命名.

区别是直接修改name属性,则是在原对象上修改,而重新命名默认是返回一个新的对象(可以使用参数inplace设置为修改原对象).

此外,Series对象的name属性在创建DaraFrame时可以转化为列标签名

s.name='example'

s1=s.rename('s1')

s
Out[28]: 
a    7
b    6
c    9
d    9
Name: example, dtype: int32

s1
Out[29]: 
a    7
b    6
c    9
d    9
Name: s1, dtype: int32

DataFrame

DataFrame是一个二维的标签数据结构,不同的列标签可以是不同类型的数据,可以简单的理解为SQL表格

或者拥有同样索引的多个Series的集合.

DataFrame的创建

同Series类似,DataFrame也可以从多种不同类型数据来创建.

同样对于从字典结构创建DataFrame也遵循一样的版本原则和索引匹配原则

只是对于DataFrame来说,除了索引的匹配,还多出了columns的匹配.

From dict of Series or dicts

最终构成的DataFrame的索引是Series索引的集合,如果没有指定columns,则默认以字典主键名为列名称.

无法匹配的值同样填充NaN.

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

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

In [36]: df
Out[36]: 
   one  two
a  1.0  1.0
b  2.0  2.0
c  3.0  3.0
d  NaN  4.0

In [37]: pd.DataFrame(d, index=['d', 'b', 'a'])
Out[37]: 
   one  two
d  NaN  4.0
b  2.0  2.0
a  1.0  1.0

In [38]: pd.DataFrame(d, index=['d', 'b', 'a'], columns=['two', 'three'])
Out[38]: 
   two three
d  4.0   NaN
b  2.0   NaN
a  1.0   NaN

DataFrame的index和columns值可以被分别的访问:

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

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

From dict of ndarrays / lists

如果指定index参数,则index的长度必须与ndarray或者list一致.

如果不指定则默认[0, ..., len(ndarray/list) - 1].

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

In [42]: pd.DataFrame(d)
Out[42]: 
   one  two
0  1.0  4.0
1  2.0  3.0
2  3.0  2.0
3  4.0  1.0

In [43]: pd.DataFrame(d, index=['a', 'b', 'c', 'd'])
Out[43]: 
   one  two
a  1.0  4.0
b  2.0  3.0
c  3.0  2.0
d  4.0  1.0

From structured or record array

这种情况与数组的字典处理相同.

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

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

In [46]: pd.DataFrame(data)
Out[46]: 
   A    B         C
0  1  2.0  b'Hello'
1  2  3.0  b'World'

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

In [48]: pd.DataFrame(data, columns=['C', 'A', 'B'])
Out[48]: 
          C  A    B
0  b'Hello'  1  2.0
1  b'World'  2  3.0

From a list of dicts

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

In [50]: pd.DataFrame(data2)
Out[50]: 
   a   b     c
0  1   2   NaN
1  5  10  20.0

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

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

From a dict of tuples

通过传递元组字典,可以自动创建多索引框架:

In [53]: 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[53]: 
       a              b      
       b    a    c    a     b
A B  1.0  4.0  5.0  8.0  10.0
  C  2.0  3.0  6.0  7.0   NaN
  D  NaN  NaN  NaN  NaN   9.0

From a Series

最后构造的DataFrame的索引将和Series一致,如果没有指定columns,则以Series的name属性作为列标签.

s=pd.Series(np.random.randint(1,10,4),index=list('abcd'),name='number')

df=pd.DataFrame(s)

df
Out[54]: 
   number
a       6
b       1
c       6
d       4

DataFrame.from_dict构造函数

DataFrame.from_dict 方法接收一个值为类ndarray序列的字典,并返回一个DataFrame.

这个方法与DaraFrame的构造方法类似,只是orient参数的默认值被设置为了'cloumns',而DaraFrame的索引也采用默认值.

In [54]: pd.DataFrame.from_dict(dict([('A', [1, 2, 3]), ('B', [4, 5, 6])]))
Out[54]: 
   A  B
0  1  4
1  2  5
2  3  6

当然,也可以将orient参数的值该为'index',并指定columns参数.

In [55]: pd.DataFrame.from_dict(dict([('A', [1, 2, 3]), ('B', [4, 5, 6])]),
   ....:                        orient='index', columns=['one', 'two', 'three'])
   ....: 
Out[55]: 
   one  two  three
A    1    2      3
B    4    5      6

DataFrame.from_records构造函数 

from_records方法接受元组列表或具有结构化dtype的ndarray。它与普通的DataFrame构造函数类似,只是产生的DataFrame索引可能是结构化dtype的特定字段.

In [56]: data
Out[56]: 
array([(1,  2., b'Hello'), (2,  3., b'World')],
      dtype=[('A', '

列标签的选取、增加、删除

可以将DataFrame对象看作一个类dict的对象,列标签(columns)的获取,增加,删除与dict操作主键的方式一致.

In [58]: df['one']
Out[58]: 
a    1.0
b    2.0
c    3.0
d    NaN
Name: one, dtype: float64

In [59]: df['three'] = df['one'] * df['two']

In [60]: df['flag'] = df['one'] > 2

In [61]: df
Out[61]: 
   one  two  three   flag
a  1.0  1.0    1.0  False
b  2.0  2.0    4.0  False
c  3.0  3.0    9.0   True
d  NaN  4.0    NaN  False

 DataFrame列标签(columns)的不仅删除方式与dict一致,同时也支持dict的pop方法.

In [62]: del df['two']

In [63]: three = df.pop('three')

In [64]: df
Out[64]: 
   one   flag
a  1.0  False
b  2.0  False
c  3.0   True
d  NaN  False

当插入的是标量值时,会自动的复制填充:

In [65]: df['foo'] = 'bar'

In [66]: df
Out[66]: 
   one   flag  foo
a  1.0  False  bar
b  2.0  False  bar
c  3.0   True  bar
d  NaN  False  bar

当插入的Series与DataFrame的索引不一致,会自动匹配并填充缺失值:

In [67]: df['one_trunc'] = df['one'][:2]

In [68]: df
Out[68]: 
   one   flag  foo  one_trunc
a  1.0  False  bar        1.0
b  2.0  False  bar        2.0
c  3.0   True  bar        NaN
d  NaN  False  bar        NaN

在默认的情况下,新插入的列会被放在最后,但insert方法可以指定插入数据的位置:

In [69]: df.insert(1, 'bar', df['one'])

In [70]: df
Out[70]: 
   one  bar   flag  foo  one_trunc
a  1.0  1.0  False  bar        1.0
b  2.0  2.0  False  bar        2.0
c  3.0  3.0   True  bar        NaN
d  NaN  NaN  False  bar        NaN

方法链中分配新列(Assigning New Columns in Method Chains)

DataFrame的assign方法可以在现在存在的DataFrame基础上派生出的新的列:

In [71]: iris = pd.read_csv('data/iris.data')

In [72]: iris.head()
Out[72]: 
   SepalLength  SepalWidth  PetalLength  PetalWidth         Name
0          5.1         3.5          1.4         0.2  Iris-setosa
1          4.9         3.0          1.4         0.2  Iris-setosa
2          4.7         3.2          1.3         0.2  Iris-setosa
3          4.6         3.1          1.5         0.2  Iris-setosa
4          5.0         3.6          1.4         0.2  Iris-setosa

In [73]: (iris.assign(sepal_ratio = iris['SepalWidth'] / iris['SepalLength'])
   ....:      .head())
   ....: 
Out[73]: 
   SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio
0          5.1         3.5          1.4         0.2  Iris-setosa       0.6863
1          4.9         3.0          1.4         0.2  Iris-setosa       0.6122
2          4.7         3.2          1.3         0.2  Iris-setosa       0.6809
3          4.6         3.1          1.5         0.2  Iris-setosa       0.6739
4          5.0         3.6          1.4         0.2  Iris-setosa       0.7200

上面的例子上,我们插入的是一个预算计算的值,我们也可以插入一个只有一个参数的函数方法:

In [74]: iris.assign(sepal_ratio = lambda x: (x['SepalWidth'] /
   ....:                                      x['SepalLength'])).head()
   ....: 
Out[74]: 
   SepalLength  SepalWidth  PetalLength  PetalWidth         Name  sepal_ratio
0          5.1         3.5          1.4         0.2  Iris-setosa       0.6863
1          4.9         3.0          1.4         0.2  Iris-setosa       0.6122
2          4.7         3.2          1.3         0.2  Iris-setosa       0.6809
3          4.6         3.1          1.5         0.2  Iris-setosa       0.6739
4          5.0         3.6          1.4         0.2  Iris-setosa       0.7200

注意的是,assign方法返回的也是一个元数据的拷贝值,以保持原数据的不可变.

在3.6版本之后的Python中,assign方法开始支持**kwargs类型的参数.

这允许依赖式的分配,在新的列对象创造出来之前在表达式中引用相同的参数.

In [76]: dfa = pd.DataFrame({"A": [1, 2, 3],
   ....:                     "B": [4, 5, 6]})
   ....: 

In [77]: dfa.assign(C=lambda x: x['A'] + x['B'],
   ....:            D=lambda x: x['A'] + x['C'])
   ....: 
Out[77]: 
   A  B  C   D
0  1  4  5   6
1  2  5  7   9
2  3  6  9  12

 依赖式引用需要注意一下python版本的差别.

在3.5及更早的Python版本中,即使表达式引用的值在表达式中已经被更新,但依赖引用时所引用的只能是最初的旧值:

#3.5及更早版本的Python
dependent = pd.DataFrame({"A": [1, 1, 1]})
dependent.assign(A=lambda x: x["A"] + 1,
                     B=lambda x: x["A"] + 2)

Out[80]: 
   A  B
0  2  3
1  2  3
2  2  3

而在3.6版本之后的python中,表达式引用的值可以同步更新:

#3.6及之后版本的Python
dependent = pd.DataFrame({"A": [1, 1, 1]})
dependent.assign(A=lambda x: x["A"] + 1,
                     B=lambda x: x["A"] + 2)

Out[81]: 
   A  B
0  2  4
1  2  4
2  2  4

索引/选择(Indexing / Selection)

索引的基础原则如下:

操作 语法 返回结果
列标签选择 df[col] Series
行标签选择 df.loc[label] Series
行位置选择 df.iloc[loc] Series
行的切片 df[1:5] DataFrame
bool向量的行选择 df[bool_ver] DataFrame

 单行的数据选择,返回的是列标签为索引的Series.

In [80]: df.loc['b']
Out[80]: 
one              2
bar              2
flag         False
foo            bar
one_trunc        2
Name: b, dtype: object

In [81]: df.iloc[2]
Out[81]: 
one             3
bar             3
flag         True
foo           bar
one_trunc     NaN
Name: c, dtype: object

更多的原因数据索引和选择的信息,可以参阅另一篇博文: Pandas数据的索引和选择.

数据的对齐和算法(Data alignment and arithmetic)

在DataFrame中,数据的自动对齐不仅仅是index属性了,还包含columns属性.

对齐后的DataFrame的index和columns值都将是唯一的.

In [82]: df = pd.DataFrame(np.random.randn(10, 4), columns=['A', 'B', 'C', 'D'])

In [83]: df2 = pd.DataFrame(np.random.randn(7, 3), columns=['A', 'B', 'C'])

In [84]: df + df2
Out[84]: 
        A       B       C   D
0  0.0457 -0.0141  1.3809 NaN
1 -0.9554 -1.5010  0.0372 NaN
2 -0.6627  1.5348 -0.8597 NaN
3 -2.4529  1.2373 -0.1337 NaN
4  1.4145  1.9517 -2.3204 NaN
5 -0.4949 -1.6497 -1.0846 NaN
6 -1.0476 -0.7486 -0.8055 NaN
7     NaN     NaN     NaN NaN
8     NaN     NaN     NaN NaN
9     NaN     NaN     NaN NaN

在DataFrame和Series之间执行操作时,默认是在DataFrame列上对齐Series索引,再在行方向上进行广播.

In [85]: df - df.iloc[0]
Out[85]: 
        A       B       C       D
0  0.0000  0.0000  0.0000  0.0000
1 -1.3593 -0.2487 -0.4534 -1.7547
2  0.2531  0.8297  0.0100 -1.9912
3 -1.3111  0.0543 -1.7249 -1.6205
4  0.5730  1.5007 -0.6761  1.3673
5 -1.7412  0.7820 -1.2416 -2.0531
6 -1.2408 -0.8696 -0.1533  0.0004
7 -0.7439  0.4110 -0.9296 -0.2824
8 -1.1949  1.3207  0.2382 -1.4826
9  2.2938  1.8562  0.7733 -1.4465

在处理时间序列数据的特殊情况下,DataFrame索引也包含日期,广播将按列进行

In [86]: index = pd.date_range('1/1/2000', periods=8)

In [87]: df = pd.DataFrame(np.random.randn(8, 3), index=index, columns=list('ABC'))

In [88]: df
Out[88]: 
                 A       B       C
2000-01-01 -1.2268  0.7698 -1.2812
2000-01-02 -0.7277 -0.1213 -0.0979
2000-01-03  0.6958  0.3417  0.9597
2000-01-04 -1.1103 -0.6200  0.1497
2000-01-05 -0.7323  0.6877  0.1764
2000-01-06  0.4033 -0.1550  0.3016
2000-01-07 -2.1799 -1.3698 -0.9542
2000-01-08  1.4627 -1.7432 -0.8266

In [89]: type(df['A'])
Out[89]: pandas.core.series.Series

In [90]: df - df['A']
Out[90]: 
            2000-01-01 00:00:00  2000-01-02 00:00:00  2000-01-03 00:00:00  \
2000-01-01                  NaN                  NaN                  NaN   
2000-01-02                  NaN                  NaN                  NaN   
2000-01-03                  NaN                  NaN                  NaN   
2000-01-04                  NaN                  NaN                  NaN   
2000-01-05                  NaN                  NaN                  NaN   
2000-01-06                  NaN                  NaN                  NaN   
2000-01-07                  NaN                  NaN                  NaN   
2000-01-08                  NaN                  NaN                  NaN   

            2000-01-04 00:00:00 ...  2000-01-08 00:00:00   A   B   C  
2000-01-01                  NaN ...                  NaN NaN NaN NaN  
2000-01-02                  NaN ...                  NaN NaN NaN NaN  
2000-01-03                  NaN ...                  NaN NaN NaN NaN  
2000-01-04                  NaN ...                  NaN NaN NaN NaN  
2000-01-05                  NaN ...                  NaN NaN NaN NaN  
2000-01-06                  NaN ...                  NaN NaN NaN NaN  
2000-01-07                  NaN ...                  NaN NaN NaN NaN  
2000-01-08                  NaN ...                  NaN NaN NaN NaN  

[8 rows x 11 columns]

警告:

该之前的版本中,一下的减法形式将被弃用:

df - df['A']

而应该采用新的方式:

df.sub(df['A'], axis=0)

与标量的操作仍然会自动的广播:

In [91]: df * 5 + 2
Out[91]: 
                 A       B       C
2000-01-01 -4.1341  5.8490 -4.4062
2000-01-02 -1.6385  1.3935  1.5106
2000-01-03  5.4789  3.7087  6.7986
2000-01-04 -3.5517 -1.0999  2.7487
2000-01-05 -1.6617  5.4387  2.8822
2000-01-06  4.0165  1.2252  3.5081
2000-01-07 -8.8993 -4.8492 -2.7710
2000-01-08  9.3135 -6.7158 -2.1330

bool值的操作也同样支持:

符号 含义
& 类似逻辑运算and
| 类似逻辑运算or
^ 一真一假为True,其余为False
- 取反
In [94]: df1 = pd.DataFrame({'a' : [1, 0, 1], 'b' : [0, 1, 1] }, dtype=bool)

In [95]: df2 = pd.DataFrame({'a' : [0, 1, 1], 'b' : [1, 1, 0] }, dtype=bool)

In [96]: df1 & df2
Out[96]: 
       a      b
0  False  False
1  False   True
2   True  False

In [97]: df1 | df2
Out[97]: 
      a     b
0  True  True
1  True  True
2  True  True

In [98]: df1 ^ df2
Out[98]: 
       a      b
0   True   True
1   True  False
2  False   True

In [99]: -df1
Out[99]: 
       a      b
0  False   True
1   True  False
2  False  False

转置(Transposing) 

与ndarray类似,使用.T属性可以将DataFrame转置.

# only show the first 5 rows
In [100]: df[:5].T
Out[100]: 
   2000-01-01  2000-01-02  2000-01-03  2000-01-04  2000-01-05
A     -1.2268     -0.7277      0.6958     -1.1103     -0.7323
B      0.7698     -0.1213      0.3417     -0.6200      0.6877
C     -1.2812     -0.0979      0.9597      0.1497      0.1764

与Numpy函数的互操作性(DataFrame interoperability with NumPy functions)

Numpy的元素级的一元函数和其他函数都可以在DataFrame上使用

In [101]: np.exp(df)
Out[101]: 
                 A       B       C
2000-01-01  0.2932  2.1593  0.2777
2000-01-02  0.4830  0.8858  0.9068
2000-01-03  2.0053  1.4074  2.6110
2000-01-04  0.3294  0.5380  1.1615
2000-01-05  0.4808  1.9892  1.1930
2000-01-06  1.4968  0.8565  1.3521
2000-01-07  0.1131  0.2541  0.3851
2000-01-08  4.3176  0.1750  0.4375

In [102]: np.asarray(df)
Out[102]: 
array([[-1.2268,  0.7698, -1.2812],
       [-0.7277, -0.1213, -0.0979],
       [ 0.6958,  0.3417,  0.9597],
       [-1.1103, -0.62  ,  0.1497],
       [-0.7323,  0.6877,  0.1764],
       [ 0.4033, -0.155 ,  0.3016],
       [-2.1799, -1.3698, -0.9542],
       [ 1.4627, -1.7432, -0.8266]])

.dot方法提供了矩阵的乘法运算:

In [103]: df.T.dot(df)
Out[103]: 
         A       B       C
A  11.3419 -0.0598  3.0080
B  -0.0598  6.5206  2.0833
C   3.0080  2.0833  4.3105

类似的,在Series上.dot方法可以实现乘法:

In [104]: s1 = pd.Series(np.arange(5,10))

In [105]: s1.dot(s1)
Out[105]: 255

需要注意的是,DataFrame并不是ndarray的完全替代,因为DataFrame的索引语义在某些地方与矩阵还是存在不同的。

显示控制(Console display)

超大的数据在控制台显示是将被截取,可以使用info()方法获取信息摘要.

这里以R语言中的棒球集数据为例:

In [106]: baseball = pd.read_csv('data/baseball.csv')

In [107]: print(baseball)
       id     player  year  stint  ...   hbp   sh   sf  gidp
0   88641  womacto01  2006      2  ...   0.0  3.0  0.0   0.0
1   88643  schilcu01  2006      1  ...   0.0  0.0  0.0   0.0
..    ...        ...   ...    ...  ...   ...  ...  ...   ...
98  89533   aloumo01  2007      1  ...   2.0  0.0  3.0  13.0
99  89534  alomasa02  2007      1  ...   0.0  0.0  0.0   0.0

[100 rows x 23 columns]

In [108]: baseball.info()

RangeIndex: 100 entries, 0 to 99
Data columns (total 23 columns):
id        100 non-null int64
player    100 non-null object
year      100 non-null int64
stint     100 non-null int64
team      100 non-null object
lg        100 non-null object
g         100 non-null int64
ab        100 non-null int64
r         100 non-null int64
h         100 non-null int64
X2b       100 non-null int64
X3b       100 non-null int64
hr        100 non-null int64
rbi       100 non-null float64
sb        100 non-null float64
cs        100 non-null float64
bb        100 non-null int64
so        100 non-null float64
ibb       100 non-null float64
hbp       100 non-null float64
sh        100 non-null float64
sf        100 non-null float64
gidp      100 non-null float64
dtypes: float64(9), int64(11), object(3)
memory usage: 18.0+ KB

 使用to_string将以表格形式返回DataFrame的字符串表示:

df= pd.DataFrame({'a' : [0, 1, 1], 'b' : [0, 1, 0] }, dtype=bool)

type(df.to_string())
Out[200]:


df.to_string()
Out[201]:
       a      b
0  False  False
1   True   True
2   True  False

 在默认情况下,宽数据框将跨多行打印,但可以通过display.width属性来设置单行的打印宽度.

In [111]: pd.set_option('display.width', 40) # default is 80

In [112]: pd.DataFrame(np.random.randn(3, 12))
Out[112]: 
         0         1         2         3         4         5         6         7         8         9         10        11
0  1.262731  1.289997  0.082423 -0.055758  0.536580 -0.489682  0.369374 -0.034571 -2.484478 -0.281461  0.030711  0.109121
1  1.126203 -0.977349  1.474071 -0.064034 -1.282782  0.781836 -1.071357  0.441153  2.353925  0.583787  0.221471 -0.744471
2  0.758527  1.729689 -0.964980 -0.845696 -1.340896  1.846883 -1.328865  1.682706 -1.717693  0.888782  0.228440  0.901805

甚至可以通过设置display.max_colwidth来调整各个列的最大宽度 

In [113]: datafile={'filename': ['filename_01','filename_02'],
   .....:           'path': ["media/user_name/storage/folder_01/filename_01",
   .....:                    "media/user_name/storage/folder_02/filename_02"]}
   .....: 

In [114]: pd.set_option('display.max_colwidth',30)

In [115]: pd.DataFrame(datafile)
Out[115]: 
      filename                           path
0  filename_01  media/user_name/storage/fo...
1  filename_02  media/user_name/storage/fo...

In [116]: pd.set_option('display.max_colwidth',100)

In [117]: pd.DataFrame(datafile)
Out[117]: 
      filename                                           path
0  filename_01  media/user_name/storage/folder_01/filename_01
1  filename_02  media/user_name/storage/folder_02/filename_02

当然还可以通过expand_frame_repr选项禁用此特性,这将把表打印在一个块中.

IPython在DataFrame列属性访问时的自动补全

(DataFrame column attribute access and IPython completion)

如果DataFrame列标签是一个有效的Python变量名,那么可以像访问属性一样访问该列:

In [118]: df = pd.DataFrame({'foo1' : np.random.randn(5),
   .....:                    'foo2' : np.random.randn(5)})
   .....: 

In [119]: df
Out[119]: 
       foo1      foo2
0  1.171216 -0.858447
1  0.520260  0.306996
2 -1.197071 -0.028665
3 -1.066969  0.384316
4 -0.303421  1.574159

In [120]: df.foo1
Out[120]: 
0    1.171216
1    0.520260
2   -1.197071
3   -1.066969
4   -0.303421
Name: foo1, dtype: float64

在Ipython中键将完成自动补全功能:

In [5]: df.fo
df.foo1  df.foo2

小结

 本章主要介绍了Pandas中的最重要的两个数据结构类型,Series和DataFrame.

 理解以下最要的两点非常重要:

1.数据的自动对齐

2.原数据对象的不可变更性,大多数的方法返回的都是一个新的对象,而不是在原数据上进行操作.

你可能感兴趣的:(Pandas,Pandas数据结构,Pandas对象类型,Pandas的数据结构,DataFrame,Series,Pandas)