利用python进行数据分析之数据规整化

数据分析和建模大部分时间都用在数据准备上,数据的准备过程包括:加载,清理,转换与重塑。

合并数据集

pandas对象中的数据可以通过一些内置方法来进行合并:

pandas.merge可根据一个或多个键将不同DataFrame中的行连接起来,实现类似于数据库中的连接操作。

pandas.cancat表示沿着一条轴将多个对象堆叠到一起。

实例方法combine_first可以将重复数据编接在一起,用一个对象中的值填充另一个对象的缺失值。

下面将进行分别讲解:

1、数据库风格的DateFrame合并

数据集的合并运算是通过一个或者多个键将行连接起来,主要使用的merge或者join方法。

>>> import pandas as pd
>>> from pandas import DataFrame
>>> import numpy as np
>>> df1=DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})
>>> df2=DataFrame({'key':['a','b','d'],'data2':range(3)})
>>> pd.merge(df1,df2)
data1 key data2
0 0 b 1
1 1 b 1
2 6 b 1
3 2 a 0
4 4 a 0
5 5 a 0
#未显示指定用何列拼接,默认用重叠列的作为键,最好显示指定
>>> pd.merge(df1,df2,on='key')
data1 key data2
0 0 b 1
1 1 b 1
2 6 b 1
3 2 a 0
4 4 a 0
5 5 a 0
#当两个对象列明不同可以进行分别指定
>>> df3=DataFrame({'lkey':['b','b','a','c','a','a','b'],'data1':range(7)})
>>> df4=DataFrame({'rkey':['a','b','d'],'data2':range(3)})
>>> pd.merge(df3,df4,left_on='lkey',right_on='rkey')
data1 lkey data2 rkey
0 0 b 1 b
1 1 b 1 b
2 6 b 1 b
3 2 a 0 a
4 4 a 0 a
5 5 a 0 a
#默认情况下merge函数进行的是交集操作,可以指定how参数来实现左右连接与并集(outer)
#根据多个键进行合并,传入一个由列名组成的列表即可
>>> left=DataFrame({'key1':['foo','foo','bar'],'key2':['one','two','three'],'lval':[1,2,3]})
>>> right=DataFrame({'key1':['foo','foo','bar','bar'],'key2':['one','two','one','two'],'rval':[4,5,6,7]})
>>> pd.merge(left,right,on=['key1','key2'],how='outer')
key1 key2 lval rval
0 foo one 1 4
1 foo two 2 5
2 bar three 3 NaN
3 bar one NaN 6
4 bar two NaN 7

对于合并运算需要考虑的最后一个问题是对重复列名的处理,merge有一个suffixes选项,用于指定附加到左右两个DataFrame对象的重叠列名上的字符串:

>>> pd.merge(left,right,on='key1')
key1 key2_x lval key2_y rval
0 foo one 1 one 4
1 foo one 1 two 5
2 foo two 2 one 4
3 foo two 2 two 5
4 bar three 3 one 6
5 bar three 3 two 7
>>> pd.merge(left,right,on='key1',suffixes=('_left','_right'))
key1 key2_left lval key2_right rval
0 foo one 1 one 4
1 foo one 1 two 5
2 foo two 2 one 4
3 foo two 2 two 5
4 bar three 3 one 6
5 bar three 3 two 7
merge函数的参数表
left 参与合并的左侧DataFrame
right 参与合并的右侧DataFrame
how 选定参与合并的方式(inner,outer,left等)
on 用于连接的列名
left_on 左侧DataFrame中用于连接的键
right_on 右侧DataFrame中用于连接的键
sort 根据连接键对合并后的数据进行排序,默认为True
suffixes

字符串元组,用于追加到重叠列名的末尾

2、索引上的合并

有时,DataFrame中的连接位于其索引中,在此种情况下可以传入left_index=True或者right_index=True以说明索引应该被用作连接键:

>>> left1=DataFrame({'key':['a','b','a','a','b','c'],'value':range(6)})
>>> right1=DataFrame({'group':[3.5,7]},index=['a','b'])
>>> left1
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
>>> right1
group
a 3.5
b 7.0

