pandas

Series对象

pandas库的Series对象用来表示一维数据结构,跟数组类似,但多了一些额外的功能,它的内部结构很简单(如下表),由两个相互关联的数组组成,其中主数组用于存放数据(Numpy任意类型数据)。主数组的每个元素都有一个与之相关联的标签,这些标签存储的另一个叫做Index的数组中。

|Series| -|- index|value 0|12 1|-4 2|7 3|9

In:

s = pd.Series([12,-4,7,9])
s

out:

0    12
1 -4
2 7
3 9
dtype: int64

可以看出左侧Index是一列标签,右侧是标签对应的元素

声明Series时,若不指定标签,pandas默认使用从0开始一次递增的数值作为标签。这种情况下,标签与Series对象中的元素索引一致。但是最好使用有意义的标签,用以区分和识别每个元素

in:

s = pd.Series([12,-4,7,9],index=['a','b','c','d'])
s

out:

a    12
b -4
c 7
d 9
dtype: int64

获取元素

s.values

array([12, -4, 7, 9], dtype=int64)

s.index

Index([‘a’, ‘b’, ‘c’, ‘d’], dtype=’object’)

s[2]
  • 7
s['c']
  • 7

in:

s[:2]

out:

a    12
b -4
dtype: int64

in:

s[['b','c']]

out:

b   -4
c 7
dtype: int64

为元素赋值

in:

s[1]=0
s

out:

a    12
b 0
c 7
d 9
dtype: int64

in:

s['b'] = 1
s

out:

a    12
b 1
c 7
d 9
dtype: int64

用Numpy数组或其他Series对象定义新Series对象

in:

a = np.array([1,2,3,4])
b= pd.Series(a)
b

out:

0    1
1 2
2 3
3 4
dtype: int32

in:

c= pd.Series(b)
c

out:

0    1
1 2
2 3
3 4
dtype: int32

这样做时不要忘记新Series对象中的元素不是原Num数组或Series对象的副本,而是对他们的引用,也就是说,这些对象是动态插入到新Series对象中。如改变原有对象元素的值,新Series对象中这些元素也会发生改变。

in:

b[2]=11
b

out:

0     1
1 2
2 11
3 4
dtype: int32

in:

c

out:

0     1
1 2
2 11
3 4
dtype: int32

筛选元素

pandas库的开发是以NumPy库为基础的,因此就数据结构而言,NumPy数组的多种操作方法得以扩展到Series对象中,其中就是根据条件筛选数据结构中的元素之一方法。

in:

s[s>8]

out:

a    12
d 9
dtype: int64

运算和数学函数

适用于NumPy数组的运算符(+,-,* ,/ )或其他数学函数,也适用于Series对象。

in:

s / 2

out:

a    6.0
b 0.5
c 3.5
d 4.5
dtype: float64

in:

s

out:

a    12
b 1
c 7
d 9
dtype: int64

NumPy库的数学函数,必须制定他们出处np,并把Series实例作为参数传入。

in:

np.log(s)

out:

a    2.484907
b 0.000000
c 1.945910
d 2.197225
dtype: float64

Series对象的组成元素

in:

color = pd.Series([1,0,2,1,2,3],index=['white','white','blue','green','green','yellow'])
color

out:

white     1
white 0
blue 2
green 1
green 2
yellow 3
dtype: int64
color.unique()

array([1, 0, 2, 3], dtype=int64)

返回一个数组,包含去重后的元素,但乱序

in:

color.value_counts()

out:

2    2
1 2
3 1
0 1
dtype: int64

返回各个不同的元素,还计算每个元素在Series中出现次数

in:

color.isin([0,3])

out:

white     False
white True
blue False
green False
green False
yellow True
dtype: bool

判断给定的一列元素是否包含在数据结构中,返回布尔值

in:

color[color.isin([0,3])]

out:

white     0
yellow 3
dtype: int64

NaN

in:

s = pd.Series([1,2,np.NaN,14])
s

out:

0     1.0
1 2.0
2 NaN
3 14.0
dtype: float64

in:

s.isnull()

out:

0    False
1 False
2 True
3 False
dtype: bool

in:

s.notnull()

out:

0     True
1 True
2 False
3 True
dtype: bool

in:

s[s.notnull()]

out:

0     1.0
1 2.0
3 14.0
dtype: float64

in:

s[s.isnull()]

out:

2   NaN
dtype: float64

Series用作字典

in:

mydict = {'red':2000,'blue':1000,'yellow':500,'orange':1000}
myseries = pd.Series(mydict)
myseries

out:

blue      1000
orange 1000
red 2000
yellow 500
dtype: int64

索引数组用字典的键来填充,每个索引所对应的元素为用作索引的键在字典中对应的值。你还可以单独制定索引,pandas会控制字典的键和数组索引标签之间的相关性。如遇缺失值处,pandas就会为其添加NaN。

in:

colors = ['red','yellow','orange','blue','green']
myseries = pd.Series(mydict,index =colors)
myseries

out:

red       2000.0
yellow 500.0
orange 1000.0
blue 1000.0
green NaN
dtype: float64

Series 对象之间的运算

in:

mydict = {'red':200,'blue':100,'yellow':50,'orange':100,'black':700}
myseries2 = pd.Series(mydict)
myseries2

out:

black     700
blue 100
orange 100
red 200
yellow 50
dtype: int64

in:

myseries + myseries2

out:

black        NaN
blue 1100.0
green NaN
orange 1100.0
red 2200.0
yellow 550.0
dtype: float64

DataFrame对象

DataFrame这种列表式数据结构跟工作表(最常见的是Excel工作表)极为相似,其设计初衷是将Series的使用场景由一维扩展到多维。DataFrame由按一定顺序排列的多列数据组成,各列数据类型可以有不同。

定义DataFrame对象

data = {'color':['blue','green','yellow','red','white'],'object':['ball','pen','pecil','paper','mug'],'price':[1.2,1.0,0.6,0.9,1.7]}
frame = pd.DataFrame(data)
frame

如果用来创建DataFrame对象的dict对象包含一些用不到的数据,你可以只选择自己感兴趣的。在DataFrame构造函数中,用columns选项制定需要的列即可。新建的DataFrame各列顺序与你制定的列顺序一致,而与他们在字典中的顺序无关。

