之前看的pandas的教材和课程里,内容参差不齐,实际使用很少的方法的内容有点多,导致很乱而且记不住那么多,这个帖子尽量用最少的文字,最精炼的语言来总结比较实用的方法,内容主要来源于《利用python进行数据分析》。
1.创建Series
直接给列表,加index。
obj = pd.Series([1,2,3,4,5],index=['a','b','c','d','e'])
也可以用字典
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
obj3 = pd.Series(sdata)
2.创建DataFrame
用最基础的方式,列表嵌套字典,注意把index放在字典外部,或者columns。
df= pd.DataFrame( {'first': ['kevin', 'lou', 'ian'],
'last': ['durant', 'reed', 'brown']}, index=['3', '4', '5'] )
下面用numpy的array数组构建DataFrame,如果要加每行、每列的指定索引可以指定index、columns,array数组没有指定索引。
frame = pd.DataFrame(np.arange(9).reshape(3,3),
index=['a','b','c'],columns=['h','i','j'])
3.DataFrame取行或列
非常重要:python中注意区分数字和字符,比如loc的使用,iloc的使用不在讨论中,iloc只能放数字(序号)。
DataFrame取列:用df['列名']或df.列名,用前者;
DataFrame取行:用loc[ ]或iloc[ ]。
tip:如果index和columns设置成数字例如1,2等,取行和取列应该为df[数字]和loc[数字],注意没有引号,如果设置成"0"、"1"(字符)的话,那就要在df[数字]中加上引号。
然后是loc和iloc的一些嵌套使用,类似这样:
data.loc['Colorado', ['two', 'three']]
data.iloc[2, [3, 0, 1]]
值得一提的是(很重要) :相对于iloc,loc的取值不像传统的python列表的选取那样,使用“:”的时候会忽略掉“:”后的那个元素,而是会取到那个值,而iloc依然是和python列表的特性一样。
a = [0,1,2,3,4,5]
a[:5] #返回[0, 1, 2, 3, 4]
ser = pd.Series(np.arange(3.))
In [144]: ser
Out[144]:
0 0.0
1 1.0
2 2.0
dtype: float64
In [147]: ser[:1]
Out[147]:
0 0.0
dtype: float64
In [148]: ser.loc[:1]
Out[148]:
0 0.0
1 1.0
dtype: float64
In [149]: ser.iloc[:1]
Out[149]:
0 0.0
dtype: float64
4.使用方法3对DataFrame进行取列或加列后操作
DataFrame和Series是带有索引的,如果想修改或增加它们的数据,索引应该要对上。(如果增加的数据是numpy的array或者其他没有索引的数据,那么数据个数能对的上就行。)
# numpy的array和单纯一个数字是没有索引的,可以直接加上去。
frame2['debt'] = np.arange(6.)
frame2['debt'] = 16.5
# frame2.state == 'Ohio'得到是一个与frame2相同索引的布尔值Series,所以能够顺利加上列。
frame2['eastern'] = frame2.state == 'Ohio'
#再比如,这个Val(Series)的索引相对于frame2的索引不完全,只有三个索引对应的3个值,索引最后结果只有3个数据匹配上增加,其他的用NaN填充。
In [58]: val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
In [59]: frame2['debt'] = val
In [60]: frame2
Out[60]:
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
这就会延申到算术运算和数据对齐部分。
5. 数据(索引)对齐后进行算术运算
数据对齐的规则在上一条已经大致说清楚了。这里的算术运算也是类似的,要求数据(索引)对齐。
算术运算的方法:可以用符号"+-*/",也可以用方法add、sub、mul、div。
Seires的算术运算比较简单,毕竟只有一维索引,要求索引对齐;DataFrame需要二维索引都对齐。不对齐的话和上面一样会出现NaN的数据。为了避免这种NaN,可以用方法“fill_value”填充值自动填充。
df1.add(df2, fill_value=0)
然后是DataFrame与Series之间的运算,依然要求数据对齐,重要的是横向还是纵向算术运算。
先用numpy的array来举个例子。arr是个3*4的array,用arr[0]提取第一行(1*4的array),然后用arr减去arr[0],是把arr的每一行都减去arr[1]这个array。
In [175]: arr = np.arange(12.).reshape((3, 4))
In [176]: arr
Out[176]:
array([[ 0., 1., 2., 3.],
[ 4., 5., 6., 7.],
[ 8., 9., 10., 11.]])
In [177]: arr[0]
Out[177]: array([ 0., 1., 2., 3.])
In [178]: arr - arr[0]
Out[178]:
array([[ 0., 0., 0., 0.],
[ 4., 4., 4., 4.],
[ 8., 8., 8., 8.]])
进而引申到DataFrame与Series的运算(前提是数据对齐),也是默认对DataFrame的每行分别减去Series。
In [179]: frame = pd.DataFrame(np.arange(12.).reshape((4, 3)),
.....: columns=list('bde'),
.....: index=['Utah', 'Ohio', 'Texas', 'Oregon'])
In [180]: series = frame.iloc[0]
In [181]: frame
Out[181]:
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
In [182]: series
Out[182]:
b 0.0
d 1.0
e 2.0
Name: Utah, dtype: float64
In [183]: frame - series
Out[183]:
b d e
Utah 0.0 0.0 0.0
Ohio 3.0 3.0 3.0
Texas 6.0 6.0 6.0
Oregon 9.0 9.0 9.0
如果DataFrame与Series的运算,要求对DataFrame的每列与Series进行算术运算,要结合axis的使用。###(这个地方的axis不用默认为1或‘columns’,可以改成0或‘index’在每列层次上进行运算)###这里发现axis默认竟然不是0?于是gpt了一下发现,关于 axis
默认值 的问题,答案是:具体情况具体分析,因为 默认的行为取决于参与运算的对象类型和索引结构。
比如这里DataFrame与Series的运算的例子。
默认行为依赖于 Series
的索引:
- 如果
Series
的索引与 DataFrame 的行索引对齐,则默认axis=0
。 - 如果
Series
的索引与 DataFrame 的列索引对齐,则默认axis=1
。
In [186]: series3 = frame['d']
In [187]: frame
Out[187]:
b d e
Utah 0.0 1.0 2.0
Ohio 3.0 4.0 5.0
Texas 6.0 7.0 8.0
Oregon 9.0 10.0 11.0
In [188]: series3
Out[188]:
Utah 1.0
Ohio 4.0
Texas 7.0
Oregon 10.0
Name: d, dtype: float64
In [189]: frame.sub(series3, axis='index')
Out[189]:
b d e
Utah -1.0 0.0 1.0
Ohio -1.0 0.0 1.0
Texas -1.0 0.0 1.0
Oregon -1.0 0.0 1.0
### 要特别注意加减乘除和sum()/average()等这些函数关于axis的使用 ###
6. “重新提取”和修改索引
Series、DataFrame(配合参数axis和0或1)可以用reindex,“重新提取”列名或行名,如果不加参数默认提取index(Series只有index),下面obj没有索引“e”对应的值,所以返回NaN。
In [91]: obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
In [93]: obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e'])
In [94]: obj2
Out[94]:
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
下面df使用了axis=1,就是重新提取列名了(columns)
In [94]: df= pd.DataFrame(
{'first': ['kevin', 'lou', 'ian'], 'last': ['durant', 'reed', 'brown']},
index=[3,4,5])
Out[94]: df.reindex(['first','third'],axis=1)
first third
3 kevin NaN
4 lou NaN
5 ian NaN
修改索引就是直接对索引进行修改。 用df.index、df.columns来修改。
7.丢弃指定轴上的项
涉及到del、drop的使用,主要是drop。
对于Series,直接drop掉想要丢弃的索引及涉及的数据们。
In [105]: obj = pd.Series(np.arange(5.), index=['a', 'b', 'c', 'd', 'e'])
In [107]: new_obj = obj.drop(['d', 'c'])
对于DataFrame,当然也可以用drop方法,但是要注意依然默认axis=0(index),即删除行。
In [110]: data = pd.DataFrame(np.arange(16).reshape((4, 4)),
.....: index=['Ohio', 'Colorado', 'Utah', 'New York'],
.....: columns=['one', 'two', 'three', 'four'])
In [112]: data.drop(['Colorado', 'Ohio'])
Out[112]:
one two three four
Utah 8 9 10 11
New York 12 13 14 15
要删除列,让axis=1(columns)。
In [114]: data.drop(['two', 'four'], axis='columns')
Out[114]:
one three
Ohio 0 2
Colorado 4 6
Utah 8 10
New York 12 14
顺带提一下del在DataFrame的运用,del用于“彻底”删除DataFrame的某列(不能删除行),相比于del的删除,drop的删除像是临时性的,临时返回一个结果对象,不会改变DataFrame本身,通常把临时修改的结果赋给某个新变量,如果想实现“彻底”删除某一行/列,可结合inplace=True选项。(很多方法在这方面和drop都是类似的,结合inplace=True实现“彻底”执行,可以就地修改对象,不会返回新的对象,这是书上原话)
del frame2['eastern']
In [115]: obj.drop('c', inplace=True)
In [116]: obj
Out[116]:
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
8.排序
排序涉及到两个方法,sort_values(值)方法和sort_index(索引)方法。
对于Series,直接在对象后面使用方法就行。
obj.sort_index()
obj.sort_values()
对于DataFrame,先讨论sort_index。需要注意一些参数。首先依然是axis,不设置axis默认为0(index),也可以设置axis=1(columns),对列索引排序。
In [203]: frame = pd.DataFrame(np.arange(8).reshape((2, 4)),
.....: index=['three', 'one'],
.....: columns=['d', 'a', 'b', 'c'])
In [204]: frame.sort_index()
Out[204]:
d a b c
one 4 5 6 7
three 0 1 2 3
In [205]: frame.sort_index(axis=1)
Out[205]:
a b c d
three 1 2 3 0
one 5 6 7 4
数据默认是按升序排序的,但也可以降序排序,设置参数ascending=False。
In [206]: frame.sort_index(axis=1, ascending=False)
Out[206]:
d c b a
three 0 3 2 1
one 4 7 6 5
下面是sort_values的讨论。首先要明确在排序时,任何缺失值默认都会被放到Series的末尾。
刚才讲的axis和ascending=False在sort_values依旧适用。然后是一些额外的补充by参数,需要选择sort_values(by=‘列名’)或者sort_values(by='行名',axis=1),by也可以放行/列名列表,按优先级进行排序。
frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
In [212]: frame
Out[212]:
a b
0 0 4
1 1 7
2 0 -3
3 1 2
In [214]: frame.sort_values(by=['a', 'b'])
Out[214]:
a b
2 0 -3
0 0 4
3 1 2
1 1 7
In [215]: frame.sort_values(by=2,axis=1)
Out[215]:
b a
0 4 0
1 7 1
2 -3 0
3 2 1
9.汇总和计算描述统计
一些常用count、sum、mean、cumsum等描述汇总统计等,不再赘述。
DataFrame的corr和cov方法将以DataFrame的形式分别返回完整的相关系数或协方差矩阵:
# returns有四列数据AAPL、GOOG、IBM、MSFT
In [247]: returns.corr()
Out[247]:
AAPL GOOG IBM MSFT
AAPL 1.000000 0.407919 0.386817 0.389695
GOOG 0.407919 1.000000 0.405099 0.465919
IBM 0.386817 0.405099 1.000000 0.499764
MSFT 0.389695 0.465919 0.499764 1.000000
In [248]: returns.cov()
Out[248]:
AAPL GOOG IBM MSFT
AAPL 0.000277 0.000107 0.000078 0.000095
GOOG 0.000107 0.000251 0.000078 0.000108
IBM 0.000078 0.000078 0.000146 0.000089
MSFT 0.000095 0.000108 0.000089 0.000215
10.唯一值、值计数以及成员资格
下面更多是对Series对象使用的方法。
可以用unique方法返回唯一值:
In [251]: obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'b', 'b', 'c', 'c'])
In [252]: uniques = obj.unique()
In [253]: uniques
Out[253]: array(['c', 'a', 'd', 'b'], dtype=object)
value_count()方法对Series里的值计数并倒序返回计数值排序。(注意单词拼写,以及这里value没有复数,区分之前的sort_values)
In [254]: obj.value_counts()
Out[254]:
c 3
a 3
b 2
d 1
dtype: int64
然后是一个isin方法,可以判断Series里面的元素是否在isin的列表里,返回一个布尔值Series。可以把这个布尔值Series结合之前的汇总描述统计方法配合使用。
In [256]: obj
Out[256]:
0 c
1 a
2 d
3 a
4 a
5 b
dtype: object
In [257]: mask = obj.isin(['b', 'c'])
In [258]: mask
Out[258]:
0 True
1 False
2 False
3 False
4 False
5 True
dtype: bool
In [259]: obj[mask]
Out[259]:
0 c
5 b
dtype: object
最后带一句:关于axis的选择对于DataFrame确实比较复杂,且涉及大部分方法,可以不用死记硬背,使用方法时,可以进行一些试错尝试(使用副本等其他方法避免对原数据操作,以免造成不可逆转的操作),来选择正确的axis参数。