对于层次化索引数据,相对更为复杂些,在这种情况下,必须以列表的形式指明用作合并键的多个列

>>> lenth=DataFrame({'key1':['ohio','ohio','ohio','nevada','nevada'],'key2':[2000,2001,2002,2001,2002],'data':np.arange(5)})
>>> righth=DataFrame(np.arange(12).reshape((6,2)),index=[['neveda','neveda','ohio','ohio','ohio','ohio'],[2001,2000,2000,2000,2001,2002]],columns=['event1','event2'])
>>> lenth
data key1 key2
0 0 ohio 2000
1 1 ohio 2001
2 2 ohio 2002
3 3 nevada 2001
4 4 nevada 2002
>>> righth
event1 event2
neveda 2001 0 1
2000 2 3
ohio 2000 4 5
2000 6 7
2001 8 9
2002 10 11
>>> pd.merge(lenth,righth,left_on=['key1','key2'],right_index=True)
data key1 key2 event1 event2
0 0 ohio 2000 4 5
0 0 ohio 2000 6 7
1 1 ohio 2001 8 9
2 2 ohio 2002 10 11

DataFrame还有一个join实例方法,它可以更为方便的实现按索引合并,还可以合并多个带有相同或者相似索引的DataFrame对象,而不管其是否有重叠的列:

>>> left2=DataFrame([[1,2],[3,4],[5,6]],index=['a','c','e'],columns=['ohio','nevada'])
>>> left2
ohio nevada
a 1 2
c 3 4
e 5 6
>>> right2=DataFrame([[7,8],[9,10],[11,12],[13,14]],index=['b','c','d','e'],columns=['missouri','alambda'])
>>> right2
missouri alambda
b 7 8
c 9 10
d 11 12
e 13 14
>>> left2.join(right2,how='outer')
ohio nevada missouri alambda
a 1 2 NaN NaN
b NaN NaN 7 8
c 3 4 9 10
d NaN NaN 11 12
e 5 6 13 14

3、轴向连接

纵向上,numpy有一个用于合并原始numpy数组的concatenation函数:

>>> arr=np.arange(12).reshape((3,4))
>>> arr
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> np.concatenate([arr,arr],axis=1)
array([[ 0, 1, 2, 3, 0, 1, 2, 3],
[ 4, 5, 6, 7, 4, 5, 6, 7],
[ 8, 9, 10, 11, 8, 9, 10, 11]])
>>> np.concatenate([arr,arr],axis=0)
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
#pandas的concat函数提供了一种能够解决这些问题的可靠方式,默认情况下,concat在0轴上工作,
>>> s1=pd.Series([0,1],index=['a','b'])
>>> s2=pd.Series([2,3,4],index=['c','d','e'])
>>> s3=pd.Series([5,6],index=['f','g'])
>>> pd.concat([s1,s2,s3])
a 0
b 1
c 2
d 3
e 4
f 5
g 6
dtype: int64
#axis=1时,得到一个DataFrame对象
>>> pd.concat([s1,s2,s3],axis=1)
0 1 2
a 0 NaN NaN
b 1 NaN NaN
c NaN 2 NaN
d NaN 3 NaN
e NaN 4 NaN
f NaN NaN 5
g NaN NaN 6

可以通过join_axes指定要在其他轴上使用的索引:

>>> s4=pd.concat([s1*5,s3])
>>> s4
a 0
b 5
f 5
g 6
dtype: int64
>>> pd.concat([s1,s4],axis=1,join_axes=[['a','c','b','e']])
0 1
a 0 0
c NaN NaN
b 1 5
e NaN NaN

 当你需要区分参与连接的片段时,可以在连接轴上创建一个层次化索引,使用key参数可以达到这个目的

