Pandas的基本使用
一、查询
-
使用单个label值进行查询
-
import pandas df = pandas.DataFrame(Data) #得到单个值 df.loc['2018-01-03', 'bWendu'] #得到一个Series df.loc['2018-01-03', ['bWendu', 'yWendu']]
-
-
使用值列表批量查询
-
#得到Series df.loc[['2018-01-03', '2018-01-04'], 'bWendu'] #得到DataFrame df.loc[['2018-01-03', '2018-01-04'], ['bWendu', 'yWendu']]
-
-
使用数值区间进行范围查询
-
# 行index按区间 df.loc['2018-01-03':'2018-01-05', 'bWendu'] #列index按区间 df.loc['2018-01-03', 'bWendu':'fengxiang'] #行和列都按照区间查询 df.loc['2018-01-03':'2018-01-05', 'bWendu':'fengxiang']
-
-
使用条件表达式查询
df['yWendu'] < -10 #查询结果是一个Series,前面是index后面是boolean值 #查询最高温度小于30度,并且最低温度小于15度,并且是青天,天气为优的数据 df.loc[(df['bWendu'] <= 30 )& (df['yWendu']>=15) & (df['tianqi'] == '晴') &(df['aqiLevel'] == 1)]
-
调用函数查询
df.loc[lambda df: (df['bWendu'] <= 30) & (df['yWendu'] >=15),:]
二、Pandas新增数据列
-
直接赋值的方法
-
df.loc[:'bWendu'] = df['bWendu'].str.replace('C','').astype('int32') #也可以计算 df.loc[:, 'wencha'] = df['bWendu'] -df['yWendu']
-
-
df.apply方法
-
def get_wendu_type(x): if x["bWendu"]>33: return "高温" if x["yWendu"] < -10: return "低温" return "常温" df.loc[:,"wendu_type"] = df.apply(get_wendu_type,axis =1) df.loc[:,"wendu_type"].value_counts()
-
-
df.assign方法
-
#可以同时添加多个列 df.assign( yWendu_huashi = lambda x:x["yWendu"] * 9 /5+32 bWendu_huashi = lambda x:x['bWendu']*9/5+32 )
-
-
按条件选择分组分别赋值
-
按条件选择分组分别赋值
df['wencha_type'] = '' df.loc[df['bWendu'] - df['yWendu'] > 10,"wencha_type"] = "温差大" df.loc[df['bWendu'] - df['yWendu'] < 10,"wencha_type"] = "温差正常"
-
三、Pandas数据统计
-
汇总类统计
-
##查看单个Series的数据 df['bWendu'].mean() #最高温 df['bWendu'].max() #最低温 df['bWendu'].min()
-
-
唯一去重和按值技术
-
df['fengli'] .unique() #取去重 df['tianqi'].value_counts() #对数值出现个数进行统计
-
-
协方差和相关系数
-
#协方差 df.cov() #相关系数 df.corr() #查看空气质量和温度 df['api'].corr(df['bWendu']) #空气质量和温差的相关系数 df['api'].corr(df['bWendu'] -df['yWendu'])
-
五、Pandas的SettingWithCopyWarning报警
-
原因
-
df[condition]['wen_cha'] = df['bWendu'] - df['yWendu'] 相当于 df.get(condition).set(wen_cha),第一步骤的get发出了报警 核心要诀 pandas的dataframe的修改写操作,只允许在源dataframe上进行,一步到位
-
-
解决方法
-
doc.loc[codition, 'wen_cha']= df['bWendu'] - df['yWendu'] df_month3 = df[condition].copy() df_month3.head() df_month3['wen_cha'] = df['bWendu'] - df['yWendu']
-
六、Pandas数据排序
-
Series的排序
-
Series.sort_values(ascending = True ,inplace = False) 参数说明 ascending:默认为True升序排序,为False为降序排序 inplace:是否修改原始的Series
-
-
DataFrame排序
-
DataFrame.sort_values(by,ascending = True, inplace=True) 参数说明: by:字符串或者list,升序还是降序 ascending:默认为True升序排序,为False为降序排序 inplace:是否修改原始的Series df.sort_values(by=['apiLevel', 'bWendu'],ascending = [True,False])
-
七、Pandas字符串处理
-
Pandas的字符串处理
- 使用方法:先获取Series上的str属性,然后在属性上调用函数
- 只能在字符串列上使用,不能数字列上使用
- DataFrame上没有str属性和处理方法
- Series.str并不是Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似
- https://pandas.pydata.org/pandas-docs/stable/reference/series.html#string-handling
-
获取Series的str属性,使用各种字符串处理函数
-
df['bWendu'].str #字符串替换函数 df['bWendu'].str.replace("C","") #判断是不是数字 df['bWendu'].str.isnumeric() #获取长度 df['bWendu'].str.len() #获取月份 2018-3-4 df['ymd'].str.replace('-','').slice(0,6) #会报错 #不能在serice上直接调用slice方法,需要转换为str形式 df['ymd'].str.replace('-','').str.slice(0,6) #正确 #使用正则表达式处理 def get_naianyueri(x): year,month,day = x['ymd'].split('-') return f'{year}年{month}月{day}日' df['中文日期'] = df.apply(get_nianyueri,axis =1) #将年月日三个中文字符去除 df['中文日期'].str.replace('年','').str.replace('月','').str.replace('日','') #正则取出方式 df['中文日期'].str.replace('[年月日]','')
-
八、Pandas的axis参数怎么理解?
- axis =0或者’index’
- 如果是单行操作,就指的是某一行
- 如果是聚合操作,指的cross rows
- axis = 1或者’columns’
- 如果是单列操作,就指的是某一列
- 如果是聚合操作,值的是跨列cross columns
九、Pandas的索引index的用途
-
index的用途总结
- 更方便的数据查询
- 使用index可以获得性能的提升
- 自动的数据对齐功能
- 更多更强大的数据结构支持
-
使用index查询数据
-
drop ==False,让索引还保持在column df.set_index('userId',inplace = True,drop = False) df.head() #查询userid = 500的 方式一 、 df.loc[df['userId'] == 500].head(5) #方式较慢 方式二、 df.set_index('userId',inplace = True,drop = False) df.loc[500].head(5)
-
使用index会提升查询性能
- 如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1)
- 如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN)
- 如果index是完全随机的,那末每次查询都要扫描全表,查询性能为O(N)
-
十、Pandas怎么实现DataFrame的Merge
-
Pandas的Merge,相当于Sql的Join,将不同的key关联到一个表
-
merge的语法
-
pd.merge(left,right,how='inner',on=None,right_on = None,left_index = False,right_index = False,sort=True,suffixes=('_x','_y'),copy=True,indicator=False),vaildate=None) left,right :要merge的datagrame或者有name的Series how: join类型,'left','right','outer','inner' on: join 的key,left和right都需要这个key left_on: left的df或者series的key right_on: right的df或者seires的key left_index,right_index:使用index而不是普通的column做join suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是'_x','_y'
-
-
理解merge时数量的对齐关系
- one-to-one: 一对一关系,关联的key都是唯一的
- 结果条数 1* 1
- one-to-many: 一对多关系,左边唯一key,右边不唯一key
- 结果条数 1*N
- many-to-many:多对多关系,左边右边都不是唯一的
- 结果条数:M*N
- one-to-one: 一对一关系,关联的key都是唯一的
十一、Pandas实现的合并
-
一句话说明concat语法:
- 使用某种合并方式(inner/outter)
- 沿着某个轴向(axis=0/1)
- 把多个Pandas对象(DataFrame/Series)合并成一个
-
concat语法:pandas.concat(objs,axis=0,join=‘outer’,ignore_index=False)
- objs: 一个列表,可以是DataFrame或者Series,可以混合
- axis:默认是0代表按行合并,如果的呢关于1表示按列合并
- join:合并的时候索引的对齐方式,默认是outer join,也可以是innerjoin
- ignore_index:是否忽略调原来的数据索引
-
1、默认的concat,参数为axis=0,join= outer, ignore_index =False pd.concat([df1,df2]) 2、添加新的列 s1 = pd.Series(list(range(4)), name = 'F') pd.concat([df1, s1], axis =1)
-
二、使用DataFrame.append按行合并数据
-
#给1个dataframe添加另一个dataframe df1.append(df2)
-
#一行一行给DataFrame添加数据 for i in ,range(5): df =df.append({'A':i},ignore_index = True ) #高性能版本 pd.concat( [pd.DataFrame([i],columns = ['A']) for i in range(5)], ignore_index = True )
-
十二、Pandas拆分和组合Excel
-
将一个大的Excel文件拆成多个小的excel
-
#1、计算拆分后的每个excel的行数 user_names = ['xiao_shuai','xiao_wang','xiaoming'] #每个人的任务数目 split_size = total_row_count // len(user_name) if total_row_count % len(user_names) != 0: split_size += 1 #拆分成多个excel df_subs = [] for idx, user_name in enumerate(user_names): #iloc的开始索引 begin = idx*split_size end = begin+ split_size #实现df按照iloc进行拆分 df_sub = df_source.iloc[begin:end] #将每个子df存入列表 df_subs.append(idx,user_name,df_sub) #将每个dataframe存入excel for idx,user_name,df_sub in df_subs: file_name = f'{splits_dir}/crazyant_blog_articles_{idx}_{user_name}.xlsx' df_sub.to_excel(file_name, index=False)
-
-
Pandas批量拆分Excel与合并Excel
-
#遍历文件夹,得到要合并的Excel名称列表 import os excel_names = [] for excel_name in os.listdir(splits_dir): excel_names.append(excel_name) #分别读取dataframe df_list = [] for excel_name in excel_names: excel_path = f'{splits_dir}/{excle_name}' df_split = pd.read_excel(excel_path) username = excel_name.replace('crazyant_blog_articles_','') #给每个df增加用户名 df_split['user_name'] = username df_list.append(df_split) #使用pd.concat进行合并 df_merged = pd.concat(df_list) df_merged.to_excle()
-
十三、Pandas怎么实现groupby分组统计
-
分组使用湖和函数做数据统计
-
单列groupby,查询所有数据列的统计
-
df.groupby('A').sum() #多个列groupby,查询所有数据列的统计 df.groupby(['A','B']).mean() #可以让A,B不变陈索引 df.groupby(['A','B'],as_index = False).mean() 到maste#同时查看多种数据统计 df.groupby('A').agg([np.sum, np.mean, np.std]) #查看单列的结果数据统计 df.groupby('A')['C'].agg([np.sum, np.mean, np.std]) df.groupby('A').agg([np.sum, np.mean, np.std])['C'] #不同的列使用不同的函数 df.groupby('A').agg({'C':np.sum, 'D':np.mean})
-
-
遍历groupby的结果理解执行流程
-
g = df.groupby('A') #遍历单个列聚合的分组 for name,group in g: print(name) print(group) print() g.get_group('bar') #遍历多个列聚合分组 g = df.groupby(['A', 'B']) for name,group in g: print(name) print(group) print() #获取出来的值是Series for name,group in g['C']: print(name) print(group) print()
-
-
天气情况
-
#查看每个月的最高温度 data = df.groupby('month')['bWendu'].max() #查看每个月的最高温度、最低温度、平均空气质量指数 group_data = df.groupby('month').agg({'bWendu':np.max , 'yWendu':np.min, 'aqi':np.mean}) group_data.plot()
-
十四、Pandas的分层索引Multindex
-
为什么要学习分层索引MultiIndex?
- 分层索引:在一个轴向上拥有多个索引层级,可以表达更高唯独数据的形式
- 可以更方便的进行数据筛选,如果有序性能更好
- groupby等操作的结果,如果是多KEY,结果是分层索引,需要使用
- 基本不需要自己建分层索引
-
Series的分层索引MultIndex
-
ser = stocks.groupby(['公司','日期'])['收盘'].mean() ser.index #unstack把二级索引变成列 ser.unstack() #把多层索引变成df ser.reset_index() ser.loc['BIDU'] ser.loc['BIDU','2019-10-02'] ser.loc[:,'2019-10-02']
-
-
DataFrame的多层索引MultiIndex
-
stocks.set_index(['公司','日期'],inplace = True) #将'公司','日期'两个column变成index stocks.sort_index(inplace = True) #让其对索引进行排序
-
-
DataFrame有多层索引MultiIndex怎样筛选数据?
-
元组(key1, key2)代表筛选多层索引,其中key1是索引第一级,key2是第二级,比如key1 =JD ,key2 = 2019-10-02
-
列表[key1,key2]代表同一层的多个key,其中key1和key2是别列的同级索引,比如key1 = JD, key2 = BIDU
-
#查看百度,指定日期的数据 stocks.loc[("BIDU",'2019-10-02'),:] stocks.loc[("BIDU",'2019-10-02'),'开盘'] stocks.loc[["BIDU",'JD'],:] stocks.loc[(["BIDU",'JD'],'2019-20-03'),:] stocks.loc[(["BIDU",'JD'],'2019-20-03'),'收盘'] stocks.loc[("BIDU",['2019-10-02','2019-20-03']),'收盘'] #slice(None)代表筛选这一索引所有的内容 stocks.loc[(slice(None),['2019-10-02','2019-20-03']),:] #让索引变成普通的列 stocks.reset_index()
-
十五、Pandas的数据转换函数
-
数据转换函数的对比:map,apply,applymap:
- map:只用于Series,实现每个值->值的映射
- apply:用于Series实现每个值的处理,用于Dataframe实现每个轴的Series的处理
- applymap:只能用于DataFrame,用于处理DataFrame的每个元素
-
map用于Series值的转化
-
#公司股票代码到中文的映射 dict_company_names = { "baidu":'百度', 'baba':'阿里巴巴', 'iq':'爱奇异', 'jd':'京东' } #方法一、Series.map(dict) stocks["公司中文 "] =stocks['公司'].str.lower().map(dict_company_names) stocks.head() #方法二、Series.map(function) stocks["公司中文"] = stocks['公司'].str.lower().map(lambda x:dict_company_names[x.lower()])
-
-
apply用于Series和DataFrame的转换
-
Series.apply(function),函数的参数是每个值
-
DataFrame.apply(function),函数的参数是Series
-
#Series.apply(function) #function的参数是Series的每个值 stocks['公司中文3'] = stocks['公司'].apply(lambda x:dict_company_names[x.lower()])
-
#DataFrame.apply(function) stocks['公司中文3'] = stocks.apply(lambda x['公司']:dict_company_names[x.lower()])
-
-
applymap用于DataFrame所有值的转换
-
sub_df = stocks[['收盘', '开盘', '高', '低', '交易量']] #将这些列的所有数字取整,应用于所有的元素 sub_df.applymap(lambda x:int(x))
-
十六、Pandas怎么对每个分组应用apply函数
-
#对电影评分实现归一化 def rationgs_norm(df): min_value = df['Ration'].min() max_value = df['Ration'].max() df['Rating_norm'] = df['Rating'].apply( lambda x:(x-min_value)/(max_value - min_value) return df ratings =ratings.groupby("UserID").apply(ratings_norm) #取每个月温度最高的两天 def getWenduTop(df,topn): return df.sort_values(by='bWendu')[['ymd','bWendu']][-topn:] df.groupby('month').apply(getWenduTopN,topn=2).head()
十七、Pandas使用stack和pivot实现数据透视
-
经过统计得到多维度指标数据
-
#pandas转时间 df['pdate'] = pd.to_datetime(df['timestamp'], unit ='s') #实现数据统计 df_group = df.groupby([df['pdate'].dt.month, 'Rating'])['UserID'].agg(pv=np.sum) #获取日期的月份
-
-
使用unstack实现数据二维视图
-
#将两个索引变成x轴和y轴 df_stack = df_group.unstack() #unstack和stack是互逆的
-
-
使用pivot简化透视
-
#将索引变成普通的column df_reset = df_group.reset_index() df_pivot = df_reset.pivot('pdate', 'Rating','pv') pivot方法相当于对df使用set_index茶ungjian分层索引,然后调用unstack
-
-
stack,unstack,pivot的语法
- stack:Dataframe.stack(level = -1,dropna=True)将column变成index把column变成index
- unstack:Dataframe.unstack(level = -1,fill_value = None),将index,变成column类似把index变成column
- pivot:DataFrame.pivot(index=None,columns=None,values=None),指定index,columns,values实现二维透视
十八、Pandas怎样实现对日期的快书处理
-
概念:pd.to_datetime:pandas的一个函数,能将字符串列表series变成日期形式
-
Timestamp:pandas表示日期的对象形式
-
DatetimeIndex:pandas表示日期的对象列表形式
-
#将日期列转换为pandas的日期 df.set_index(pd.to_datatime(df['ymd']), inplace = True) #方便对DatetimeIndex进行查询 df.loc['2018-01-05'] #日期区间 df.loc['2018-01-05':'2018-01-10'] #按月份前缀进行筛选 df.loc['2018-03'] #按月份前缀筛选 df.loc['2018-07':'2018-09'].index #按年份进行前缀筛选 df.loc['2018'].head() #周数字列表 df.index.week #月数字列表 df.index.month #季度数字列表 df.index.quarter #统计每周的数据 df.groupby(df.index.week)['bWendu'].max().head()
十九、Pandas怎么处理日期索引的缺失
-
问题:按日期统计的数据,缺失了某天,导致数据不全该怎么处理
-
可以用两种方法实现:
- DataFrame.reindex,调整dataframe的索引以适应新的索引
- DataFrame.resampe,可以对时间序列重新采样,支持补充缺失值
-
如果缺失了索引该怎么填充
-
#使用reindex pdates = pd.date_range(start = '2019-12-01', end='2019-12-05') df_date_new = df_date.reindex(pdates, fill_value=0) #使用dataframe的resample的方法按照天进行重采样 resample的含义 改变数据的时间频率,比如把天数据变成月份,或者把小时变成分钟级别 resample的语法 (DataFrame or Series).resample(arguments).(aggregate function) #由于采样区间变成一个值,所以需要指定的mean等采样值的设定方法 df_new2 = df_new2.resample('D').mean().fillna(0) df_new2.resample('2D').mean()
-
二十、Pandas画Excel折现图
-
背景
- pandas是Python用于数据分析领域的超级牛的库
- Echarts是百度开源的非常好用的强大的可视化图表库,Pyecharts是它的Python库版本
-
使用Pyecharts绘制折线图
-
#如果没有安装,使用pip install pyecharts安装 from pyecharts.charts import Line from pyecharts import options as opts #折线图 line = Line() #x轴 line.add_xaxis(df.index.to_list()) #每个y轴 line.add_yaxis('开盘价',df['open'].round(2).to_list()) line.add_yaxis('收盘价',df['close'].round(2).to_list()) #图标配置 line.set_global_opts( title_opts = opts.TitleOpts(title='百度股票2019年'), tooltip_opts = opts.TooltipOpts(trigger='axis',axis_pointer_type='cross') #交互的十字架 ) #渲染数据 line.render_notebook()
-
二十一、Pandas结合Sklearn实现机器学习
-
#训练模型 from sklearn.linear_model import LogisticRegression #创建模型对象 logreg = LogisticRegression() #实现模型的训练 logreg.fit(X,y) #找一个历史中不存在的数据 X.drop_duplicates().sort_values(by=['Pclass','Parch']) #预测这个数据存活 logreg.predict([2,4]) logreg.predict_proba([2,4])
二十二、对网站的日志做数据分析
-
读取数据并清理格式化
-
pd.set_option('display.max_colwidth', -1) from pyecharts import options as opts from pyecharts.charts import Bar,Pie,Line #读取目录,拼接文件 data_dir = '....' df_list = [] fro fname in os.listdir(f'{data_dir}'): df_list.append(pd.read_csv(f'{data_dir/fname}',sep = '',header=None,err_bad_lines=False)) df = pd.concat(df_list) df =df[[0,3,6,9]].copy() df.columns = ['ip', 'stime', 'status', 'client'] #统计spider的比例 df['is_spider'] = df['client'].str.lower().str.contains9('spider') df_spider = df['is_spider'].value_counts() bar = ( Bar() .add_xaxis([str(x) fro x in df_spidre.index]) .add_yaxis('是否Spider',df_spider.values.tolist()) .set_global_opts(title_opts = opts.TitleOpts(title = '爬虫访问量占比')) ) bar.render_notebook() #访问状态码数量对比 df_status = df.groupby('status').size() pie = ( Pie(), .add('状态码比例', list(zip(df_status.index,df_status))) .set_series_opts(label_opts = opts.LabelOpts(formatter = "{b}:{c}")) ) pie.render_notebook()
-
按时间粒度对数据进行统计
-
#按小时进行统计 df_pvuv = df.resample("H")['ip'].agg(pv=np.size,uv = pd.Series.nunique) #按每六小时进行统计 df_pvuv = df.resample("6H")['ip'].agg(pv = np.size,uv = pd.Series.nunique) #按天进行统计 df_pvuv = df.resample("D")['ip'].agg(pv = np.size,uv = pd.Series.nunique) line =( Line() .add_xaxis(df_pvuv.index.to_list()) .add_yaxis('PV',df_pvuv['pv'].to_list()) .add_yaxis('UV',df_pvuv['uv'].to_list()) .set_global_opts( title_opts = opts.TitleOpts(title='PVUV数据对比') tooltip_opts = opts.TooltipOpts(trigger='axis',axis_pointer_type='cross') ) ) line.render_notebook( )
-
二十三、Pandas查询语句df.query
-
方式一、使用df[(df[‘a’] >3)&(df[‘b’]<5) ]
-
方式二、使用df.query(‘a’>3 &‘b’<5)
-
性能对比:
- 数据量小用第一种
- 数据大勇第二种
-
使用外部的变量
-
high_temperature = 15 low_temperature = 13 df.query('yWendu<=@high_temperature & yWendu>=@low_temperature')
-
二十四、Pandas按行便利DataFrame的三种方法
-
df.iterrows
-
for idx,row in df.iterrows(): result[(row['A'],row['B'])] += row['A'] + row['B']
-
-
df.itertuples
-
for row in df.itertuples(): result[(row.A,row.B)] += row.A + row.B
-
-
for+zip
-
for A,B in zip(df['A'],df['B']): print(A,B)
-
二十五、批量合并多个excel
-
dfs = [] for fname in os.listdir('./'): if fname.endswith('.xls') and fname!='final.xls': df = pd.read_excel( fname, header = None, sheet_name = None ) dfs.extend(df.values()) result = pd.concat(dfs) result.to_excel('./final.xls', index =False)