frame2 = pd.DataFrame(data,columns=['object','price'])
frame2

DataFrame对象和Series一样,如果Index数组没有明确制定标签,pandas也会自动为其添加一列从0开始的数值作为索引。如果想用标签作为DataFrame的索引,则要把标签放在数组中,赋给index选项

frame3 = pd.DataFrame(data,index=['one','two','three','four','five'])
frame3

选取元素

frame.columns #列名

Index([‘color’, ‘object’, ‘price’], dtype=’object’)

frame.index #索引

RangeIndex(start=0, stop=5, step=1)

frame.values #所有元素

out:

array([['blue', 'ball', 1.2],
['green', 'pen', 1.0],
['yellow', 'pecil', 0.6],
['red', 'paper', 0.9],
['white', 'mug', 1.7]], dtype=object)

in:

frame['price']

out:

0    1.2
1 1.0
2 0.6
3 0.9
4 1.7
Name: price, dtype: float64

in:

frame.price

out:

0    1.2
1 1.0
2 0.6
3 0.9
4 1.7
Name: price, dtype: float64

in:

frame.ix[2]

out:

color     yellow
object pecil
price 0.6
Name: 2, dtype: object
frame

in:

frame.loc[2]

out:

color     yellow
object pecil
price 0.6
Name: 2, dtype: object

in:

frame.iloc[2]

out:

color     yellow
object pecil
price 0.6
Name: 2, dtype: object
frame.loc[[2,4]]

frame.iloc[[2,4]] #i表示整数

frame3.loc['one']

out:

color     blue
object ball
price 1.2
Name: one, dtype: object
frame[1:3]

frame['object'][3]

‘paper’

赋值

frame.index.name = 'id'
frame.columns.name = 'item'
frame

frame['new'] = 12
frame

frame['new'] = [3.0,1.3,2.2,0.8,1.1]
frame

in:

ser = pd.Series(np.arange(5))
ser

out:

0    0
1 1
2 2
3 3
4 4
dtype: int32
frame['new']  = ser
frame

frame['price'][2] = 3.3
frame

frame.set_value(2,'price',2)

frame.at[2,'price']=22
frame

frame.isin([1.0,'pen'])

frame[frame.isin([1.0,'pen'])]

del frame['new']
frame

删除一列

d1 = {'red':{2012:22,2013:33},'white':{2011:13,2012:22,2013:16},'blue':{2011:17,2012:27,2013:18}}
frame2 = pd.DataFrame(d1)
frame2

frame2.T

Index对象

in:

ins = pd.Series([5,0,3,8,4],index=['red','blue','yellow','white','green'])
ins

out:

red       5
blue 0
yellow 3
white 8
green 4
dtype: int64
ins.index

Index([‘red’, ‘blue’, ‘yellow’, ‘white’, ‘green’], dtype=’object’)

ins.idxmin() #返回索引值最小的元素

‘blue’

ins.idxmax() #返回索引值最大的元素

‘white’

重复标签的Index

serd = pd.Series(range(6),index=['white','white','blue','green','green','yellow'])
serd

out:

white     0
white 1
blue 2
green 3
green 4
yellow 5
dtype: int64

in:

serd['white']

out:

white    0
white 1
dtype: int64
serd.index.is_unique

False

判断是否存在重复项

frame.index.is_unique

True

frame

索引对象的其他功能

更换索引

ser = pd.Series([2,3,4,5],index=['one','two','three','four'])
ser

out:

one      2
two 3
three 4
four 5
dtype: int64

in:

ser.reindex(['three','four','five','one'])

out:

three    4.0
four 5.0
five NaN
one 2.0
dtype: float64

自动编制索引

ser2 = pd.Series([1,5,6,3],index =[0,3,5,6])
ser2

out:

0    1
3 5
5 6
6 3
dtype: int64

in:

ser2.reindex(range(6),method='ffill') #插值,以得到一个完整的序列(前插)

out:

0    1
1 1
2 1
3 5
4 5
5 6
dtype: int64

in:

ser2.reindex(range(6),method='bfill') #插值,以得到一个完整的序列(后插)

out:

0    1
1 5
2 5
3 5
4 6
5 6
dtype: int64

删除

pandas提供专门的删除操作函数:drop()

ser3 = pd.Series(np.arange(4.),index=['red','blue','yellow','white'])
ser3

out:

red       0.0
blue 1.0
yellow 2.0
white 3.0
dtype: float64

in:

ser3.drop('yellow')

out:

red      0.0
blue 1.0
white 3.0
dtype: float64

in:

ser3.drop(['blue','white'])

out:

red       0.0
yellow 2.0
dtype: float64

frame = pd.DataFrame(np.arange(16).reshape((4,4)),index=['blue','yellow','red','white'],columns=['ball','pen','pencil','paper'])
frame

frame.drop(['blue','yellow']) #默认删除行

frame.drop(['pen','pencil'],axis=1) #删除列

add() sub() div() mul()

in:

ser4 = pd.Series(np.arange(4.),index=['red','blue','yellow','white'])
ser4

out:

red       0.0
blue 1.0
yellow 2.0
white 3.0
dtype: float64

in:

ser5 = pd.Series(np.arange(5.),index=['red','blue','black','brown','yellow'])
ser5

out:

red       0.0
blue 1.0
black 2.0
brown 3.0
yellow 4.0
dtype: float64

in:

ser4 + ser5

out:

black     NaN
blue 2.0
brown NaN
red 0.0
white NaN
yellow 6.0
dtype: float64
frame1 = pd.DataFrame(np.arange(16).reshape((4,4)),index=['red','blue','yellow','white'],columns=['ball','pen','pencil','paper'])
frame1

frame2 = pd.DataFrame(np.arange(12).reshape((4,3)),index=['blue','green','white','yellow'],columns=['mug','pen','ball'])
frame2

frame1 + frame2

frame1.add(frame2)

frame2 = pd.DataFrame(np.arange(16).reshape((4,4)),index=['red','blue','yellow','white'],columns=['ball','pen','pencil','paper'])
frame2