>>> result=pd.concat([s1,s2,s3],keys=['one','two','three'])
>>> result
one a 0
b 1
two c 2
d 3
e 4
three f 5
g 6
dtype: int64
#如果沿着axis=1对Series进行合并,则keys会变成合并后DataFrame的列头
>>> pd.concat([s1,s2,s3],keys=['one','two','three'],axis=1)
one two three
a 0 NaN NaN
b 1 NaN NaN
c NaN 2 NaN
d NaN 3 NaN
e NaN 4 NaN
f NaN NaN 5
g NaN NaN 6

最后一个需要考虑的问题是,跟当前分析无关的DataFrame索引,直接传入ignore_index=True即可:

>>> df1=DataFrame(np.random.randn(3,4),columns=['a','b','c','d'])
>>> df2=DataFrame(np.random.randn(2,3),columns=['b','d','a'])
>>> df1
a b c d
0 -1.928978 -1.202455 -0.180614 0.693538
1 -1.234482 0.664544 0.259534 0.429279
2 0.305255 0.133844 0.934637 0.243345
>>> df2
b d a
0 -1.582425 0.055378 0.288906
1 -0.381170 0.731310 -0.661805
>>> pd.concat([df1,df2],ignore_index=True)
a b c d
0 -1.928978 -1.202455 -0.180614 0.693538
1 -1.234482 0.664544 0.259534 0.429279
2 0.305255 0.133844 0.934637 0.243345
3 0.288906 -1.582425 NaN 0.055378
4 -0.661805 -0.381170 NaN 0.731310
#注意区分与下面区别
>>> pd.concat([df1,df2])
a b c d
0 -1.928978 -1.202455 -0.180614 0.693538
1 -1.234482 0.664544 0.259534 0.429279
2 0.305255 0.133844 0.934637 0.243345
0 0.288906 -1.582425 NaN 0.055378
1 -0.661805 -0.381170 NaN 0.731310

4、合并重叠数据

还有一种数据不能用简单的合并或者连接运算来处理比如你有可能索引全部或部分重叠的两个数据集:

>>> a=Series([np.nan,2.5,np.nan,3.5,4.5,np.nan],index=['f','e','d','c','b','a'])
>>> b=Series(np.arange(len(a),dtype=np.float64),index=['f','e','d','c','b','a'])
>>> a
f NaN
e 2.5
d NaN
c 3.5
b 4.5
a NaN
dtype: float64
>>> b
f 0
e 1
d 2
c 3
b 4
a 5
dtype: float64
>>> np.where(pd.isnull(a),b,a)
array([ 0. , 2.5, 2. , 3.5, 4.5, 5. ])
#可以看作用参数对象中的数据为调用者对象的缺失数据打补丁

也可用combine_first方法

>>> df1=DataFrame({'a':[1,np.nan,5,np.nan],'b':[np.nan,2,np.nan,6],'c':range(2,18,4)})
>>> df1
a b c
0 1 NaN 2
1 NaN 2 6
2 5 NaN 10
3 NaN 6 14
>>> df2=DataFrame({'a':[5,4,np.nan,3,7],'b':[np.nan,3,4,6,8]})
>>> df2
a b
0 5 NaN
1 4 3
2 NaN 4
3 3 6
4 7 8
>>> df1.combine_first(df2)
a b c
0 1 NaN 2
1 4 2 6
2 5 4 10
3 3 6 14
4 7 8 NaN

重塑和轴向旋转

1、重塑层次化索引

层次化索引技术为DataFrame数据重拍运算提供了一种具有良好一致性的方式,主要功能有二:

stack,将数据的列旋转为行

unstack,将数据的行旋转为列

>>> data=DataFrame(np.arange(6).reshape((2,3)),index=['ohio','colorado'],columns=['one','two','three'])
>>> data
one two three
ohio 0 1 2
colorado 3 4 5
>>> data.index
Index([u'ohio', u'colorado'], dtype='object')
>>> data.index.name='state'
>>> data.columns.name='number'
>>> data
number one two three
state
ohio 0 1 2
colorado 3 4 5
>>> data.stack()
state number
ohio one 0
two 1
three 2
colorado one 3
two 4
three 5
dtype: int32
#将列转化为行,得到一个Series
#对于一个层次化索引的Series,可以用unstack将其重排为一个DataFrame

