Python总结笔记(九)Pandas
pandas数据结构:Series和DataFrame
Series
Series是基础数据结构(一维数组),索引可以像字典一样指定key。字典值乱序,Series有序,可以使用非数字下标索引。
import pandas as pd#导入库
from pandas import DataFrame, Series#引用对象
- 构建Series、初始化
- 初始化Series,不给索引:索引自动从0开始,依次递增。
obj = Series([4, 7, -5, 3])#索引自动从0开始,依次递增。
-
在初始化同时,给索引
obj = Series([4, 7, -5, 3], index=[‘d’, ‘b’, ‘a’, ‘c’])#自己设定索引,使用非数字下标索引。 -
先初始化Series,再给索引
obj = Series([4, 7, -5, 3])
obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan']#若数量不匹配,会报错
字典初始化Series对象,是有序的,但是无法通过字典构造指定key的顺序。
sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000,'California':1}
obj3 = Series(sdata) # 使用字典初始化Series,但是顺序没有保证。
#解决办法:
states = ['California', 'Ohio', 'Oregon', 'Texas', 'Utah', 'New Jersy']
obj4 = Series(sdata, index=states) # 字典和索引数组结合保证顺序,初始化Series,同时指定索引数组,长度由索引数组决定。
obj.index#查看索引
obj.values#查看值
obj.name = ‘population’ # 给Series起名
obj.index.name = ‘state’ # 给Series的index起名
- Series读取(访问)、操作
读取(访问)
根据数字下标索引:obj[1])
根据非数字下标索引:obj[‘b’]
过滤:obj[obj > 0]
判断key(index)是否存在:‘b’ in obj
查看Series的支持方法:dir(obj)
np.exp(obj)或者obj * 2:作用在每个元素上
检测缺失值,返回Series数组。pd.isnull(obj) :缺失返回True、不缺失返回Flase。obj.isnull():缺失返回True,不缺失返回True。
obj3 + obj4:对应索引位置相加,对不上的设置为None
obj.reindex([‘a’, ‘b’, ‘c’, ‘d’, ‘e’]) # 重新指定索引顺序
obj.reindex([‘a’, ‘b’, ‘c’, ‘d’, ‘e’], fill_value=obj.mean()) #重新指定索引顺序,并且定填充值。
obj = Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c'])
obj2 = obj.reindex(['a', 'b', 'c', 'd', 'e']) # 重新指定索引顺序
print(obj2)
obj.reindex(['a', 'b', 'c', 'd', 'e'], fill_value=obj.mean()) #指定填充值
obj3.reindex(range(6), method=‘ffill’) # 指定填充方式为ffill,对于找不到的值用前一个值填充。
obj3 = Series(['blue', 'purple', 'yellow'], index=[0, 2, 4])
obj3.reindex(range(6), method='ffill') # 指定填充方式为ffill,对于找不到的值用前一个值填充。
排序
obj.sort_values() # 根据值排序
obj.sort_index()#根据索引排序
#根据索引排序(不用给定的obj.sort_index()函数)
index = ['d', 'c', 'a', 'b']
obj = Series([4, 7, -3, 2], index=index)
index = sorted(index)
obj = obj.reindex(index)
obj
切片
- 普通数值下标切片:
index = ['d', 'c', 'a', 'b', 'f', 'g']
obj = Series([4, 7, -3, 2, 9, 3], index=index)
x = obj[1:5] #普通数值索引: 左闭右开区间,并且x没有复制生成一个新的Series。
x[2] = 10#切片引用,修改了原来的值
obj
x
注意:对Series切片是引用类型,与数组不同(数组:不引用,修改不了值)。
x1=[1,2,3,4,5,6]
x2=x1[1:4]
x2[0]=100#数组修改值,未改变原来的,不是引用。
print(x1)
print(x2)
- 非数值切片:obj[‘c’:‘f’:1或者-1] #起始位置,结束位置,步长方向(若为负数代表反方向)
#切片-索引:
print(obj['c':'f'])#起始位置,结束位置,步长方向
print(obj['b':'d':-1]) # 闭区间-1代表反方向
DataFrame
本质上是一个二维数组,用index定位行,用columns定位列。
# col_1 col_2 ... col_n
# index_1 x11 x12 x1n
# index_2 x21 x22 x2n
# ...
# index_m xm1 xm2 xmn
#
# 房价 人口 GDP
# 上海 ...
# 北京
# 天津
- 初始化
创建列无序:
data = {'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],
'year': [2000, 2001, 2002, 2001, 2002],
'pop': [1.5, 1.7, 3.6, 2.4, 2.9]} # key代表列的名字,对应的数组就是这个列的值。(行采用默认的数字索引。)
#使用字典,导致列无序
frame = DataFrame(data)
frame
创建列无序:
frame = DataFrame({‘b’: [4, 7, -3, 2], ‘a’: [0, 1, 0, 1]})
指定列的顺序:DataFrame(data, columns=[‘year’, ‘state’, ‘pop’])
创建列有序:
frame2 = DataFrame(data,
columns=['year', 'state', 'pop', 'debt'], # 匹配不到的行和列设置为None
index=['one', 'two', 'three', 'four', 'five']) # 使用index指定列
将列变成索引:
frame = DataFrame({'year': [2000, 2001, 2002, 2003, 2004],
'sales': [1500, 3700, 2400, 2900, 4900]})
frame
frame.set_index('year') # 将列变成索引
- 访问
快速访问列:.+属性名 print(frame2.year) #.+属性名 快速访问列,不管是一行还是一列,返回的是一个Series。
索引访问:print(frame2[‘pop’]) #索引访问,和普通二维数组非常不一样!!!
切片访问:数字索引,iloc用数字索引访问行和列(左闭右开区间)
print(frame2.iloc[1,]) # 访问第1行
print(frame2.iloc[:,2]) # 访问第2列pop
print(frame2.iloc[1:3, 0:3]) #第1/2行,第0/1/2列切片
切片访问:名字索引,指定行范围或者某一列。loc用名字索引访问行和列(闭区间)
print(frame2.loc['one',])
print(frame2.loc['one':'three',])
print(frame2.loc[:,'state'])
print(frame2.loc['two':'four','year':'debt'])
花式索引:使用iloc或loc选择指定的行列组合
frame2.iloc[[0, 1, 3], [0, 2]]
frame2.loc[['one', 'three', 'four'], ['state', 'pop']]
- 赋值
对某一列赋值,作用在所有元素上 frame2[‘debt’] = 100
赋值数组,长度必须一致 frame2[‘debt’] = np.arange(5)
据索引名字匹配行,匹配不到的索引自动扔掉 frame2[‘debt’] = Series([-1.2, -1.5, -1.7, 2], index=[‘two’, ‘four’, ‘five’, ‘six’])
增加一列进行赋值
frame2[‘eastern’] = (frame2.state == ‘Ohio’)
frame2[‘big’] = (frame2[‘pop’] > 2.5)
注意: 数组a[row][col];但是在df中 a[row,col],a[col]表示单独一列。
重新定义索引:frame2 = frame.reindex([‘a’, ‘b’, ‘c’, ‘d’]) # 数量不用匹配,没有的自动填充NaN。
frame2 = frame.reindex(['a', 'b', 'c', 'd']) # 数量不用匹配,没有的自动填充NaN。
states = ['Texas', 'Utah', 'California']
frame3 = frame2.reindex(columns=states) # 重新指定行/列索引顺序
根据index删除值:默认axis=0按行
data = DataFrame(np.arange(16).reshape((4, 4)),
index=['Ohio', 'Colorado', 'Utah', 'New York'],
columns=['one', 'two', 'three', 'four'])
print(data)
print(data.drop(['Colorado', 'Ohio']))
print(data.drop('two', axis=1))
print(data.drop(['two', 'four'], axis=1))
数据过滤-按列过滤
data[data.three < 10] # three列上值大于等于10的行扔掉,小于的保留。
data.loc[data.three < 5, ]
赋值: data[data > 10] = 0
注意:定位行和列[],调用方法:()
- DataFrame和Series的计算
加法:data + 100
每一行减去其中一行:
frame = DataFrame(np.arange(12.).reshape((4, 3)),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
s = frame.iloc[0]#取一行
print(frame)
print(s)
print(frame - s) # 每一行减去对应的s,本质上每一行在对应的索引位置上相减。
选取几列加上对应数值:
s2 = Series(range(3), index=['b', 'e', 'f'])
print(s2)
print(frame + s2)
每列加减操作
# 行上操作的特殊性
s3 = frame['d']#找到一列
print(s3)
#每个列不可以直接加减。
frame.sub(s3, axis=0) # 每一列都沿着行的方向,根据index做减法。
绝对值——元素级函数
frame = DataFrame(np.random.randn(4, 3),
columns=list('bde'),
index=['Utah', 'Ohio', 'Texas', 'Oregon'])
print(frame)
np.abs(frame) # 元素级函数
自己定义函数,并应用。
f = lambda x: x.max() - x.min()#数组最大值-最小值
frame.apply(f) # 每一列应用f 默认axis=0 每一列
frame.apply(f, axis=1)# 每一行
def f(x):
return Series([x.min(), x.max()], index=['min', 'max'])#返回Series
frame.apply(f, axis=1)#对某一列
format = lambda x: '%.2f' % x
frame.applymap(format)#对每个元素进行操作
frame['e'].map(format)
- 排序
按行索引排序
# 排序
frame = DataFrame(np.arange(8).reshape((2, 4)),
index=['three', 'one'],
columns=['d', 'a', 'b', 'c'])
frame.sort_index() # 按行索引排序
按列名降序排序 frame.sort_index(axis=1, ascending=False)
按某列值排序 frame.sort_values(by=‘b’, ascending=False)
列a相等时用b排序frame.sort_values(by=[‘a’, ‘b’]) # 参考sql的order by, a相等时用b排序
根据某行索引,调整排序顺序 frame.sort_values(by=[2], axis=1) # 根据行数字索引为2,调整排序顺序
rank函数(与出现位置有关的排序)
求每列sum print(df.sum()) # 沿着行的方向对每一列求sum
求每行sum print(df.sum(axis=1))# 沿着列的方向
累加 df.cumsum() # 累加
每一列的统计信息 df.describe() # 每一列的统计信息
相关系数和协方差,使用tushare
- 缺失值处理
有NA的行删除 data.dropna() #有NA的行删除
data = DataFrame([[1., 6.5, 3.],
[1., 7, NA],
[NA, NA, NA],
[NA, 6.5, 3.]])
data
cleaned = data.dropna() # 有NA的行删除
cleaned
只有某一行全部是NA才删除 data.dropna(how=‘all’) #只有某一行全部是NA才删除。
至少有3个值不为NA的列被保留,其它删除 data.dropna(thresh=3, axis=1) #至少有3个值不为NA的列被保留,其它删除
- 数据合并
# outer: 左右,左-,-右
# inner:左右
# left: 左右,左-
# right: 左右,-右
默认根据名字相同的列作合并
df1 = DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'],
'data1': range(7)})
df2 = DataFrame({'key': ['a', 'b', 'd'],
'data2': range(3)})
print(df1)
print(df2)
pd.merge(df1, df2) # 默认根据名字相同的列作合并,等价pd.merge(df1, df2, on='key')
pd.merge(df1, df2, on='key')
分别指定用于合并的参考列
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') # 分别指定用于合并的参考列
指定连接方式 pd.merge(df1, df2, how=‘outer’) # 指定连接方式
多个列的合并
left = DataFrame({'key1': ['foo', 'foo', 'bar'],
'key2': ['one', 'two', 'one'],
'lval': [1, 2, 3]})
right = DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'],
'key2': ['one', 'one', 'one', 'two'],
'rval': [4, 5, 6, 7]})
pd.merge(left, right, on=['key1', 'key2'], how='outer') # 基于多个列的合并
重名列可以指定合并后的后缀 pd.merge(left, right, on=‘key1’, suffixes=(’_left’, ‘_right’)) # 重名列可以指定合并后的后缀
使用right的索引参与合并
left1 = DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'],
'value': range(6)})
right1 = DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
print(left1)
print(right1)
pd.merge(left1, right1, left_on='key', right_index=True) # 使用right的索引参与合并
join默认使用索引合并
left2 = DataFrame([[1., 2.], [3., 4.], [5., 6.]],
index=['a', 'c', 'e'],
columns=['Ohio', 'Nevada'])
right2 = DataFrame([[7., 8.], [9., 10.], [11., 12.], [13, 14]],
index=['b', 'c', 'd', 'e'],
columns=['Missouri', 'Alabama'])
left2.join(right2, how='outer') # join默认使用索引合并
一次合并多个DataFrame,默认使用全连接
another = DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]],
index=['a', 'c', 'e', 'f'],
columns=['New York', 'Oregon'])
left2.join([right2, another]) # 一次合并多个DataFrame,默认使用全连接。
连接
s1 = Series([0, 1], index=['a', 'b'])
s2 = Series([2, 3, 4], index=['c', 'd', 'e'])
s3 = Series([5, 6], index=['f', 'g'])
pd.concat([s1, s2, s3]) # 默认沿着行的方向连接——串起来
pd.concat([s1, s2, s3], axis=1) # 在列方向上连接,行索引没有识别到自动为nan
条件搜索
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'])
b[-1] = np.nan
np.where(pd.isnull(a), b, a) # 条件搜索, 根据where筛选,如果a对应位置的元素为None就选b,否则保留a的值
填补
df1 = DataFrame({'a': [1., np.nan, 5., np.nan],
'b': [np.nan, 2., np.nan, 6.],
'c': range(2, 18, 4)})
df2 = DataFrame({'a': [5., 4., np.nan, 3., 7.],
'b': [np.nan, 3., 4., 6., 8.]})
print(df1)
print(df2)
df1.combine_first(df2)#df1对应为空,则选取df2对应项填补
- 其他需要的知识点
pivot和melt
值替换
数据切割
排列组合和随机采样–数据d5、做交叉验证asan
Pandas画图
线型图
# 线型图
s = Series(np.random.randn(1000).cumsum(), index=np.arange(0, 100, 0.1))
s.plot()
多条线型图
df = DataFrame(np.random.randn(100, 4).cumsum(0),
columns=['A', 'B','C', 'D'],
index=np.arange(0, 100, 1))
df.plot() # 每一列对应一条曲线
柱状图
# 柱状图 - Series
data = Series(np.random.rand(10), index=list('abcdefghij'))
fig, axes = plt.subplots(2, 1)
data.plot(kind='bar', ax=axes[0])
data.plot(kind='barh', ax=axes[1])
多个柱状图
# 柱状图(并列) - Pandas
df = DataFrame(np.random.rand(6, 4),
columns=['A', 'B', 'C', 'D'],
index=['one', 'two','three', 'four', 'five', 'six'])
df.plot(kind='bar')