ser1 = pd.Series(np.arange(4),index=['ball','pen','pencil','paper'])
ser1

out:

ball      0
pen 1
pencil 2
paper 3
dtype: int32
frame2 - ser1

ser1['mug'] = 9
ser1

out:

ball      0
pen 1
pencil 2
paper 3
mug 9
dtype: int64
frame2 - ser1

通用函数

np.sqrt(frame2) #平方根

按行或列执行操作的函数

f = lambda x:x.max() - x.min()

frame2.apply(f)

out:

ball      12
pen 12
pencil 12
paper 12
dtype: int64

in:

frame2.apply(f,axis = 1) # 行

out:

red       3
blue 3
yellow 3
white 3
dtype: int64

in:

def f(x):
return pd.Series([x.min(),x.max()],index=['min','max'])

frame2.apply(f)

统计函数

frame2.sum()

out:

ball      24
pen 28
pencil 32
paper 36
dtype: int64

in:

frame.describe()

排序

根据索引排序

ser = pd.Series([5,0,3,8,4],index=['red','blue','yellow','white','green'])
ser

out:

red       5
blue 0
yellow 3
white 8
green 4
dtype: int64

in:

ser.sort_index() #a-zp升序

out:

blue      0
green 4
red 5
white 8
yellow 3
dtype: int64

in:

ser.sort_index(ascending=False)  #降序

out:

yellow    3
white 8
red 5
green 4
blue 0
dtype: int64

in:

frame2

frame2.sort_index()

frame2.sort_index(axis=1)

根据对象排序

frame2.sort_values(by = 'pen')

frame2.at['red','pen']=18
frame2

frame2.sort_values(by = 'pen')

排位

in:

ser.rank() #排位

out:

red       4.0
blue 1.0
yellow 2.0
white 5.0
green 3.0
dtype: float64

in:

ser.rank(method = 'first')

out:

red       4.0
blue 1.0
yellow 2.0
white 5.0
green 3.0
dtype: float64

in:

ser.rank(ascending=False) #降序

out:

red       2.0
blue 5.0
yellow 4.0
white 1.0
green 3.0
dtype: float64

in:

frame2.rank()

frame3 = frame2.sort_values(by = 'pen')
frame3.rank()

相关性和协方差

seq2 = pd.Series([3,4,3,4,5,4,3,2],['2006','2007','2008','2009','2010','2011','2012','2013'])
seq2

out:

2006    3
2007 4
2008 3
2009 4
2010 5
2011 4
2012 3
2013 2
dtype: int64
seq = pd.Series([1,2,3,4,4,3,2,1],['2006','2007','2008','2009','2010','2011','2012','2013'])
seq

out:

2006    1
2007 2
2008 3
2009 4
2010 4
2011 3
2012 2
2013 1
dtype: int64

in:

seq.corr(seq2)

0.7745966692414835

seq.cov(seq2)

0.8571428571428571

frame2 = pd.DataFrame([[1,4,3,6],[4,5,6,1],[3,3,1,5],[4,1,6,4]],index=['red','blue','yellow','white'],columns = ['ball','pen','pencil','paper'])
frame2

frame2.corr()

frame2.cov()

corrwith()方法可以计算DataFrame对象的列或行与Series对象或其他DataFrame对象元素两两之间的相关性

frame2.corrwith(ser)

out:

ball     -0.140028
pen -0.869657
pencil 0.080845
paper 0.595854
dtype: float64

in:

f1 = frame2.corrwith(frame)
f1

out:

ball     -0.182574
pen -0.831522
pencil 0.105409
paper 0.597614
dtype: float64

in:

f1.dropna() #删除NaN

out:

ball     -0.182574
pen -0.831522
pencil 0.105409
paper 0.597614
dtype: float64

in:

f1[f1.notnull()]

out:

ball     -0.182574
pen -0.831522
pencil 0.105409
paper 0.597614
dtype: float64

in:

frame3 = pd.DataFrame([[6,np.nan,6],[np.nan,np.nan,np.nan],[2,np.nan,5]],index = ['blue','green','red'],columns = ['ball','mug','pen'])
frame3

frame3.dropna()

frame3.dropna(how ='all')

frame3.fillna(0) #指定缺失值填充

frame3.fillna({'ball':1,'mug':0,'pen':99})

mser = pd.Series(np.random.rand(8),index=[['white','white','white','blue','blue','red','red','red'],['up','down','right','up','down','up','down','left']])
mser #等级索引

out:

white  up       0.096961
down 0.633575
right 0.652724
blue up 0.269485
down 0.518140
red up 0.143647
down 0.335544
left 0.574777
dtype: float64

in:

mser.index

out:

MultiIndex(levels=[['blue', 'red', 'white'], ['down', 'left', 'right', 'up']],
labels=[[2, 2, 2, 0, 0, 1, 1, 1], [3, 0, 2, 3, 0, 3, 0, 1]])

in:

mser['white']

out:

up       0.096961
down 0.633575
right 0.652724
dtype: float64

in:

mser[:,'up']

out:

white    0.096961
blue 0.269485
red 0.143647
dtype: float64
mser['white','up']

0.09696136257353527

frame = mser.unstack() #把等级索引Series转换成简单的DataFrame对象
frame

frame.stack()

out:

blue   down     0.518140
up 0.269485
red down 0.335544
left 0.574777
up 0.143647
white down 0.633575
right 0.652724
up 0.096961
dtype: float64
mframe = pd.DataFrame(np.random.randn(16).reshape(4,4),
index =[['white','white','red','red'],['up','down','up','down']],
columns=[['pen','pen','paper','paper'],[1,2,1,2]])
mframe

mframe.columns.names =['objects','id']
mframe.index.names = ['colors','status']
mframe

mframe.swaplevel('colors','status') #互换位置

mframe.sort_index(level='colors') #根据层级排序

mframe.sum(level='colors')  #按照层级统计

mframe.sum(level='id',axis=1)  #按照层级统计

pandas:数据读写

csv和文本文件

多年以来,人们已习惯于文本文件的读写,特别是列表形式的数据。如果文件每一行的多 个元素是用逗号隔开的,则这种格式叫作CSV,这可能是最广为人知和最受欢迎的格式。

