pandas教程:Introduction to pandas Data Structures pandas的数据结构
pandas是Python中用于数据分析和操作的库,其核心数据结构包括Series和DataFrame。Series是pandas中类似于数组的一维数据结构,具有索引(index)和标签(label)的特性。通过pd.Series()可以创建Series,其索引可以是字符串或其他类型。例如:
python obj = pd.Series([4, 7, -5, 3]) obj 0 4 1 7 2 -5 3 3 dtype: int64
DataFrame是pandas中二维数据结构,类似于Excel表格。可以通过字典或列表构建DataFrame,并支持行和列的索引操作。例如:
python data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]} frame = pd.DataFrame(data) frame
DataFrame支持数据对齐操作,类似Excel的合并功能。可以通过loc属性按行或列标签进行定位。例如:
python frame.loc['three']
pandas的Index对象负责存储轴标签,支持不可变操作,如选择子集或转置。例如:
python frame3 = pd.DataFrame(pop, index=[2001, 2002, 2003]) frame3.T
通过pd.Index()可以创建自定义索引,支持集合操作。例如:
python labels = pd.Index(np.arange(3)) labels
pandas提供了丰富的方法和属性,如values获取二维数组,isnull检测缺失值等。例如:
python frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five', 'six']) frame2['debt'] = np.arange(6.) frame2
通过这些操作,pandas为数据分析提供了强大的工具支持。
文章目录
- 第5章 初识pandas
- 5.1 探索pandas数据结构
-
- Series对象
-
- DataFrame对象
-
- 索引对象
Chapter 5 Getting Started with pandas
这样导入pandas:
import pandas as pd
e:\python3.7\lib\site-packages\numpy\_distributor_init.py:32: UserWarning: loaded more than 1 DLL from .libs:
e:\python3.7\lib\site-packages\numpy\.libs\libopenblas.TXA6YQSD3GCQQC22GEQ54J2UDCXDXHWN.gfortran-win_amd64.dll
e:\python3.7\lib\site-packages\numpy\.libs\libopenblas.XWYDX2IKJW2NMTWSFYNGFUWKQU3LYTCZ.gfortran-win_amd64.dll
stacklevel=1)
另外可以导入Series和DataFrame,因为这两个经常被用到:
from pandas import Series, DataFrame
5.1 Introduction to pandas Data Structures
在数据结构领域中,该课程的核心内容具体来说,涉及Series和DataFrame这两个核心概念。
1 Series
这里series这个词我就不翻译成序列了,因为之前的所有笔记里,我都是把sequence这个词翻译成序列的。
series类似于数组的一种一维序列,同时它还伴随着一个用于表示label的数组,这个数组被称为index。构建一个series的过程相对直接:
obj = pd.Series([4, 7, -5, 3])
obj
0 4
1 7
2 -5
3 3
dtype: int64
观察到左边标记了index,右边标注了对应的value。通过value和index属性,可以轻松地进行查看。
obj.values
array([ 4, 7, -5, 3], dtype=int64)
obj.index # like range(4)
RangeIndex(start=0, stop=4, step=1)
当然我们也可以自己指定index的label:
obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
obj2
d 4
b 7
a -5
c 3
dtype: int64
obj2.index
Index(['d', 'b', 'a', 'c'], dtype='object')
可以用index的label来选择:
obj2['a']
-5
obj2['d'] = 6
obj2[['c', 'a', 'd']]
c 3
a -5
d 6
dtype: int64
这里[‘c’, ‘a’, ‘d’]其实被当做了索引,尽管这个索引是用string构成的。
使用numpy函数或类似的操作,会保留index-value的关系:
obj2[obj2 > 0]
d 6
b 7
c 3
dtype: int64
obj2
d 12
b 14
a -10
c 6
dtype: int64
import numpy as np
np.exp(obj2)
d 403.428793
b 1096.633158
a 0.006738
c 20.085537
dtype: float64
另一种方式来看待series,它相当于一个固定长度、有序的dict,从index到value进行映射。在多个场景中,可以将其视为dict来使用。
'b' in obj2
True
'e' in obj2
False
还可以直接用现有的dict来创建series:
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon':16000, 'Utah': 5000}
obj3 = pd.Series(sdata)
obj3
Ohio 35000
Texas 71000
Oregon 16000
Utah 5000
dtype: int64
series中的index本质上是dict中有序排列的keys。我们还可以指定一个自定义的排序顺序:
states = ['California', 'Ohio', 'Oregon', 'Texas']
obj4 = pd.Series(sdata, index=states)
obj4
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
顺序是遵循states中的排列,但因未找到california,即为NaN。NaN代表缺失数据,即在提到时,我们用missing或NA来指代。pandas中,isnull和notnull函数可用于识别缺失数据:
pd.isnull(obj4)
California True
Ohio False
Oregon False
Texas False
dtype: bool
pd.notnull(obj4)
California False
Ohio True
Oregon True
Texas True
dtype: bool
series也有对应的方法:
obj4.isnull()
California True
Ohio False
Oregon False
Texas False
dtype: bool
关于缺失数据,在第七章还会讲得更详细一些。
在series中,一个有实用价值的特性会根据index label进行排序(Data alignment features)
obj3
Ohio 35000
Texas 71000
Oregon 16000
Utah 5000
dtype: int64
obj4
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
obj3 + obj4
California NaN
Ohio 70000.0
Oregon 32000.0
Texas 142000.0
Utah NaN
dtype: float64
这个Data alignment features(数据对齐特色)和数据库中的join相似。
series自身属性和其index都具有名为name的属性,该属性能够与其他pandas函数进行整合:
obj4.name = 'population'
obj4.index.name = 'state'
obj4
state
California NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
Name: population, dtype: float64
series的index能被直接更改:
obj
0 4
1 7
2 -5
3 3
dtype: int64
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']
obj
Bob 4
Steve 7
Jeff -5
Ryan 3
dtype: int64
2 DataFrame
DataFrame是一种二维表格结构,代表一种排好序的列集合,其中每一列可以是不同类型的数值数据(如数字、字符串、布尔值)。DataFrame包含行索引和列索引(row index, column index),可以理解为一种共享所有索引的由series组成的字典结构。数据以多维块存储结构保存。
我将dataframe视为类似于Excel表格的存在,这样使用起来更加直观。
构建一个dataframe的方法,用一个dcit,dict里的值是list:
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002, 2003],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}
frame = pd.DataFrame(data)
frame
| pop | state | year | |
|---|---|---|---|
| 0 | 1.5 | Ohio | 2000 |
| 1 | 1.7 | Ohio | 2001 |
| 2 | 3.6 | Ohio | 2002 |
| 3 | 2.4 | Nevada | 2001 |
| 4 | 2.9 | Nevada | 2002 |
| 5 | 3.2 | Nevada | 2003 |
dataframe也会像series一样,自动给数据赋index, 而列则会按顺序排好。
对于一个较大的DataFrame,通过head方法调用可以获取前五行数据(注:在数据分析中,该函数常被用来查看数据集的前几行内容,帮助了解数据结构)
frame.head()
| pop | state | year | |
|---|---|---|---|
| 0 | 1.5 | Ohio | 2000 |
| 1 | 1.7 | Ohio | 2001 |
| 2 | 3.6 | Ohio | 2002 |
| 3 | 2.4 | Nevada | 2001 |
| 4 | 2.9 | Nevada | 2002 |
如果指定一列的话,会自动按列排序:
pd.DataFrame(data, columns=['year', 'state', 'pop'])
| year | state | pop | |
|---|---|---|---|
| 0 | 2000 | Ohio | 1.5 |
| 1 | 2001 | Ohio | 1.7 |
| 2 | 2002 | Ohio | 3.6 |
| 3 | 2001 | Nevada | 2.4 |
| 4 | 2002 | Nevada | 2.9 |
| 5 | 2003 | Nevada | 3.2 |
如果你导入一个不存在的列名,那么会显示为缺失数据:
frame2 = pd.DataFrame(data, columns=['year', 'state', 'pop', 'debt'],
index=['one', 'two', 'three', 'four', 'five', 'six'])
frame2
| year | state | pop | debt | |
|---|---|---|---|---|
| one | 2000 | Ohio | 1.5 | NaN |
| two | 2001 | Ohio | 1.7 | NaN |
| three | 2002 | Ohio | 3.6 | NaN |
| four | 2001 | Nevada | 2.4 | NaN |
| five | 2002 | Nevada | 2.9 | NaN |
| six | 2003 | Nevada | 3.2 | NaN |
frame2.columns
Index(['year', 'state', 'pop', 'debt'], dtype='object')
从DataFrame中提取一列会返回series类型的数据,也可以以属性或字典形式提取数据:
frame2['state']
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
six Nevada
Name: state, dtype: object
frame2.year
one 2000
two 2001
three 2002
four 2001
five 2002
six 2003
Name: year, dtype: int64
提示:通过frame2[column]结构,可以处理任意列名,但仅当frame2.column时,column必须是合法的Python变量名。
返回的series有DataFrame种同样的index,而且name属性也是对应的。
对于行,要用在loc属性里用 位置或名字:
frame2.loc['three']
year 2002
state Ohio
pop 3.6
debt NaN
Name: three, dtype: object
列值也能通过赋值改变。比如给debt赋值:
frame2['debt'] = 16.5
frame2
| year | state | pop | debt | |
|---|---|---|---|---|
| one | 2000 | Ohio | 1.5 | 16.5 |
| two | 2001 | Ohio | 1.7 | 16.5 |
| three | 2002 | Ohio | 3.6 | 16.5 |
| four | 2001 | Nevada | 2.4 | 16.5 |
| five | 2002 | Nevada | 2.9 | 16.5 |
| six | 2003 | Nevada | 3.2 | 16.5 |
frame2['debt'] = np.arange(6.)
frame2
| year | state | pop | debt | |
|---|---|---|---|---|
| one | 2000 | Ohio | 1.5 | 0.0 |
| two | 2001 | Ohio | 1.7 | 1.0 |
| three | 2002 | Ohio | 3.6 | 2.0 |
| four | 2001 | Nevada | 2.4 | 3.0 |
| five | 2002 | Nevada | 2.9 | 4.0 |
| six | 2003 | Nevada | 3.2 | 5.0 |
在将list或array赋值给column时,必须确保其长度与DataFrame的行数一致。相反,若将series赋值给DataFrame,系统会根据DataFrame的索引进行对齐,若series长度不足,缺失值将被填充。
val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
frame2['debt'] = val
frame2
| year | state | pop | debt | |
|---|---|---|---|---|
| one | 2000 | Ohio | 1.5 | NaN |
| two | 2001 | Ohio | 1.7 | -1.2 |
| three | 2002 | Ohio | 3.6 | NaN |
| four | 2001 | Nevada | 2.4 | -1.5 |
| five | 2002 | Nevada | 2.9 | -1.7 |
| six | 2003 | Nevada | 3.2 | NaN |
若列不存在,赋值操作会生成一个新列。同样地,使用del进行删除操作,其行为类似于删除字典键的行为。
frame2['eastern'] = frame2.state == 'Ohio'
frame2
| year | state | pop | debt | eastern | |
|---|---|---|---|---|---|
| one | 2000 | Ohio | 1.5 | NaN | True |
| two | 2001 | Ohio | 1.7 | -1.2 | True |
| three | 2002 | Ohio | 3.6 | NaN | True |
| four | 2001 | Nevada | 2.4 | -1.5 | False |
| five | 2002 | Nevada | 2.9 | -1.7 | False |
| six | 2003 | Nevada | 3.2 | NaN | False |
然后用del删除这一列:
del frame2['eastern']
frame2.columns
Index(['year', 'state', 'pop', 'debt'], dtype='object')
注意:columns返回的是一个view,而不是创建了一个copied object。因此,任何对series的修改,会作用于整个DataFrame。除非我们使用copy方法来创建一个新的副本。
另一种常见的格式是dict中的dict:
pop = {'Nevada': {2001: 2.4, 2002: 2.9},
'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
将这种嵌入式字典传递给DataFrame,pandas会将外层dict的键作为列,内层键作为索引:
当嵌入式字典被传递给DataFrame时,pandas会将外层dict的键作为列,内层键作为索引:
将嵌入式dict传递给DataFrame,pandas会将外层dict的键作为列,内层键作为行索引:
当嵌套字典传递给DataFrame时,pandas会将外层字典的键作为列,内层键作为索引:
将嵌套dict传递给DataFrame,pandas会将外层dict的键作为列,内层键作为行索引:
当嵌入式字典被传递给DataFrame时,pandas会将外层字典的键作为列,内层键作为索引:
将嵌入式dict传递给DataFrame,pandas会将外层dict的键作为列,内层键作为索引:
当嵌入式字典被传递给DataFrame时,pandas会将外层dict的键作为列,内层键作为索引:
将嵌入式dict传递给DataFrame,pandas会将外层dict的键作为列,内层键作为索引:
当嵌入式字典被传递给DataFrame时,pandas会将外层dict的键作为列,内层键作为索引:
frame3 = pd.DataFrame(pop)
frame3
| Nevada | Ohio | |
|---|---|---|
| 2000 | NaN | 1.5 |
| 2001 | 2.4 | 1.7 |
| 2002 | 2.9 | 3.6 |
另外DataFrame也可以向numpy数组一样做转置:
frame3.T
| 2000 | 2001 | 2002 | |
|---|---|---|---|
| Nevada | NaN | 2.4 | 2.9 |
| Ohio | 1.5 | 1.7 | 3.6 |
指定index:
pd.DataFrame(pop, index=[2001, 2002, 2003])
| Nevada | Ohio | |
|---|---|---|
| 2001 | 2.4 | 1.7 |
| 2002 | 2.9 | 3.6 |
| 2003 | NaN | NaN |
series组成的dict:
pdata = {'Ohio': frame3['Ohio'][:-1],
'Nevada': frame3['Nevada'][:2]}
pd.DataFrame(pdata)
| Nevada | Ohio | |
|---|---|---|
| 2000 | NaN | 1.5 |
| 2001 | 2.4 | 1.7 |
如果DataFrame的index和column有自己的name属性,也会被显示:
frame3.index.name = 'year'; frame3.columns.name = 'state'
frame3
| state | Nevada | Ohio |
|---|---|---|
| year | ||
| 2000 | NaN | 1.5 |
| 2001 | 2.4 | 1.7 |
| 2002 | 2.9 | 3.6 |
values属性会返回二维数组:
frame3.values
array([[ nan, 1.5],
[ 2.4, 1.7],
[ 2.9, 3.6]])
如果column有不同的类型,dtype会适应所有的列:
frame2.values
array([[2000, 'Ohio', 1.5, nan],
[2001, 'Ohio', 1.7, -1.2],
[2002, 'Ohio', 3.6, nan],
[2001, 'Nevada', 2.4, -1.5],
[2002, 'Nevada', 2.9, -1.7],
[2003, 'Nevada', 3.2, nan]], dtype=object)
3 Index Objects (索引对象)
pandas中的Index Objects(索引对象)负责存储axis labels以及一些附加数据,例如axis name或names。当一个数组或序列被用于构建series或DataFrame时,会自动被转换为index:
obj = pd.Series(range(3), index=['a', 'b', 'c'])
index = obj.index
index
Index(['a', 'b', 'c'], dtype='object')
index[1:]
Index(['b', 'c'], dtype='object')
index object是不可更改的:
index[1] = 'd'
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-67-676fdeb26a68> in <module>()
----> 1 index[1] = 'd'
/Users/xu/anaconda/envs/py35/lib/python3.5/site-packages/pandas/indexes/base.py in __setitem__(self, key, value)
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
正因为不可修改,所以data structure中分享index object是很安全的:
labels = pd.Index(np.arange(3))
labels
Int64Index([0, 1, 2], dtype='int64')
obj2 = pd.Series([1.5, -2.5, 0], index=labels)
obj2
0 1.5
1 -2.5
2 0.0
dtype: float64
obj2.index is labels
True
index除了想数组,还能像大小一定的set:
frame3
| state | Nevada | Ohio |
|---|---|---|
| year | ||
| 2000 | NaN | 1.5 |
| 2001 | 2.4 | 1.7 |
| 2002 | 2.9 | 3.6 |
frame3.columns
Index(['Nevada', 'Ohio'], dtype='object', name='state')
'Ohio' in frame3.columns
True
2003 in frame3.columns
False
与python里的set不同,pandas的index可以有重复的labels:
dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])
dup_labels
Index(['foo', 'foo', 'bar', 'bar'], dtype='object')
在这种重复的标签中选择的话,会选中所有相同的标签。
