《利用Python进行数据分析·第2版》第五章 pandas入门——基础对象、操作、规则
-
视图=引用 副本=浅拷贝/深拷贝
-
浅拷贝:拷贝对象的副本,但内部子对象还是引用(如果list内还有小list,小list改变会使原对象变化 .copy/python切片/ * 运算
深拷贝:父对象子对象副本全都拷贝,没有引用 .deepcopy
第五章:pandas入门
pandas: Series:类数组数据结构 DataFrame:类数据库表数据结构
5.1 pandas的数据结构介绍
1)Series:类似于一维数组的对象 标签(即索引)+数据(一列
In [11]: obj = pd.Series([4, 7, -5, 3])
In [12]: obj
Out[12]:
0 4
1 7
2 -5
3 3
dtype: int64
- 左边是行索引,右边数据值
行索引默认:0—(N-1) :可以指定行索引
Series:obj.value obj.index obj:series的实例
In [13]: obj.values
Out[13]: array([ 4, 7, -5, 3])
In [14]: obj.index # like range(4)
Out[14]: RangeIndex(start=0, stop=4, step=1)
- 设置行索引:1.初始化设置 2.后续赋值设置
In [15]: obj2 = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c'])
In [16]: obj2
Out[16]:
d 4
b 7
a -5
c 3
dtype: int64
In [17]: obj2.index #可以根据索引选取值
Out[17]: Index(['d', 'b', 'a', 'c'], dtype='object')
In [18]: obj2['a']
Out[18]: -5
In [20]: obj2[['c', 'a', 'd']] #根据索引顺序显示,Series显示是按行显示(不同于numpy数组
Out[20]:
c 3
a -5
d 6
dtype: int64
- 使用numpy函数或者运算后—>保留索引位置
Series:定长有序字典—>索引到数据值的映射 / 可以代替字典参数进行的函数:
In [24]: 'b' in obj2
Out[24]: True
- 可以通过字典创建Series: —>还可以传入排好序或者不同的字典键来改变顺序
In [26]: sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000}
In [27]: obj3 = pd.Series(sdata)
In [28]: obj3
Out[28]:
Ohio 35000
Oregon 16000
Texas 71000
Utah 5000
dtype: int64
In [29]: states = ['California', 'Ohio', 'Oregon', 'Texas']
In [30]: obj4 = pd.Series(sdata, index=states) #最后值是按索引决定
In [31]: obj4
Out[31]:
California NaN #缺失值NaN
Ohio 35000.0
Oregon 16000.0
Texas 71000.0
dtype: float64
- pd.isnull() / pd.notnull():检测缺失数据 = (应用在series时) obj.isnull()
In [32]: pd.isnull(obj4)
Out[32]:
California True
Ohio False
Oregon False
Texas False
dtype: bool
In [33]: pd.notnull(obj4)
Out[33]:
California False
Ohio True
Oregon True
Texas True
dtype: bool
Seies重要功能:根据运算的索引标签自动对齐数据再做运算(相当于做了一步自然连接,并且是 inner join操作 其他的join=数据对齐
obj.name:数据列的列名 obj.index.name:索引行的行名 (可以看作是Series列索引的列索引
2)DataFrame
DataFrame:表格型数据结构 行索引 / 列索引 = 多个Series组成的字典(字典键:列索引
frame.index :行索引 frame.column:列索引
二维结构存储表示更高维度 层次化索引的表格型结构 列=维度 行=数据点
最常用建DataFrame:①:传入等长的列表 or numpy数组字典
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], #每个list / 数组是一列
'year': [2000, 2001, 2002, 2001, 2002, 2003],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2]}frame = pd.DataFrame(data)
行索引设置:=Series设置行索引 //frame:DataFrame的实例frame.head():选取前五行显示
In [46]: frame.head()
Out[46]:
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
In [47]: pd.DataFrame(data, columns=['year', 'state', 'pop']) #指定列序列,即给列名的显示顺序
Out[47]:
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
- DataFrame的每列=Series:frame[column]—>赋值若没有该column时则自动添加column列(添加列只能用frame[column]而不能用frame.column)
In [51]: frame2['state'] #可用于查询也可用于添加
Out[51]:
one Ohio
two Ohio
three Ohio
four Nevada
five Nevada
six Nevada
Name: state, dtype: object
In [52]: frame2.year #可用于查询但不可用于添加
Out[52]:
one 2000
two 2001
three 2002
four 2001
five 2002
six 2003
Name: year, dtype: int64
DataFrame可以用这两种方式进行列索引:frame[colum]适用于任何列名,frame.column只有当列名是合理的python变量名时才可使用(全是视图
DataFrame使用loc属性去获取位置数据:(.loc跟直接列索引貌似好像是引用跟拷贝的关系???)
-
.iloc与loc的不同:
iloc行索引始终是行序数,列索引可以是列名,也可以是列序数;而loc列行索引只能是列行名
iloc只能用于查询;而loc可以用于查询也可以用于赋值,添加新列(loc速度更快
In [53]: frame2.loc['three'] #df.loc[[1, 5], ['b', 'c']] , df.loc[1:4,'b'] 取多列/多行的方式
Out[53]:
year 2002
state Ohio
pop 3.6
debt NaN
Name: three, dtype: object
- del 删除列
In [63]: del frame2['eastern']
frame.T转置
最常用建DataFrame:②:嵌套字典 or ③Series字典
In [65]: pop = {'Nevada': {2001: 2.4, 2002: 2.9},
....: 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
In [66]: frame3 = pd.DataFrame(pop) #可以用内层键作为行索引,也可以指定index作为行索引
In [67]: frame3
Out[67]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
In [70]: pdata = {'Ohio': frame3['Ohio'][:-1],
....: 'Nevada': frame3['Nevada'][:2]}
In [71]: pd.DataFrame(pdata)
Out[71]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
- frame.index.name frame.column.name 索引行的行名 索引列的列名(索引的索引
In [72]: frame3.index.name = 'year'; frame3.columns.name = 'state'
In [73]: frame3
Out[73]:
state Nevada Ohio
year
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
frame.value // frame[column].value
dtype=object:(兼容所有列的数据结构类型:python类型)
3)索引对象
- index行索引 columns列索引 —>统称Index对象
索引对象在dataframe/series新建之后是不可变的—>使索引对象在多个数据结构之间安全共享
index类似set(固定大小的集合 两者不相同
In [85]: frame3
Out[85]:
state Nevada Ohio
year
2000 NaN 1.52001 2.4 1.72002 2.9 3.6
In [86]: frame3.columns
Out[86]: Index(['Nevada', 'Ohio'], dtype='object', name='state')
In [87]: 'Ohio' in frame3.columns
Out[87]: True
In [88]: 2003 in frame3.index
Out[88]: False
- 区别:pandas的index可以包含重复的label(集合唯一不可重复
In [89]: dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar'])
In [90]: dup_labels
Out[90]: Index(['foo', 'foo', 'bar', 'bar'], dtype='object')
- index常用方法:一般单独取出使用,index_tes=pd.Index() or =frame.columns/obj.index (赋值引用,所以可以单独取出
5.2 pandas数据处理基本功能
1)重新索引
-
obj.reindex([重索引List]):重索引是根据原索引进行重新的序数排列构造的新对象,若有原索引不存在的值,则引入NaN缺失值
reindex参数:Dataframe.reindex(index=None,columns=None,**kwargs)
In [91]: obj = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
In [92]: obj
Out[92]:
d 4.5
b 7.2
a -5.3
c 3.6
dtype: float64
In [93]: obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e']) #NaN值可以填充也可以插值等
In [94]: obj2
Out[94]:
a -5.3
b 7.2
c 3.6
d 4.5
e NaN
dtype: float64
- 对于时间序列有序数据,reindex可能需要进行插值处理:替补缺值项NaN —>利用method参数项可以实现插值(如ffill:前向值填充
( method : {None, ‘backfill’/’bfill’, ‘pad’/’ffill’, ‘nearest’}, optional。 method参数可选项
In [95]: obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
In [96]: obj3
Out[96]:
0 blue
2 purple
4 yellow
dtype: object
In [97]: obj3.reindex(range(6), method='ffill') #填补原索引中未有的NaN项
Out[97]:
0 blue
1 blue
2 purple
3 purple
4 yellow
5 yellow
dtype: object
2)丢弃指定轴上的项
frame.del():删除指定列
obj.drop():删除指定轴上项(一行/一列 参数:axis / inpalce
In [107]: new_obj = obj.drop('c') #默认指定行:axis=0 / 'index'
In [108]: new_obj
Out[108]:
a 0.0
b 1.0
d 3.0
e 4.0
dtype: float64
In [113]: data.drop('two', axis=1) #axis=1 删除指定列
Out[113]:
one three four
Ohio 0 2 3
Colorado 4 6 7
Utah 8 10 11
New York 12 14 15
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
3)索引、选取和过滤
- obj[]:索引/切片—>默认行索引 (与普通python切片运算不同:索引值包括末端
In [121]: obj[2:4] #各种切片运算
Out[121]:
c 2.0
d 3.0
dtype: float64
In [122]: obj[['b', 'a', 'd']]
Out[122]:
b 1.0
a 0.0
d 3.0
dtype: float64
In [123]: obj[[1, 3]]
Out[123]:
b 1.0
d 3.0
dtype: float64
In [124]: obj[obj < 2] #布尔型数组选取索引
Out[124]:
a 0.0
b 1.0
dtype: float64
In [126]: obj['b':'c'] = 5 #利用切片进行赋值(视图
4)利用.loc和.iloc进行选取
frame.loc([],[]):左列右行 loc(列) 一行;loc(:,行) 一列 ( .loc索引包括最后索引 .iloc索引不包括最后索引
DataFrame的索引选项
5)整数索引
ser = pd.Series(np.arange(3.))
ser
ser[-1] #整数索引最后一行整数索引(内置索引)可能会与series生成的整数索引产生矛盾:对于非整数索引则不会产生索引
In [144]: ser
Out[144]:
1 0.0
2 1.0
3 2.0
dtype: float64
-
ser[1]=>是指0.0还是指1.0,产生矛盾bug
所以一般为了准确使用索引统一用.loc(标签)和.iloc(整数)
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
6)算术运算和数据对齐
- 不同索引对象算术运算=数据库自然连接(数据对齐)+算术运算—>不重叠索引引入NaN值,缺失值会在算术运算过程中传播
7)在算术方法中填充值
- 如果不希望引入NaN值/传播缺失值—>则使用算术方法+fill_value填充值 r+算术方法:表示反转参数的算术运算
In [171]: df1.add(df2, fill_value=0)
Out[171]:
a b c d e
0 0.0 2.0 4.0 6.0 4.0
1 9.0 5.0 13.0 15.0 9.0
2 18.0 20.0 22.0 24.0 14.0
3 15.0 16.0 17.0 18.0 19.0
In [172]: 1 / df1
Out[172]:
a b c d
0 inf 1.000000 0.500000 0.333333
1 0.250000 0.200000 0.166667 0.142857
2 0.125000 0.111111 0.100000 0.090909
In [173]: df1.rdiv(1) #df1.div(1)=df1/1 df1.rdiv(1)=1/df1 反转了参数两者
Out[173]:
a b c d
0 inf 1.000000 0.500000 0.333333
1 0.250000 0.200000 0.166667 0.142857
2 0.125000 0.111111 0.100000 0.090909
8)DataFrame和Series之间的运算
-
DataFrame和Series之间的算术运算(行运算):根据Series的索引匹配dataframe列,沿着行进行行广播boardcasting(series做一特殊行,与dataframe每一行都做运算
如果有两者不公共的索引,则与算术运算一样,不重叠部分用NaN值填充;同样也可以用算术方法进行值填充
列运算:必须采用算术方法(行运算可以用这个也可以直接用算术符号)
在算术方法中传参(axis='index' or axis=0)即可在列上进行列广播
9)函数应用和映射
1. numpy的ufuncs(元素级数组方法)也可以操作pandas对象
In [192]: np.abs(frame)
Out[192]:
b d e
Utah 0.204708 0.478943 0.519439
Ohio 0.555730 1.965781 1.393406
Texas 0.092908 0.281746 0.769023
Oregon 1.246435 1.007189 1.296221
2. 将函数应用到作用各列/各行形成的一维数组上:利用dataframe的apply方法
- (很多常见的数组统计方法都已被dataframe实现,如sum/mean,所以不需要用apply方法)
In [193]: f = lambda x: x.max() - x.min() #计算一个Series的最大最小值之差,每列都执行了一次,结果返回值是一个Series,列作为新对象索引
In [194]: frame.apply(f) #将f作用于frame的各列(默认各列 #f可以用def也可以用lambda函数
Out[194]: #函数必须是作用一行数据(如果是元素级python函数,则需要用applymap:意思就是作用到每个数据的函数
b 1.802165 #之所以叫applymap:是因为Series中含有一个应用元素级的map方法:frame['e'].map(f)
d 1.684034
e 2.689627
dtype: float64
In [196]: def f(x):
.....: return pd.Series([x.min(), x.max()], index=['min', 'max']) #也可以返回多个Series,用了多个算术方法
In [197]: frame.apply(f)
Out[197]:
b d e
min -0.555730 0.281746 -1.296221
max 1.246435 1.965781 1.393406
10)排序和排名
- sorting:根据字典顺序索引排序(字典
- obj.sort():默认值排序
- obj.sort_index():根据索引(根据指定轴)进行排序,返回一个已排序的新对象(series/dataframe
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
In [206]: frame.sort_index(axis=1, ascending=False) #默认升序排序;False则是降序排序
Out[206]:
d c b a
three 0 3 2 1
one 4 7 6 5
- obj.sort_value():根据值进行排序,返回一个已排序的新对象
In [209]: obj = pd.Series([4, np.nan, 7, np.nan, -3, 2])
In [210]: obj.sort_values()
Out[210]: #NaN值放到最后
4 -3.0
5 2.0
0 4.0
2 7.0
1 NaN
3 NaN
dtype: float64
In [211]: frame = pd.DataFrame({'b': [4, 7, -3, 2], 'a': [0, 1, 0, 1]})
In [213]: frame.sort_values(by='b') #通过by参数指定按照某列的值进行排序
Out[213]:
a b
2 0 -3
3 1 2
0 0 4
1 1 7
In [214]: frame.sort_values(by=['a', 'b']) #多列值排序,根据by的先后决定权重
Out[214]:
a b
2 0 -3
0 0 4
3 1 2
1 1 7
- Series & DataFrame.rank():将对象按照值大小进行排名—>1-(n-1) (默认:为各组分配一个平均排名破坏平级关系(默认dataframe按行为组,可以通过 axis='columns'参数进行按列为组)
In [215]: obj = pd.Series([7, -5, 7, 4, 2, 0, 4])
In [216]: obj.rank() #当出现相同值时,两者取平均;默认按从小到大的顺序排序
Out[216]:
0 6.5 #如原本是第5和6,则两者都取平均为6.5
1 1.0
2 6.5
3 4.5
4 3.0
5 2.0
6 4.5
dtype: float64
In [217]: obj.rank(method='first') #同时也可以设置method参数:first;表示第一次出现的数大于第二次出现的数,序数则也更大
Out[217]:
0 6.0 #于是第一次出现的7排6,第二次出现的7排5
1 1.0
2 7.0
3 4.0
4 3.0
5 2.0
6 5.0
dtype: float64
In [218]: obj.rank(ascending=False, method='max') #降序排列,从大到小
Out[218]:
0 2.0
1 7.0
2 2.0
3 4.0
4 5.0
5 6.0
6 4.0
dtype: float64
- 排名用于破坏平级关系的method
11)带有重复标签的轴索引
-
索引唯一非强制:obj.index.is_unique—>bool返回索引值是否唯一
重复索引值进行索引返回一个series;唯一索引值索引返回一个标量
5.3 汇总和计算描述统计
-
pandas对象的常用数学和统计方法:可以有缺失值(所以提前做好缺失值填补—>如 df.sum() df.mean()
dataframe返回一个series/series返回一个标量
约简型/汇总统计:常用
In [231]: df
Out[231]:
one two
a 1.40 NaN
b 7.10 -4.5
c NaN NaN
d 0.75 -1.3
In [232]: df.sum() #默认按列进行操作,返回列索引转行索引
Out[232]:
one 9.25
two -5.80
dtype: float64
In [233]: df.sum(axis=1) #设置按行进行操作 统计时无视NaN值
Out[233]:
a 1.40
b 2.60
c NaN
d -0.55
In [234]: df.mean(axis='columns', skipna=False) #skipna要求正视NaN的存在,对于NaN无法进行统计,结果返回NaN
Out[234]:
a NaN
b 1.300
c NaN
d -0.275
dtype: float64
约简型数学统计方法的参数:
间接统计方法:如最大值/最小值的索引: idxmax()/idxmin()
In [235]: df.idxmax() #值是df行最大值对应的索引
Out[235]:
one b
two d
dtype: object
- 累计型统计方法:如
In [236]: df.cumsum()
Out[236]:
one two
a 1.40 NaN
b 8.50 -4.5
c NaN NaN
d 9.25 -5.8
- 既不是约简型,也不是累计型:如describe;一次性产生多个汇总统计
In [237]: df.describe() #对于数值
Out[237]:
one two
count 3.000000 2.000000
mean 3.083333 -2.900000
std 3.493685 2.262742
min 0.750000 -4.500000
25% 1.075000 -3.700000
50% 1.400000 -2.900000
75% 4.250000 -2.100000
max 7.100000 -1.300000
In [238]: obj = pd.Series(['a', 'a', 'b', 'c'] * 4) #对于非数值
In [239]: obj.describe()
Out[239]:
count 16
unique 3
top a
freq 8
dtype: object
1)相关系数与协方差:
+相关系数/协方差:需要通过参数对计算出来
import pandas_datareader.data as web
all_data = {ticker: web.get_data_yahoo(ticker) #股票数据
for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG']}
price = pd.DataFrame({ticker: data['Adj Close'] #股票价格
for ticker, data in all_data.items()})
volume = pd.DataFrame({ticker: data['Volume'] #股票成交量
for ticker, data in all_data.items()})
In [242]: returns = price.pct_change() #计算价格的百分比变化(相关时间序列操作
In [243]: returns.tail() #显示最后五条
Out[243]:
AAPL GOOG IBM MSFT
Date
2016-10-17 -0.000680 0.001837 0.002072 -0.003483
2016-10-18 -0.000681 0.019616 -0.026168 0.007690
2016-10-19 -0.002979 0.007846 0.003583 -0.002255
2016-10-20 -0.000512 -0.005652 0.001719 -0.004867
2016-10-21 -0.003930 0.003011 -0.012474 0.042096
-
obj.corr(obj2):计算两个series中重叠的,非NaN的,按索引对齐的相关系数
obj.cov(obj2):计算两个的协方差
In [244]: returns['MSFT'].corr(returns['IBM'])
Out[244]: 0.49976361144151144
In [245]: returns['MSFT'].cov(returns['IBM'])
Out[245]: 8.8706554797035462e-05
frame.corr() / frame.cov():返回完整的相关系数/协方差矩阵 (自身的系数矩阵
frame.corrwith():计算其列/行跟另一个Series/dataframe之间的相关系数:
传入Series返回相关系数值的series(针对各列进行计算)
传入dataframe返回按列名匹配的相关系数值 (按索引对齐
In [249]: returns.corrwith(returns.IBM) #同样axis参数可以设置为1/columns使之按行运算
Out[249]:
AAPL 0.386817
GOOG 0.405099
IBM 1.000000
MSFT 0.499764obj.isin
dtype: float64
In [250]: returns.corrwith(volume) #两个不同dataframe之间的相关系数
Out[250]:
AAPL -0.075565
GOOG -0.007067
IBM -0.204849
MSFT -0.092950
dtype: float64
2)唯一值、值计数以及成员资格
obj.unique():得到series中的唯一值数组
obj.value_counts():计算各值出现次数,索引为各值,值为次数(默认降序
= pd.value_counts(obj.value,sort=False):用于任何数组或序列obj.isin([Set]):用于判断矢量化集合的成员资格,过滤Series/dataframe列中数据;返回一个等列大小的布尔列,
=pd.Index(小对象).get_indexer(大对象):判断大对象列中的元素是否包含在小对象中,返回大对象包含元素在小对象中的索引序列
In [256]: obj
Out[256]:
0 c
1 a
2 d
3 a
4 a
5 b
6 b
7 c
8 c
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
6 True
7 True
8 True
dtype: bool
In [259]: obj[mask]
Out[259]:
0 c
5 b
6 b
7 c
8 c
dtype: object
In [260]: to_match = pd.Series(['c', 'a', 'b', 'b', 'c', 'a'])
In [261]: unique_vals = pd.Series(['c', 'b', 'a'])
In [262]: pd.Index(unique_vals).get_indexer(to_match)
Out[262]: array([0, 2, 1, 1, 0, 2])
- 比如计算各列出现了多少个不同的数的柱状图:
In [263]: data = pd.DataFrame({'Qu1': [1, 3, 4, 3, 4],
.....: 'Qu2': [2, 3, 1, 2, 3],
.....: 'Qu3': [1, 5, 2, 4, 4]})
In [264]: data
Out[264]:
Qu1 Qu2 Qu3
0 1 2 1
1 3 3 5
2 4 1 2
3 3 2 4
4 4 3 4
In [265]: result = data.apply(pd.value_counts).fillna(0) #利用apply函数,NaN值填充0
In [266]: result #行索引是所有列的唯一值,后面是该值在各列出现的次数
Out[266]:
Qu1 Qu2 Qu3
1 1.0 1.0 1.0
2 0.0 2.0 1.0
3 2.0 2.0 0.0
4 2.0 0.0 2.0
5 0.0 0.0 1.0