其他由空格或制表符分隔的列表数据通常存储在各种类型的文本文件中(扩展名一般 为.txt )。

因此这种文件类型是最常见的数据源,它易于转录和解释。pandas的下列函数专门用来处理 这种文件类型:

  • read_csv
  • read_table
  • to_csv
csvframe = pd.read_csv('myCSV_01.csv')
csvframe

csvframe = pd.read_table('myCSV_01.csv',sep=',')
csvframe

第一行作为列名称,但是往往很多数据第一行不是列名

csvframe = pd.read_csv('myCSV_02.csv')
csvframe

csvframe = pd.read_csv('myCSV_02.csv',header=None) #添加默认表头
csvframe

csvframe = pd.read_csv('myCSV_02.csv',names=['white','red','blue','green','animal']) #指定表头
csvframe

csvframe = pd.read_csv('myCSV_03.csv')
csvframe

csvframe = pd.read_csv('myCSV_03.csv',index_col=['color','status']) #等级索引
csvframe

pd.read_table('ch05_04.txt',sep='\s+') #根据正则解析

pd.read_table('ch05_05.txt',sep=r'\D+',header=None,engine='python')

另一种很常见的情况是,解析数据时把空行排除在外。文件中的表头或没有必要的注释,有时用不到。使用skiprows选项,可以排除多余的行。把要排除的行的行号放到数组中,赋给该选项即可。

pd.read_table('ch05_06.txt',sep=',',skiprows=[0,1,3,6])

从TXT文件读取部分数据

处理大文件或是只对文件部分数据感兴趣时,往往需要按照部分(块)读取文件,因为只需 要部分数据s这两种情况都得使用迭代。 举例来说,假如只想读取文件的一部分,可明确指定要解析的行号,这时要用到nrows和skiprows选项。你可以指定起始行n (n = SkipRows)和从起始行往后读多少行(nrows = i).

pd.read_csv('myCSV_02.csv',skiprows=[2],nrows=3,header=None)

另外一项既有趣又很常用的操作是切分想要解析的文本,然后遍历各个部分,逐一对其执行 某一特定操作。

例如,对于一列数字,每隔两行取一个累加起来,最后把和插人到Series对象中„这个小例 子理解起来很简单,也没有实际应用价值,但是一旦领会了其原理,你就能将其用到更加复杂的情况。

out = pd.Series()
pieces = pd.read_csv('myCSV_01.csv',chunksize=3)
pieces

In:

i = 0
for piece in pieces:
print(piece['white'])
out.at[i] = piece['white'].sum()
i += 1

out:

0    1
1 2
2 3
Name: white, dtype: int64
3 2
4 4
5 4
Name: white, dtype: int64

in:

out

out:

0     6
1 10
dtype: int64

往CSV文件写入数据

frame1

frame1.to_csv('ch05_07.csv')

把DataFrame写人文件时,索引和列名称连同数据一起写入。使用index和 header选项,把它们的值设置为False,可取消这一默认行为

frame1.to_csv('ch05_07b.csv',index =False,header=False)
frame3

需要注意的是,数据结构中的NaN写入文件后,显示为空字段

frame3.to_csv('ch05_08.csv')

可以用to_csv()函数的na_rep选项把空字段替换为你需要的值。常用值有NULL、0和NaN

frame3.to_csv('ch05_09.csv',na_rep='NaN')

读写HTML文件

frame = pd.DataFrame(np.arange(4).reshape(2,2))
frame

print(frame.to_html())

out:

<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>0</th>
<th>1</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>0</td>
<td>1</td>
</tr>
<tr>
<th>1</th>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
 frame = pd.DataFrame( np.random.random((4,4)),
index = ['white','black','red','blue1'],
columns = ['up','down','right','left'])
frame

in:

s = ['<HTML>']
s.append('<HEAD><TITLE>My DataFrame</TITLE></HEAD>')
s.append(' <B0DY>')
s.append(frame.to_html())
s.append('</BODY></HTML>')
html = ''.join(s)
html_file = open('myFrame.html','w')
html_file.write(html)
html_file.close()

读取

web_frames = pd.read_html('myFrame.html')
web_frames[0]

ranking = pd.read_html('http://www.meccanismocomplesso.org/en/ meccanismo-complesso-sito-2/classifica-punteggio/')
ranking[0]

此处省略。。。

ranking[1]

从XML读取数据

pandas的所有I/O API函数中,没有专门用来处理XML(可扩展标记语言)格式的。虽然没有, 但这种格式其实很重要,因为很多结构化数据都是以XML格式存储的。pandas没有专门的处理函 数也没关系,因为Python有很多读写XML格式数据的库(除了pandas)。

其中一个库叫作lxml,它在大文件处理方面性能优异,因而从众多同类库之中脱颖而出。这 一节将介绍如何用它处理XML文件,以及如何把它和pandas整合起来,以最终从XML文件中获 取到所需数据并将其转换为DataFrame对象。

from lxml import objectify

xml = objectify.parse('books.xml')
xml
root = xml.getroot()
root
root.Book.Author

‘ 272103_l_EnRoss, Mark’

root.Book.PublishDate

‘2014-22-0l’

mes = root.Book.getchildren()
mes

[‘ 272103_l_EnRoss, Mark’, ‘XML Cookbook’, ‘Computer’, 23.56, ‘2014-22-0l’]

[child.tag for child in mes]

[‘Author’, ‘Title’, ‘Genre’, ‘Price’, ‘PublishDate’]

[child.text for child in mes]

[‘ 272103_l_EnRoss, Mark’, ‘XML Cookbook’, ‘Computer’, ‘23.56’, ‘2014-22-0l’]

读写 Microsoft Excel文件

  • to_excel()
  • read_excel()

能够读取.xls和.xlsx两种类型的文件

读写JSON数据

  • read_json()
  • to_json()

HDF5格式

至此,已学习了文本格式的读写。若要分析大量数据,最好使用二进制格式。Python有多 种二进制数据处理工具。HDF5库在这个方面取得了一定的成功。