默认情况下unstack操作的是最内层的,可传入分层级别的编号和名称参数,即可对其他级别进行untack操作:

>>> result=data.stack()
>>> result
state number
ohio one 0
two 1
three 2
colorado one 3
two 4
three 5
dtype: int32
>>> result.unstack(0)
state ohio colorado
number
one 0 3
two 1 4
three 2 5
>>> result.unstack('state')
state ohio colorado
number
one 0 3
two 1 4
three 2 5

在对DataFrame,进行unset操作时,作为旋转轴的级别将会成为结果中的最低级别(即旋转轴索引将成为最内层索引):

>>> df=DataFrame({'left':result,'right':result+5},columns=['left','right'])
>>> df.columns.name='side'
>>> df
side left right
state number
ohio one 0 5
two 1 6
three 2 7
colorado one 3 8
two 4 9
three 5 10
>>> df.unstack('state')
side left right
state ohio colorado ohio colorado
number
one 0 3 5 8
two 1 4 6 9
three 2 5 7 10
>>> df.unstack('state').stack('side')
state ohio colorado
number side
one left 0 3
right 5 8
two left 1 4
right 6 9
three left 2 5
right 7 10

数据转换

除了数据合并与重排之外,另一类重要的操作是过滤,清理。

1、移除重复数据

DataFrame的duplicated方法返回一个布尔型Series,表示各行是否为重复行

>>> data=DataFrame({'k1':['one']*3+['two']*4,'k2':[1,1,2,3,3,4,4]})
>>> data
k1 k2
0 one 1
1 one 1
2 one 2
3 two 3
4 two 3
5 two 4
6 two 4
>>> data.duplicated()
0 False
1 True
2 False
3 False
4 True
5 False
6 True
dtype: bool
#drop_duplicates方法用于返回一个移除了重复行的DataFrame,删除那些为True的行
>>> data.drop_duplicates()
k1 k2
0 one 1
2 one 2
3 two 3
5 two 4
#可以指定过滤重复列的项
>>> data.drop_duplicates(['k1'])
k1 k2
0 one 1
3 two 3
#以上两个方法默认保留第一个出现的组合值,传入take_last=True则可以保留最后一个

2、利用函数或映射进行数据转换

Series的map方法可以接受一个函数或含有映射关系的字典型对象

>>> data=DataFrame({'food':['bacon','pulled prok','bacon','pastrami','corned beef','bacon','pastrami','honey ham','nova lox'],'ounce':[4,3,12,6,7.5,8,3,5,6]})
>>> data
food ounce
0 bacon 4.0
1 pulled prok 3.0
2 bacon 12.0
3 pastrami 6.0
4 corned beef 7.5
5 bacon 8.0
6 pastrami 3.0
7 honey ham 5.0
8 nova lox 6.0
>>> meat_to_animal={'bacon':'pig','pulled pork':'pig','pastrami':'cow','honey ham':'pig','nova lox':'salmon'}
>>> data['animal']=data['food'].map(meat_to_animal)
>>> data
food ounce animal
0 bacon 4.0 pig
1 pulled prok 3.0 NaN
2 bacon 12.0 pig
3 pastrami 6.0 cow
4 corned beef 7.5 NaN
5 bacon 8.0 pig
6 pastrami 3.0 cow
7 honey ham 5.0 pig
8 nova lox 6.0 salmon

3、替换值

利用fillna方法填充缺失数据可以看作值替换的一种特殊情况,但是使用replace则提供了一种实现该功能更简单的方法:

>>> pd.Series([1,-999,2,-999,-1000,3])
0 1
1 -999
2 2
3 -999
4 -1000
5 3
dtype: int64
>>> data=pd.Series([1,-999,2,-999,-1000,3])
>>> data.replace(-999,np.nan)
0 1
1 NaN
2 2
3 NaN
4 -1000
5 3
dtype: float64
#如果想一次性替换多个值,可以传入一个由待替换值组成的列表以及一个替换值:

>>> data.replace([-999,-1000],np.nan)
  0      1
  1    NaN
  2      2
  3    NaN
  4    NaN
  5      3
dtype: float64

#如果希望对不同的值做不同的替换,则传入一个由替换关系组成的列表即可:

>>> data.replace([-999,-1000],[np.nan,0])
 0 1
 1 NaN
 2 2
 3 NaN
 4 0
 5 3
 dtype: float64

#传入的参数也可以是字典形式:{-999:np.nan,-1000:0}

4、重命名轴索引

轴标签也可以通过函数或映射进行转换,从而得到一个新对象。轴也可以被修改,而无需创建一个新的数据结构。

轴标签也可以使用map方法

>>> df1=DataFrame(np.arange(12).reshape((3,4)),index=['ohio','colorado','new york'],columns=['one','two','three','four'])
>>> df1
one two three four
ohio 0 1 2 3
colorado 4 5 6 7
new york 8 9 10 11
>>> df1.index.map(str.upper)
array(['OHIO', 'COLORADO', 'NEW YORK'], dtype=object)
>>> df1.index=df1.index.map(str.upper)
>>> df1
one two three four
OHIO 0 1 2 3
COLORADO 4 5 6 7
NEW YORK 8 9 10 11
#如果不想修改原始数据可以创建数据的转换版
>>> df1.rename(columns=str.upper)
ONE TWO THREE FOUR
OHIO 0 1 2 3
COLORADO 4 5 6 7
NEW YORK 8 9 10 11
#rename也可以结合字典型对象实现对部分轴标签进行更新
>>> df1.rename(index={'OHIO':'INDIANA'},columns={'three':'peekaboo'})
one two peekaboo four
INDIANA 0 1 2 3
COLORADO 4 5 6 7
NEW YORK 8 9 10 11

5、离散化和面元划分

为了便于分析,连续数据常常需要被离散化或拆分为"面元",此时需要使用pandas库中的cut函数:

>>> ages=[20,22,25,27,21,23,37,31,61,45,41,32]
>>> bins=[18,25,35,60,100]
>>> cats=pd.cut(ages.bins)
>>> cats=pd.cut(ages,bins)
>>> cats
[(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]]
Length: 12
Categories (4, object): [(18, 25] < (25, 35] < (35, 60] < (60, 100]]
#pandas返回的是一个特殊的categorcal对象,它含有一个表示不同分类名称的levels数组以及一个为年龄数据进行标号的labels属性
>>> cats.labels
array([0, 0, 0, 1, 0, 0, 2, 1, 3, 2, 2, 1], dtype=int8)
>>> cats.levels
Index([u'(18, 25]', u'(25, 35]', u'(35, 60]', u'(60, 100]'], dtype='object')

也可以设置自定义的面元名称,将labels选项设置为一个列表或元组即可:

>>> pd.cut(ages,bins,labels=['youth','youngadult','middleaged','senior'])
[youth, youth, youth, youngadult, youth, ..., youngadult, senior, middleaged, middleaged, youngadult]
Length: 12
Categories (4, object): [youth < youngadult < middleaged < senior]

如果cut传入的是面元的数量而不是确切的面元边界,则它会根据数据的最小值和最大值计算等长的面元,实现均分:

>>> data=np.random.randn(20)
>>> pd.cut(data,4,precision=2)
[(-1.018, 0.095], (-1.018, 0.095], (0.095, 1.21], (0.095, 1.21], (-1.018, 0.095], ..., (0.095, 1.21], (0.095, 1.21], (-1.018, 0.095], (0.095, 1.21], (-1.018, 0.095]]
Length: 20
Categories (4, object): [(-2.14, -1.018] < (-1.018, 0.095] < (0.095, 1.21] < (1.21, 2.32]]

qcut是一个类似与cut的函数,它可以根据样本分位数对数据进行面元划分:

>>> data=np.random.randn(1000)
>>> cats=pd.qcut(data,4) #按四分位数进行切割
>>> cats
[(0.644, 3.0404], (-0.00691, 0.644], (0.644, 3.0404], (-0.00691, 0.644], (0.644, 3.0404], ..., (-0.00691, 0.644], (-0.00691, 0.644], (0.644, 3.0404], [-3.753, -0.709], (-0.709, -0.00691]]
Length: 1000
Categories (4, object): [[-3.753, -0.709] < (-0.709, -0.00691] < (-0.00691, 0.644] < (0.644, 3.0404]]
>>> pd.value_counts(cats)
(0.644, 3.0404] 250
(-0.00691, 0.644] 250
(-0.709, -0.00691] 250
[-3.753, -0.709] 250
dtype: int64

6、检测和过滤异常值

异常值的过滤或变换运算在很大程度上就是数组运算:

>>> data=DataFrame(np.random.randn(1000,4))
>>> data.describe()
0 1 2 3
count 1000.000000 1000.000000 1000.000000 1000.000000
mean -0.067684 0.067924 0.025598 -0.002298
std 0.998035 0.992106 1.006835 0.996794
min -3.428254 -3.548824 -3.184377 -3.745356
25% -0.774890 -0.591841 -0.641675 -0.644144
50% -0.116401 0.101143 0.002073 -0.013611
75% 0.616366 0.780282 0.680391 0.654328
max 3.366626 2.653656 3.260383 3.927528
>>> col=data[3] #选取具体某列
>>> col[np.abs(col)>3]
97 3.927528
305 -3.399312
400 -3.745356
Name: 3, dtype: float64
#找出绝对值大小超过3的值

7、排列和随机抽样

利用numpy.random.permutation函数可以实现对Series或DataFrame的列的排列工作:

>>> df=DataFrame(np.arange(5*4).reshape(5,4))
>>> sapmler=np.random.permutation(5)
>>> df
0 1 2 3
0 0 1 2 3
1 4 5 6 7
2 8 9 10 11
3 12 13 14 15
4 16 17 18 19
>>> df.take(sapmler)
0 1 2 3
1 4 5 6 7
0 0 1 2 3
2 8 9 10 11
3 12 13 14 15
4 16 17 18 19

8、计算指标/哑变量

另一种常见的统计建模或机器学习的转换方式是将分类变量转换为哑变量矩阵,pandas有一个get_dummies函数可以实现该功能

>>> df=DataFrame({'key':['b','b','a','c','a','b'],'data1':range(6)})
>>> df
data1 key
0 0 b
1 1 b
2 2 a
3 3 c
4 4 a
5 5 b
>>> pd.get_dummies(df['key'])
a b c
0 0 1 0
1 0 1 0
2 1 0 0
3 0 0 1
4 1 0 0
5 0 1 0

有时候需要给DataFrame的列加上一个前缀,能够与其他的数据进行合并,get_dummies函数的prefix参数可以实现该功能

>>> dum=pd.get_dummies(df['key'],prefix='key')
>>> df_with_dummy=df[['data1']].join(dum)
>>> df_with_dummy
data1 key_a key_b key_c
0 0 0 1 0
1 1 0 1 0
2 2 1 0 0
3 3 0 0 1
4 4 1 0 0
5 5 0 1 0

结合cut与get_dummies离散化二元化数据:

>>> values=np.random.randn(10)
>>> values
array([ 0.04648638, -0.61044135, -0.39498189, 1.19991518, -0.45181441,
-0.15538512, -0.15351407, 0.01119376, -0.05055467, 0.42021107])
>>> bins=[0,0.2,0.4,0.6,0.8,1]
>>> pd.get_dummies(pd.cut(values,bins))
(0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1]
0 1 0 0 0 0
1 0 0 0 0 0
2 0 0 0 0 0
3 0 0 0 0 0
4 0 0 0 0 0
5 0 0 0 0 0
6 0 0 0 0 0
7 1 0 0 0 0
8 0 0 0 0 0
9 0 0 1 0 0

字符串操作

python能够成为流行的数据处理语言,部分原因是其简单易用的字符串和文本处理功能。