HDF代表等级数据格式(hierarchical data format )。HDF5库关注的是HDF5文件的读写,这种文件的数据结构由节点组成,能够存储大量数据集。

该库全部用c语言开发,提供了python/matlab和Java语言接口。它的迅速扩展得益于开发人 员的广泛使用,还得益于它的效率,尤其是使用这种格式存储大量数据,其效率很高。比起其他处理起二进制数据更为简单的格式,HDF5支持实时压缩,因而能够利用数据结构中的重复模式压缩文件。

目前,Python提供两种操纵HDF5格式数据的方法:PyTables和h5py。这两种方法有几点不同,选用哪一种很大程度上取决于具体需求。

h5py为HDF5的高级API提供接口。PyTables封装了很多HDF5细节,提供更加灵活的数据容器、索引表、搜索功能和其他计算相关的介质。

pandas还有一个叫作HDFStore、类似于diet的类,它用PyTables存储pandas对象。使用HDF5格式之前,必须导人HDFStore类。

from pandas.io.pytables import HDFStore

frame = pd.DataFrame(np.arange(16).reshape(4,4),

index=['white','black1','red','blue'],

columns=['up','down','right','left'])

frame1

store = HDFStore('mydata.h5')
store['obj1'] = frame
frame2

store['obj2'] = frame2
store


File path: mydata.h5

store['obj2']

store['obj1']

pickle ——python对象序列化

pickle模块实现了一个强大的算法,能够对用Python实现的数据结构进行序列化(pickling) 和反序列化操作。序列化是指把对象的层级结构转换为字节流的过程。序列化便于对象的传输、存储和重建,仅用接收器就能重建对象,还能保留它的所有原始特征。

import pickle

data = { 'color': ['white','red'], 'value': [5, 7]}

pickled_data = pickle.dumps(data)

pickled_data