1、字符串对象方法

以逗号分隔的字符串可以用split拆分为数段,split常常结合strip一起使用:

>>> val='a,b, guido'
>>> val.split(',')
['a', 'b', ' guido']
>>> pieces=[x.strip() for x in val.split(',')]
>>> pieces
['a', 'b', 'guido']

利用加法可以将子字符串以双冒号的形式连接起来,但是更简便的方式是使用字符串'::'的join方法传入一个元组或列表:

>>> first,second,third=pieces
>>> '::'.join(pieces)
'a::b::guido'

另一类方法关注的是子串定位,检测子串的最佳方式是利用python的in关键字(index与find同样适用):

>>> 'guido'in val
True
>>> val.index(',')
1
>>> val.find(':')
-1
>>>
#如果找不到字符串,find返回一个-1,index会引发异常

此外,还有一个count函数,可返回指定子串的出现次数,replace用于将指定模式替换为另一个模式:

>>> val.count(',')
2
>>> val.replace(',',':')
'a:b: guido'
python内置字符串说明列表
count 返回子串在字符串中出现的次数
endswith,startswith 如果字符串以某个后缀结尾(开头),返回ture
join 将字符串用作连接其他字符串序列的分隔符
index 如果在字符串中找到子串,返回子串在字符串中的第一个字符所在的位置
find 如果在字符串中找到子串,返回子串在字符串中的第一个字符所在的位置,没找到则返回-1
replace 用一个字符串替换指定字符串
strip,rstrip,lstrip 去除空白符,包括换行符
split 通过指定的分隔符将字符串拆分为一组字符串
lower,upper 将字符串转换为小写或大写

2、正则表达式

正则表达式提供了一种灵活在文本中搜索或匹配字符串模式的方式。

re模块的函数可以分为三个大类:模式匹配,替换和拆分,这三个是相辅相成:

>>> text="foo  bar\t baz  \tqux"
>>> text
'foo bar\t baz \tqux'
>>> re.split('\s+',text)
['foo', 'bar', 'baz', 'qux']

一般可以用re.compile编译一个可重用的regrex对象,且针对许多字符串用同一正则表达式时,通过使用re.compile可以节省大量cpu计算时间:

>>> regrex=re.compile('\s+')
>>> regrex.split(text)
['foo', 'bar', 'baz', 'qux']
#如果只希望得到regrex匹配的所有模式,可以使用findall方法
>>> regrex.findall(text)
[' ', '\t ', ' \t']

match功能和search功能跟findall功能类似,findall返回的是字符串中所有的匹配项,而search只返回第一个匹配项,match更加严格,它只匹配字符串的首部,sub方法会将匹配到的模式替换为指定字符串,并返回得到的字符串。

ps:想要用好正则表达式,需要大量的额外练习与使用

3、pandas中矢量化的字符串函数

清理待分析的散乱数据时,常常需要做一些字符串规整化的工作:

通过data.map,所有字符串和正则表达式方法都能被用于各个值,但传入na就会报错,Series提供了一些能够跳过NA值的字符串操作方法

>>> data={'Dave':'dave@google.com','Steve':'steve@gmail.com','Rob':'rob@gmail.com','Wes':np.nan}
>>> data=pd.Series(data)
>>> data
Dave dave@google.com
Rob rob@gmail.com
Steve steve@gmail.com
Wes NaN
dtype: object
>>> data.isnull()
Dave False
Rob False
Steve False
Wes True
dtype: bool
>>> data.str.contains('gmail')
Dave False
Rob True
Steve True
Wes NaN
dtype: object

这里也可以通过正则表达式解决:

>>> data.str.findall(pattern,flags=re.IGNORECASE)
Dave [dave@google.com]
Rob [rob@gmail.com]
Steve [steve@gmail.com]
Wes NaN
dtype: object

有两个方法可以实现矢量化的元素获取操作:1)使用str.get,2)在str属性上使用索引

上一篇:Pig Latin程序设计1


下一篇:利用GitHub Pages和Hexo搭建个人博客