b’\x80\x03}q\x00(X\x05\x00\x00\x00colorq\x01]q\x02(X\x05\x00\x00\x00whiteq\x03X\x03\x00\x00\x00redq\x04eX\x05\x00\x00\x00valueq\x05]q\x06(K\x05K\x07eu.’

nframe = pickle.loads(pickled_data)
nframe

{‘color’: [‘white’, ‘red’], ‘value’: [5, 7]}

用pandas实现对象序列化

用pandas库实现对象序列化(反序列化)很方便,所有工具都是现成的,无需在Python会话中导入cPickle模块,所有的操作都是隐式进行的。 pandas的序列化格式并不是完全使用ASCII编码

frame = pd.DataFrame(np.arange(16).reshape(4,4), index = ['up','down','left','right'])

frame.to_pickle('frame.pkl')

pd.read_pickle('frame.pkl')

pandas的所有序列化和反序列化操作都在后台运行,用户根本看不到。这使得这两项操作对数据分析人员而言尽可能简单和易于理解。

注意 :使用这种格式时,要确保打开的文件的安全性。pickle格式无法规避错误和恶意数据。

对接数据库

在很多应用中,所使用的数据来自于文本文件的很少,因为文本文件不是存储数据最有效的方式

数据往往存储于SQL类关系型数据库,作为补充,NoSQL数据库近来也已流行开来。

从SQL数据库加载数据,将其转换为DataFrame对象很简单pandas提供的几个函数简化了该过程。

pandas.io.sql模块提供独立于数据库、叫作sqlalchemy的统一接口。该接口简化了连接模式, 不管对于什么类型的数据库,操作命令都只有一套。连接数据库使用create_engine()函数,你可以用它配置驱动器所需的用户名、密码、端口和数据库实例等所有属性。 数据库URL的典型形式是:

dialect+driver://username:password@host:port/database

名称的标识名称,例如sqlite,mysql,postgresql,oracle,或mssql。drivername是用于使用全小写字母连接到数据库的DBAPI的名称。如果未指定,则将导入“默认”DBAPI(如果可用) - 此默认值通常是该后端可用的最广泛的驱动程序。

from sqlalchemy import create_engine

PostgreSQL

default

engine = create_engine(‘postgresql://scott:tiger@localhost/mydatabase’)

psycopg2

engine = create_engine(‘postgresql+psycopg2://scott:tiger@localhost/mydatabase’)

pg8000

engine = create_engine(‘postgresql+pg8000://scott:tiger@localhost/mydatabase’)

MySql

default

engine = create_engine(‘mysql://scott:tiger@localhost/foo’)

mysql-python

engine = create_engine(‘mysql+mysqldb://scott:tiger@localhost/foo’)

MySQL-connector-python

engine = create_engine(‘mysql+mysqlconnector://scott:tiger@localhost/foo’)

OurSQL

engine = create_engine(‘mysql+oursql://scott:tiger@localhost/foo’)

Oracle

engine = create_engine(‘oracle://scott:tiger@127.0.0.1:1521/sidname’)

engine = create_engine(‘oracle+cx_oracle://scott:tiger@tnsname’)

Microsoft SQL

pyodbc

engine = create_engine(‘mssql+pyodbc://scott:tiger@mydsn’)

pymssql

engine = create_engine(‘mssql+pymssql://scott:tiger@hostname:port/dbname’)

SQLite

由于SQLite连接到本地文件,因此URL格式略有不同。URL的“文件”部分是数据库的文件名。

对于相对文件路径,这需要三个斜杠:

sqlite:///

where is relative:

engine = create_engine(‘sqlite:///foo.db’)

对于绝对文件路径,三个斜杠后面是绝对路径:

Unix/Mac - 4 initial slashes in total

engine = create_engine(‘sqlite:////absolute/path/to/foo.db’)

Windows

engine = create_engine(‘sqlite:///C:\path\to\foo.db’)

Windows alternative using raw string

engine = create_engine(r’sqlite:///C:\path\to\foo.db’)

SQLite3数据读写

学习使用Python内置的SQLite数据库sqlite3。SQLite3工具实现了简单、 轻量级的DBMS SQL,因此可以内置于用Python语言实现的任何应用。它很实用,你可以在单个文件中创建一个嵌入式数据库。

若想使用数据库的所有功能而又不想安装真正的数据库,这个工具就是最佳选择。若想在使用真正的数据库之前练习数据库操作,或在单一程序中使用数据库存储数据而无需考虑接口, SQLite3都是不错的选择。

frame = pd.DataFrame( np.arange(20).reshape(4,5),
columns=['white','red','blue','black','green'])
frame

#连接SQLite3数据库
engine = create_engine('sqlite:///foo.db')

#把DataFrame转换为数据库表。
frame.to_sql('colors',engine)

#读取。
pd.read_sql('colors',engine)

数据处理

数据准备

  • 加载
  • 组装
    • 合并(merging)
    • 拼接(concatenation)
    • 组合(combine)
  • 变形(轴向旋转)
  • 删除

合并

对于合并操作,熟悉SQL的读者可以将其理解为JOIN操作,它使用一个或多个键把多行数据 结合在一起.

事实上,跟关系型数据库打交道的开发人员通常使用SQL的JOIN查询,用几个表共有的引用 值(键)从不同的表获取数据。以这些键为基础,我们能够获取到列表形式的新数据,这些数据是对几个表中的数据进行组合得到的。pandas库中这类操作叫作合并,执行合并操作的函数为 merge().

import pandas as pd
import numpy as np

frame1 = pd.DataFrame( {'id':['ball','pencil','pen','mug','ashtray'],
'price': [12.33,11.44,33.21,13.23,33.62]})
frame1

frame2 = pd.DataFrame( {'id':['pencil','pencil','ball','pen'],
'color': ['white','red','red','black']})
frame2

pd.merge(frame1,frame2)

frame1 = pd.DataFrame( {'id':['ball','pencil','pen','mug','ashtray'],
'color': [' white','red','red','black','green'],
'brand': ['OMG','ABC','ABC','POD','POD']})
frame1

frame2 = pd.DataFrame( {'id':['pencil','pencil','ball','pen'],
'brand': ['OMG','POD','ABC','POD']})
frame2

pd.merge(frame1,frame2)

pd.merge(frame1,frame2,on='id')

pd.merge(frame1,frame2,on='brand')

假如两个DataFrame基准列的名称不一致,该怎样进行合并呢?为 了解决这个问题,你可以用left_on和right_on选项指定第一个和第二个DataFrame的基准列。

frame2.columns = ['brand','sid']
frame2

pd.merge(frame1,frame2,left_on='id',right_on='sid')

merge()函数默认执行的是内连接操作;上述结果中的键是由交叉操作(intersection)得到的。

其他选项有左连接、右连接和外连接。外连接把所有的键整合到一起,其效果相当于左连接 和右连接的效果之和。连接类型用how选项指定。

frame2.columns = ['brand','id']
frame4 = pd.DataFrame( {'id':['ball','pencil','pen','mug','ashtray'],
'color': [' white','red','red','black','green'],
'brand': ['OMG','ABC','ABC','POD','POD']})

frame4

pd.merge(frame4,frame2,on='id')

pd.merge(frame4,frame2,on='id',how='outer')

pd.merge(frame4,frame2,on='id',how='left')

pd.merge(frame4,frame2,on='id',how='right')

pd.merge(frame4,frame2,on=['id','brand'],how='outer')

根据索引合并

pd.merge(frame4,frame2,right_index=True, left_index=True)

#frame4.join(frame2)  #会报错,因为列名有重合
frame2.columns = ['brand2','id2']
frame4.join(frame2)

拼接

另外一种数据整合操作叫作拼接(concatenation)。NumPy的concatenate()函数就是用于数 组的拼接操作。

array1  = np.arange(9).reshape((3,3))
array1

array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])

array2  = np.arange(9).reshape((3,3))+6
array2

array([[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])

np.concatenate([array1,array2],axis = 1)

array([[ 0, 1, 2, 6, 7, 8],
[ 3, 4, 5, 9, 10, 11],
[ 6, 7, 8, 12, 13, 14]])

np.concatenate([array1,array2],axis = 0)

array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])

pandas库以及它的Series和DataFrame等数据结构实现了带编号的轴,它可以进一步扩展数组

拼接功能。pandas的concat()函数实现了按轴拼接的功能。

ser1 = pd.Series(np.random.rand(4),index=[1,2,3,4])
ser1

1 0.676614
2 0.607490
3 0.491370
4 0.687731
dtype: float64

ser2 = pd.Series(np.random.rand(4),index=[5,6,7,8])
ser2

5 0.129962
6 0.650653
7 0.701635
8 0.820312
dtype: float64

pd.concat([ser1,ser2])

1 0.676614
2 0.607490
3 0.491370
4 0.687731
5 0.129962
6 0.650653
7 0.701635
8 0.820312
dtype: float64

concat()函数默认按照axis=0这条轴拼接数据,返回Series对象。如果指定axis=l,返回结果将是DataFrame对象。

pd.concat([ser1,ser2],axis=1)

pd.concat([ser1,ser2],keys=[1,2]) #等级索引

1 1 0.676614
2 0.607490
3 0.491370
4 0.687731
2 5 0.129962
6 0.650653
7 0.701635
8 0.820312
dtype: float64

frame5 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[1,2,3],columns=['A','B','C'])
frame5

frame2 = pd.DataFrame(np.random.rand(9).reshape(3,3), index=[4,5,6],columns=['A','B','C'])
frame2

pd.concat([frame5,frame2])

pd.concat([frame5,frame2],axis = 1)

组合

还有另外一种情况,我们无法通过合并或拼接方法组合数据。例如,两个数据集的索引完全或部分重合。

ser1 = pd.Series(np.random.rand(5),index=[1,2,3,4,5])
ser1

1 0.479704
2 0.956898
3 0.785966
4 0.868556
5 0.134064
dtype: float64

ser2 = pd.Series(np.random.rand(4),index=[2,4,5,6])
ser2

2 0.337220
4 0.570806
5 0.419785
6 0.140270
dtype: float64

ser1.combine_first(ser2)

1 0.479704
2 0.956898
3 0.785966
4 0.868556
5 0.134064
6 0.140270
dtype: float64

ser2.combine_first(ser1)

1 0.479704
2 0.337220
3 0.785966
4 0.570806
5 0.419785
6 0.140270
dtype: float64

ser1[:3].combine_first(ser2[:3])

1 0.479704
2 0.956898
3 0.785966
4 0.570806
5 0.419785
dtype: float64

轴向旋转

frame5 = pd.DataFrame(np.arange(9).reshape(3,3),
index=['white','black','red'],
columns=['ball','pen','pencil'])
print(frame5)

out:

       ball  pen  pencil
white 0 1 2
black 3 4 5
red 6 7 8

in:

frame6 = frame5.stack()  #列变行
frame6

out:

white  ball      0
pen 1
pencil 2
black ball 3
pen 4
pencil 5
red ball 6
pen 7
pencil 8
dtype: int32

in:

frame6.unstack()

frame6.unstack(0)

in:

frame5.unstack()

out:

ball    white    0
black 3
red 6
pen white 1
black 4
red 7
pencil white 2
black 5
red 8
dtype: int32

in:

longframe = pd.DataFrame({ 'color':['white','white','white','red','red','red','black','black','black'],
'item':['ball','pen','mug','ball','pen','mug','ball','pen','mug'],
'value': np.random.rand(9)})
longframe

这种记录数据的模式有几个缺点。例如其中一个缺点是,因为一些字段具有多样性和 重复性特点,所以选取列作为键时,这种格式的数据可读性较差,尤其是无法完全理解基准列和 其他列之间的关系a

除了长格式,还有一种把数据调整为表格形式的宽格式。这种模式可读性强,也易于连接其他表,且占用空间较少。因此一般而言,用它存储数据效率更高,虽然它的可操作性差,这一点 尤其体现在填充数据时。

如要选择一列或几列作为主键,所要遵循的规则是其中的元素必须是唯一的。

讲到格式转换,pandas提供了能够把长格式DataFrame转换为宽格式的pivot()函数,它以用 作键的一列或多列作为参数。

接着上面的例子,选择color列作为主键,item列作为第二主键,而它们所对应的元素则作 为DataFrame的新列。

wideframe = longframe.pivot('color','item')
wideframe

这种格式的DataFrame对象更加紧凑,它里面的数据可读性也更强。

删除

数据处理的最后一步是删除多余的行和列。

frame7 = pd.DataFrame(np.arange(9).reshape(3,3),
index=['white','black','red'],
columns=['ball','pen','pencil'])
frame7

del frame7['ball']  #删除列
frame7

frame7.drop('white') #删除行

frame7.drop('pen',axis=1)

数据转换

删除重复元素

dframe = pd.DataFrame({ 'color': ['white','white','red','red','white'],'value': [2,1,3,3,2]})
dframe

DataFrame对象的duplicated()函数可用来检测重复的行,返回元素为布尔型的Series对象。 每个元素对应一行,如果该行与其他行重复(也就是说该行不是第一次出现),则元素为True; 如果跟前面不重复,则元素就为False。

dframe.duplicated()

0 False
1 False
2 False
3 True
4 True
dtype: bool

返回元素为布尔值的Series对象用处很大,特别适用于过滤操作。

dframe[dframe.duplicated()]

通常,所有重复的行都需要从DataFrame对象中删除。pandas库的drop_duplicates()函数实

现了删除功能,该函数返回的是删除重复行后的DataFmme对象。

dframe.drop_duplicates()

映射

用映射替换元素

frame8 = pd.DataFrame({ 'item':['ball','mug','pen','pencil','ashtray'],
'color': ['white','rosso','verde','black','yellow'],
'price':[5.56,4.20,1.30,0.56,2.75]})
frame8

要用新元素替换不正确的元素,需要定义一组映射关系。在映射关系中,旧元素作为键,新元素作为值。

newcolors ={
'rosso':'red',
'verde':'green'
}
frame8.replace(newcolors)

DataFrame对象中两种旧颜色被替换为正确的元素。还有一种常见情况,是把NaN替换为其他值,比如0。这种情况下,仍然可以用replace()函数,它能优雅地完成该项操作。

ser = pd.Series([13,np.nan,4,6,np.nan,3])
ser

0 13.0
1 NaN
2 4.0
3 6.0
4 NaN
5 3.0
dtype: float64

ser.replace(np.nan,0)

0 13.0
1 0.0
2 4.0
3 6.0
4 0.0
5 3.0
dtype: float64

用映射添加元素

frame9  = pd.DataFrame({ 'item':['ball','mug','pen','pencil','ashtray'], 'color':['white','red','green','black','yellow']})
frame9

price = {
'ball' : 5.56,
'mug' : 4.20,
'bottle1' : 1.30,
'scissors' : 3.41,
'pen' : 1.30,
'pencil' : 0.56,
'ashtray' : 2.75
}
frame9['price'] = frame9['item'].map(price)
frame9

重命名轴索引

reindex = {
0:'first',
1:'second',
2:'third',
3:'fourth',
4:'fifth'
}
frame9.rename(reindex)

recolumn ={
'item':'object',
'price':'value'
}

索引被重命名。若要重命名各列,必须使用columns选项

frame9.rename(index = reindex,columns=recolumn)

对于只有单个元素要替换的最简单情况,可以对传入的参数做进一步限定,而无需把多个变 量都写出来,也避免产生多次赋值操作。

frame9.rename(index={1:'first'},columns = {'item':'object'})

frame9

frame9.rename(index={1:'first'},columns = {'item':'object'},inplace=True)
frame9

离散化和面元划分

ages=[20,22,25,27,21,23,37,31,61,45,41,32]
bins=[18,25,35,60,100]
cat = pd.cut(ages,bins)
cat

out:

[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
Length: 12
Categories (4, interval[int64]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]

in:

cat.codes

array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)

每个面元的出现次数,即每个类别有多少个元素,可使用value_counts()函数。

pd.value_counts(cat)  ##查看每个种类的数量

(18, 25] 5
(35, 60] 3
(25, 35] 3
(60, 100] 1
dtype: int64

cuts = pd.cut(ages,bins,right=False)   ## 使用right=False可以修改开端和闭端

out:

[[18, 25), [18, 25), [25, 35), [25, 35), [18, 25), ..., [25, 35), [60, 100), [35, 60), [35, 60), [25, 35)]
Length: 12
Categories (4, interval[int64]): [[18, 25) < [25, 35) < [35, 60) < [60, 100)]

in:

cut1 = pd.cut(ages,bins,right=False,labels=list('abcd'))
cut1

out:

[a, a, b, b, a, ..., b, d, c, c, b]
Length: 12
Categories (4, object): [a < b < c < d]

in:

pd.cut(ages,5)  # 如果cut传入的是数字n,那么就会均分成n份。

out:

[(19.959, 28.2], (19.959, 28.2], (19.959, 28.2], (19.959, 28.2], (19.959, 28.2], ..., (28.2, 36.4], (52.8, 61.0], (44.6, 52.8], (36.4, 44.6], (28.2, 36.4]]
Length: 12
Categories (5, interval[float64]): [(19.959, 28.2] < (28.2, 36.4] < (36.4, 44.6] < (44.6, 52.8] < (52.8, 61.0]]
pd.value_counts(pd.cut(ages,4))

(19.959, 30.25] 6
(30.25, 40.5] 3
(40.5, 50.75] 2
(50.75, 61.0] 1
dtype: int64

pd.qcut(ages,5)

out:

[(19.999, 22.2], (19.999, 22.2], (22.2, 25.8], (25.8, 31.6], (19.999, 22.2], ..., (25.8, 31.6], (40.2, 61.0], (40.2, 61.0], (40.2, 61.0], (31.6, 40.2]]
Length: 12
Categories (5, interval[float64]): [(19.999, 22.2] < (22.2, 25.8] < (25.8, 31.6] < (31.6, 40.2] < (40.2, 61.0]]

in:

pd.value_counts(pd.qcut(ages,4))

out:

(38.0, 61.0]       3
(29.0, 38.0] 3
(22.75, 29.0] 3
(19.999, 22.75] 3
dtype: int64

异常值检测和过滤

data = pd.DataFrame(np.random.randn(1000,3))
data.describe()

可能会将比标准差大3倍的元素视作异常值。用std()函数就可以求得DataFrame对象每一列的标准差。

3σ原则

data.std()

0 1.049592
1 1.025227
2 1.001221
dtype: float64

data[(np.abs(data-data.mean())>(3*data.std())).any(1)]  #过滤条件

排序

nframe = pd.DataFrame(np.arange(25).reshape(5,5))
nframe

new_order = np.random.permutation(5)  #乱序整数[0-4]  如果是100 [0-99]
new_order

array([4, 0, 3, 1, 2])

nframe.take(new_order)  #排序

np.random.permutation(100)

out:

array([94,  5, 24, 55, 99, 80, 76, 25, 82, 66, 52, 37, 87, 16, 15, 78, 69,
41, 72, 71, 89, 3, 58, 10, 17, 35, 30, 77, 22, 14, 13, 98, 88, 32,
36, 4, 33, 11, 59, 40, 79, 46, 50, 8, 54, 1, 23, 93, 95, 38, 90,
9, 62, 26, 73, 91, 75, 21, 7, 56, 83, 18, 6, 67, 42, 74, 43, 84,
47, 86, 65, 49, 60, 29, 34, 96, 19, 81, 2, 20, 31, 51, 70, 39, 63,
48, 53, 45, 28, 12, 68, 57, 27, 0, 97, 92, 61, 64, 85, 44])
nframe.take([3,4,2])  #只对一部分排序

sample = np.random.randint(len(nframe),size =3)  #随机整数
sample

array([2, 2, 4])

nframe.take(sample)

数据聚合

GroupBy

frame10 = pd.DataFrame({ 'color': ['white','red','green','red','green'],'object': ['pen','pencil','pencil','ashtray','pen'],
'price1' : [5.56,4.20,1.30,0.56,2.75],'price2' : [4.75,4.12,1.60,0.75,3.15]})
frame10

group = frame10['price1'].groupby(frame10['color'])
group
group.groups

{‘green’: Int64Index([2, 4], dtype=’int64’),
‘red’: Int64Index([1, 3], dtype=’int64’),
‘white’: Int64Index([0], dtype=’int64’)}

group.sum()

color
green 4.05
red 4.76
white 5.56
Name: price1, dtype: float64

group.mean()

color
green 2.025
red 2.380
white 5.560
Name: price1, dtype: float64

等级分组

ggroup = frame10['price1'].groupby([frame10['color'],frame10['object']])
ggroup.groups

{(‘green’, ‘pen’): Int64Index([4], dtype=’int64’),
(‘green’, ‘pencil’): Int64Index([2], dtype=’int64’),
(‘red’, ‘ashtray’): Int64Index([3], dtype=’int64’),
(‘red’, ‘pencil’): Int64Index([1], dtype=’int64’),
(‘white’, ‘pen’): Int64Index([0], dtype=’int64’)}

ggroup.sum()

out:

color  object 
green pen 2.75
pencil 1.30
red ashtray 0.56
pencil 4.20
white pen 5.56
Name: price1, dtype: float64

in:

frame10[['price1','price2']].groupby(frame10['color']).mean()

组迭代

for name,group in frame10.groupby('color'):
print(name)
print(group)

out:

green
color object price1 price2
2 green pencil 1.30 1.60
4 green pen 2.75 3.15
red
color object price1 price2
1 red pencil 4.20 4.12
3 red ashtray 0.56 0.75
white
color object price1 price2
0 white pen 5.56 4.75

链式转换

result1 = frame10['price1'].groupby(frame10['color']).mean()
result1

color
green 2.025
red 2.380
white 5.560
Name: price1, dtype: float64

result2 = frame10.groupby(frame10['color']).mean()
result2

frame10.groupby(frame10['color'])['price1'].mean()

color
green 2.025
red 2.380
white 5.560
Name: price1, dtype: float64

(frame10.groupby(frame10['color']).mean())['price1']

color
green 2.025
red 2.380
white 5.560
Name: price1, dtype: float64

frame10.groupby('color').mean().add_prefix('mean_')

替换

maps = {'x':xx}
data['name'] = data['name'].apply(lamda x: maps[x])

取值

sub_data = data.loc[data['name']==1]
------ 本文结束 🎉🎉 谢谢观看 ------
0%