一、Pandas介绍
pandas 是基于NumPy 的一种工具,该工具是为解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具。pandas提供了大量能使我们快速便捷地处理数据的函数和方法。你很快就会发现,它是使Python成为强大而高效的数据分析环境的重要因素之一。
Pandas [1] 是python的一个数据分析包,最初由AQR Capital Management于2008年4月开发,并于2009年底开源出来,目前由专注于Python数据包开发的PyData开发team继续开发和维护,属于PyData项目的一部分。Pandas最初被作为金融数据分析工具而开发出来,因此,pandas为时间序列分析提供了很好的支持。 Pandas的名称来自于面板数据(panel data)和python数据分析(data analysis)。panel data是经济学中关于多维数据集的一个术语,在Pandas中也提供了panel的数据类型。
二、Pandas读取文件
pandas 需要读取表格类型的数据 ,然后进行分析
csv tsv txt 用逗号分隔、tab分割的线文本文件 pd.read_csv
excel 微软xls或xlsx文件 pd.read_excel
mysql 关系型数据库存表 pd.read_sql
import pandas as pd import pymysql # 1、读取txt文件 fpath1="./read_csv.csv" # # 读取数据 csv = pd.read_csv(fpath1) # # 查看前几行 print(csv.head()) # # 查看数据的形状,返回(行数,列数) print(csv.shape) # # 查看列名 print(csv.columns) # # 查看索引 print(csv.index) # # 查看每列的数据类型 print(csv.dtypes) # ''' # 读取txt文件,自定义分隔符、列名 # ''' csv1 = pd.read_csv( fpath1, sep="\t", header=None, names=['id','name','num'] ) print(csv1) # 2、读取excel文件 fpath2="./my.xlsx" xlsx1 = pd.read_excel(fpath2) print(xlsx1) # 3、读取MySql数据库 # (1)连接数据库 conn = pymysql.connect( host='192.168.1.17', user='root', passwd='123456', database='mysql', charset='utf8' ) # # (2)查询数据库 mysql_page=pd.read_sql("SELECT * FROM user",conn) print(mysql_page)</pre>
三、Pandas数据结构
Pandas数据结构:
DataFrame:二维数据,整个表格,多行多列
df.index:行
df.columns:列Series:一维数据,一行或一列,二维降维到一维
import pandas as pd import numpy as np """ 1、Series,是一种类似于一维数组的对象,它一组数据(不同数据类型)以及一组与之相关的数据标签 (即索引)组成。 1.1 仅有数据列表即可产生最简单的Series """ s1 = pd.Series([1,'a',3.3,8]) # 左侧为索引,右侧是数据 print(s1) # 获取索引 print(s1.index) # 获取数据 print(s1.values) """ 1.2 创建一个具有标签索引的Series """ # 指定索引 s2=pd.Series([1,'b',3.3,8],index=['a','b','c','d']) print(s2) # 获取索引 print(s2.index) """ 1.3 使用Python字典创建Series """ sdata={'0id':3000,'1id':303.9,'2id':4990,'3id':8903} s3=pd.Series(sdata) print(s3) """ 1.4 根据标签索引查询数据 """ print(s2['a']) print(type(s2['c'])) print(s2[['a','b']]) print(type(s2[['a','b']])) """ 2、DataFrame DataFrame是一个表格型的数据结构 每列可以是不同的值类型(数值、字符串、布尔值等) 既有行索引index,也有列索引columns 可以被看做由Series组成的字典 创建dataframe最常用的方法,见02节读取纯文本文件、excel、mysql数据库 """ # 2.1 根据多个字典序列创建DataFrame data={ 'state':['haha','haha','haha','hello','hello'], 'year':[2000,2001,2002,2003,2004], 'pop':[1.5,1.7,1.9,3.2,4.8] } df=pd.DataFrame(data) print(df) # 查看类型 print(df.dtypes) # 查看列索引 print(df.columns) # 查看行索引 print(df.index) """ 3、从DataFrame中查询出Series 如果只查询一列、一列,返回的是pd.Series 如果查询多行、多列,返回的是pd.DataFrame """ # 3.1 查询一列,结果是一个pd.Series print(df['year']) print(type(df['year'])) # 3.2 查询多列,结果是一个pd.DataFrame print(df[['year','pop']]) print(type(df[['year','pop']])) # 3.3 查询一行,结果是一个pd.Series print(df.loc[1]) print(type(df.loc[1])) # 3.4 查询多行,结果是一个pd.DataFrame print(df.loc[1:3]) print(type(df.loc[1:3]))
四、Pandas数据查询
Pandas 数据查询 的五种方法:数值、列表、区间、条件、函数
Pandas查询数据的几种方法:
1、df.loc方法:根据行、列的标签值查询
2、df.iloc方法:根据行、列的数字位置查询
3、df.where方法
4、df.query方法
.loc既能查询 ,又能覆盖写入,强烈推荐Pandas使用df.loc查询数据的方法
1、使用单个label值查询数据
2、使用值列表批量查询
3、使用数值区间进行范围查询
4、使用条件表达式查询
5、调用函数查询注意:
以上查询方法,既适用于行,也适用于列
注意观察降维 DataFrame > Series > 值
import pandas as pd """ 0、读取数据 """ df =pd.read_excel("./2020.xlsx") print(df.head()) # 设定索引为日期 df.set_index('日期',inplace=True) print(df.index) # 重新查询,发现索引变为 日期 print(df.head()) print(df.dtypes) # 替换数据,把 "bWendu" 列下的所有 "C" 替换为 "",类型为'int32' # df.loc[:,"bWendu"] = df["bWendu"].str.replace("C","").astype('int32') """ 1、使用单个label值查询数据 """ # 行 或 列,都可以只传入单个值,实现精确匹配 # 得到单个值 print(df.loc['2020-01-21',"单位"]) # 得到一个Series print(df.loc['2020-01-21',["单位","品名","规格"]]) """ 2、使用值列表批量查询 """ # 得到Series print(df.loc[['2020-01-21','2020-01-22','2020-01-23'],'单位']) # 得到DataFrame print(df.loc[['2020-01-21','2020-01-22','2020-01-23'],["单位","品名","规格"]]) """ 3、使用数值区间进行范围查询 """ # 注意:区间包含开始,也包含结束 # 行 index按区间 # print(df.loc['2020-01-02':'2020-01-15','单位']) # 列 index按区间 print(df.loc['2020-01-21','品名':'单位']) # 行和列都按区间查询 print(df.loc["2020-01-02": "2020-01-09", "品名":"单位"]) """ 4、使用条件表达式查询 """ # bool列表的长度得等于行数或者列数 # 简单条件查询,最小数量为10的列表 print(df.loc[df["数量"] < 10, :]) # 观察一下这里的boolean条件 print(df["数量"] < 10) # 复杂查询:组合条件用 & 符号合并,每个条件判断都得带括号 print(df.loc[(df["数量"]<=500) & (df["数量"]>=100)& (df["品名"] == "30/70混合重组人胰岛素注射液(甘舒霖30R(原:甘舒霖30R笔芯))"), :]) print((df["数量"]<=500) & (df["数量"]>=100)& (df["品名"] == "30/70混合重组人胰岛素注射液(甘舒霖30R(原:甘舒霖30R笔芯))")) ''' 5、调用函数查询 ''' # 直接写lambda表达式 print(df.loc[lambda df:(df["数量"]<=500) & (df["数量"]>=100),:]) print((df["数量"]<=500) & (df["数量"]>=100)) # 自定义函数,查询 # 函数式编程的本质:函数自身可以像变量一样传递 def query_my_data(df): return df.index.str.startswith('2020-01') & df["数量"]==100 print(df.loc[query_my_data,:])
五、Pandas新增数据列
直接赋值、apply、assign、分条件赋值
在进行数据分析时,经常需要按照一定条件创建新的数据列,然后进行进一步分析。
1、直接赋值2、df.apply方法
3、df.assign方法
4、按条件选择分组分别赋值
import pandas as pd # 0、 读取csv数据到dataframe fpath = "./beijing_tianqi_2018.csv" df = pd.read_csv(fpath) print(df.head()) # 1、 直接赋值 # 替换掉温度的后缀 ℃ ,变成数字类型------> 修改列 df.loc[:,"bWendu"] = df["bWendu"].str.replace("℃","").astype("int32") df.loc[:,"yWendu"] = df["yWendu"].str.replace("℃","").astype("int32") # 计算温差 -------> 新增列 # 注意:df["bWendu"]其实是一个Series,后面的减法返回的是Series df.loc[:,"wencha"] = df["bWendu"] - df["yWendu"] print(df.head()) # 2、 df.apply方法 """ Apply a function along an axis of the DataFrame. Object passed to the function are Series objects whose index is either the DataFrame's index (axis=0) or the DataFrame's columns (axis=1). 实例:添加一列温度类型: 1、如果最高温度大于33度就是高温 2、低于-10度是低温 3、否则常温 """ def get_wendu_type(x): if x["bWendu"] > 33: return "高温" if x["yWendu"] < -10: return "低温" return "常温" # 注意: 需要设置axis == 1,这是Series的index是columns df.loc[:,"wendu_type"] = df.apply(get_wendu_type,axis= 1) print(df.head()) # 查看温度类型的计数 print(df["wendu_type"].value_counts()) # 3、df.assign方法 """ Assign new columns to a DataFrame. Returns a new object with all original columns in addition to new ones. 实例:将温度从摄氏度变成华氏度 """ # 可以同时添加多个新的列 df.assign( # 摄氏转华氏 yWendu_huashi=lambda x: x["yWendu"] * 9 / 5 + 32, bWendu_huashi=lambda x: x["bWendu"] * 9 / 5 + 32 ) print(df.head()) # 4、按条件选择分组分别赋值 """ 按条件先选择数据,然后对这部分数据赋值新列 实例:高低温差大于10度,则认为温差大 """ # 先创建空列(这是第一种创建新列的方法) df["wencha_type"] = "" df.loc[df["bWendu"] - df["yWendu"] > 10,"wencha_type"] = "温差大" df.loc[df["bWendu"] - df["yWendu"] < 10 ,"wencha_type"] = "温差正常" print(df.head()) print(df["wencha_type"].value_counts())
六、Pandas 数据统计函数 1、汇总类统计 2、唯一去重和按值计数 3、相关系数和协方差
import pandas as pd # 0、读取csv数据 fpath = "./beijing_tianqi_2018.csv" df = pd.read_csv(fpath) # print(df.head(3)) # 替换掉温度的后缀 ℃ ,变成数字类型------> 修改列 df.loc[:,"bWendu"] = df["bWendu"].str.replace("℃","").astype("int32") df.loc[:,"yWendu"] = df["yWendu"].str.replace("℃","").astype("int32") # 1、汇总类统计 df.describe() # 一下子提取所有数字列统计结果 print(df.describe()) # 查看单个列Series的数据 print(df["bWendu"].mean()) # 平均温度 print(df["bWendu"].max()) # 最高温度 print(df["bWendu"].min()) # 最低温度 # 2、 唯一去重和按值计数 # 2.1 唯一去重 # 一般不用于数值列,而是枚举、分类列 print(df["fengxiang"].unique()) print(df["tianqi"].unique()) print(df["fengli"].unique()) # 2.2 按值计数 print(df["fengxiang"].value_counts()) print(df["tianqi"].value_counts()) print(df["fengli"].value_counts()) # 3、相关系数和协方差 """ 用途:(超级厉害) 1、两只股票,是不是同涨同跌?程度多大?正相关还是负相关? 2、产品销量的波动,跟哪些因素正相关、负相关、程度有多大? 来自知乎,对于两个变量x y: 1、协方差:衡量同向反向程度,如果协方差为正,说明X、Y同向变化,协方差越大,说明同向程度越高; 如果协方差为负,说明X,Y反向运动,协方差越小说明反向程度越高。 2、相关系数:衡量相似度程度,当他们的相关系统为1时,说明两个变量变化时的正向相似度最大, 当相关系数为-1时,说明两个变量变化的反向相似度最大。 """ # 协方差矩阵 print(df.cov()) # 相关系数矩阵 print(df.corr()) # 单独查看空气质量和最高温度的相关系数 print(df["aqi"].corr(df["bWendu"])) print(df["aqi"].corr(df["yWendu"])) # 空气质量和温差的相关系数 print(df["aqi"].corr(df["bWendu"] - df["yWendu"])) """ !! 这就是特征工程对于机器学习重要性的一个盒子!!"""
七、Pandas对缺失值的处理
1、isnull和notnull:检测是否是空值,可用于df和series
2、dropna:丢弃、删除缺失值
1)axis:删除行还是列,{0 or ‘index’, 1 or ‘columns’},default 0
2) how:如果等于any则任何值为空都删除,如果等于all则所有值都为空才删除
3)inplace:如果 为True则修改当前df,否则返回新的df
3、fillna:填充空值:
1)value:用于填充的值,可以是单个值,或者字典(key是列名,value是值)
2)method:等于ffill使用前一个不为空的值填充forword fill;等于bfill使用后一个不为空的值填充backword fill
3)axis:按行还是列填充,{0 or ‘index’ , 1 or ‘columns’}
4)inplace:如果为True则修改当前df,否则返回新的df
import pandas as pd # 实例:特殊Excel的读取、清洗、处理 # 步骤1:读取excel的时候,忽略前几个空行 studf = pd.read_excel("./student_excel.xlsx",skiprows = 2) print(studf) # 步骤2:检测空值,True表示空 print(studf.isnull()) # 检测单列空值 print(studf["分数"].isnull()) # 与isnull相反的函数 notnull(),NaN(False)表示空,可以筛选出不为空的行 print(studf["分数"].notnull) # 筛选没有空分数的所有行 print(studf.loc[studf["分数"].notnull(),:]) # 步骤3:删除掉全是空值的列,columns表示列 print(studf.dropna(axis="columns",how="all",inplace=True)) print(studf) # 步骤4:删除掉全是空值的行,index表示行 print(studf.dropna(axis="index",how="all",inplace=True)) print(studf) # 步骤5:将分数列为空的填充为0分 # 方法一:传入一个字典,key表示列名 studf.fillna({"分数": 0.0}) print(studf) # 方法二: studf.loc[:,"分数"] = studf["分数"].fillna(0.0) print(studf) # 步骤6:将姓名的缺失值填充 # 使用前面的有效值填充,用 ffill: forward fill studf.loc[:,"姓名"] = studf["姓名"].fillna(method="ffill") print(studf) # 步骤7:将清洗好的excel保存,index=False表示不保存索引 studf.to_excel("./student_excel_clean.xlsx",index=False)
八、Pandas 的SettingWithCopyWarning 报警复现、原因、解决方案
import pandas as pd # 0、读取数据 fpath = "beijing_tianqi_2018.csv" df = pd.read_csv(fpath) # 替换温度后的℃ df.loc[:,"bWendu"]= df["bWendu"].str.replace("℃","").astype("int32") df.loc[:,"yWendu"]= df["yWendu"].str.replace("℃","").astype("int32") # 1、复现报警 # 只选出3月份的数据用于分析 condition = df["ymd"].str.startswith("2018-03") # 设置温差 df[condition]["wen_cha"] = df["bWendu"] - df["yWendu"] # 报警出现 # 查看是否修改成功 df[condition].head() # 建议用这个方式:.loc[row_indexer,col_indexer] = value instead # 2、原因 """ 发出警告的代码:df[condition]["wen_cha"] = df["bWendu"] - df["yWendu"] 代码相当于:df.get(condition).set(wen_cha),第一步的get发出了报警 链式操作其实是两个步骤,先get后set,get得到的dataframe可能是view也可能是copy,pandas发出警告 官方文档: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy 核心要决:pandas的dataframe的修改写操作,只允许在源dataframe上进行,一步到位 """ # 3、解决方法 # 方法一:将get + set的两步操作,改成set 的一步操作 df.loc[condition,"wen_cha"] = df["bWendu"]-df["yWendu"] print(df[condition].head()) # 方法二:如果需要预筛选数据做后续的处理分析,使用copy复制dataframe df_month3 = df[condition].copy() print(df_month3) df_month3["wen_cha"] = df["bWendu"]-df["yWendu"] print(df_month3.head()) """ 总之,pandas不允许先筛选子dataframe,再进行修改写入 要么使用.loc实现一个步骤直接修改源dataframe 要么先复制一个子dataframe再一个步骤执行修改 """
九、Pandas数据排序
Series的排序:
Series.sort_values(ascending=True,inplace=False)
参数说明:
ascending:默认为True升序排序,为False降序排序
inplace:是否修改原始SeriesDataFrame的排序:
DataFrame.sort_values(by,asendong=True,inplace=False)
参数说明:
by:字符串或才List<字符串>,单列排序 或者多列排序
ascending: bool或者List,升序还是降序,如果 是list对应by的多列
inplace: 是否修改原始DataFrame
import pandas as pd # 0、读取数据 fpath = "beijing_tianqi_2018.csv" df = pd.read_csv(fpath) # 替换温度后的℃ df.loc[:,"bWendu"]= df["bWendu"].str.replace("℃","").astype("int32") df.loc[:,"yWendu"]= df["yWendu"].str.replace("℃","").astype("int32") # 1、Series的排序 default=df['aqi'].sort_values() # 默认,升序 print(default) df_false=df['aqi'].sort_values(ascending=False) # 降序 print(df_false) tianqi = df['tianqi'].sort_values() # 中文内容排序 print(tianqi) # 2、DataFrame的排序 # 2.1 单列排序 default = df.sort_values(by='aqi') print(default) df_false= df.sort_values(by='aqi',ascending=False) print(df_false) # 2.2 多列排序 # 按空气质量等级、最高温度排序 ,默认升序 default = df.sort_values(by=['aqiLevel','bWendu']) print(default) # 两个字段都是降序 df_false=df.sort_values(by=["aqiLevel",'bWendu'],ascending=False) print(df_false) # 分别指定升序和降序 option_value=df.sort_values(by=['aqiLevel','bWendu'],ascending=[True,False]) print(option_value)
十、Pandaspb字符串处理
前面我们已经使用了字符串的处理函数:
df[“bWendu”].str.replace(“℃”).astype(“int32”)Pandas的字符串处理:
1、使用方法:先获取Series的str属性,然后在属性上调用函数;
2、只能在字符串列上使用,不能在数字列上使用;
3、DATaFrame上没有属性和处理方法
4、Series.str并不Python原生字符串,而是自己的一套方法,不过大部分和原生str很相似;Series.str字符串方法列表参考文档:
https://pandas.pydata.org/pandas-docs/stable/reference/series.html#string-handling本节演示内容:
1、获取Series的属性,然后使用各种字符串处理函数
2、使用str的startswith、contains等bool类Series可以做条件查询
3、需要多次str处理的链式操作
4、使用正则表达式的处理
import pandas as pd fpath = "beijing_tianqi_2018.csv" df=pd.read_csv(fpath) # print(df.dtypes) # 类型object,都是字符串的列 # 1、获取Series的str属性,使用各种字符串处理函数 # get_str = df["bWendu"].str # 获取df["bWendu"]的属性,发现是字符串StringMethods # print(get_str) # 字符串替换函数 # df = df["bWendu"].str.replace("℃","") # print(df) # 判断是不是数字,返回布尔值 # isNum=df["bWendu"].str.isnumeric() # print(isNum) # 不能在数字列上使用 .len(),只能在 string类型的列上使用 # get_len=df["aqi"].str.len() # print(get_len) # 2、使用str的startswith、contains等得到bool的Series可以做条件查询 # startswith,返回布尔值,在ymd列查询 包含2018-03的行 # condition = df["ymd"].str.startswith("2018-03") # print(condition) # print(df[condition].head()) # 查看查询的结果 # 3、多次str处理的链式操作 """ 怎样提取201803这样的数字月份? 1、先将日期2018-03-01 2、提取月份字符串20180301 """ # 替换 “-” 为“” # new_mon=df["ymd"].str.replace("-","") # print(new_mon) # 每次调用函数 ,都返回一个新Series,报错,只能在str上使用 # get_mon = df["ymd"].str.replace("-","").slice(0,6) # print(get_mon) # 正确做法,slice就是切片语法 # new_mon=df["ymd"].str.replace("-","").str.slice(0,6) # print(new_mon) # slice就是切片语法,可以直接用切片.str[0:6] # new_mon = df["ymd"].str.replace("-","").str[0:6] # print(new_mon) # 4、使用正则表达式的处理 # 添加新列,axis:0表示行,1表示列 def get_ymd(x): year,month,day = x["ymd"].split("-") return f"{year}年{month}月{day}日" df["中文日期"] = df.apply(get_ymd,axis = 1) print(df["中文日期"]) # 怎样装饰“2018年01月05日”中的年月日去掉 # 方法一:链式replace # new_ymd=df["中文日期"].str.replace("年","").str.replace("月","").str.replace("日","") # print(new_ymd) # 方法二:正则表达式替换 new_ymd=df["中文日期"].str.replace("[年月日]","") print(new_ymd)
十一、Pandas的axis参数怎么理解?
axis=0 或 axis = index:
如果是单行操作,就指的是某一行
如果是聚合操作,指的是跨行cross rows
axis=1 或 axis = columns:
如果是单列操作,就指的是某一列
如果是聚合操作,就指的是跨列cross columns
按哪个axis,就是这个axis要动起来(类似被 for 遍历),其它的axis保持不动
import pandas as pd import numpy as np # 0、构造一个DataFrame df = pd.DataFrame( np.arange(16).reshape(4,4), # 生成0-11的12个数字,把它们分成3行4列 columns=['A','B','C','D'] # 指定列名 ) print(df) # 1、单列drop,就是删除某一列 # drop_col= df.drop("A",axis=1) # print(drop_col) # 2、单行drop,删除某一行 # drop_row = df.drop(1,axis=0) # print(drop_row) # 3、按axis=0/index执行mean聚合操作 # 反直觉:输出的不是每行的结果,而是每列的结果 # df_mean = df.mean(axis=0) # df_mean = df.mean(axis=0) # 按哪个axis,就是这个axis要动起来(类似被 for 遍历),其它的axis保持不动 # print(df_mean) # 删除第一行,把列变成行,列名变成索引,列的首个值变成每行的首个值 # 4、 按axis=1/columns执行mean聚合操作 # 反直觉:输出的不是每行的结果,而是每列的结果 # df_mean = df.mean(axis=1) # print(df_mean) # 删除列名,行数不变,只保留每行的平均值,清理其他数 # 5、再次举例,加深理解 # 返回四列每行的和 def get_sum_value(x): return x["A"] + x["B"] + x["C"] + x["D"] df["sum_value"] = df.apply(get_sum_value,axis=1) print(df["sum_value"])
十二、Pandas的索引index
把数据存储于普通的columns列也能用于数据查询,那使用index有什么好?
index的用途总结:
1、更方便的数据查询
2、使用index可以获得性能提升
3、自动的数据对齐功能
4、更多强大的数据结构支持
import pandas as pd import time # 0、获取数据 df = pd.read_csv("ratings.csv") # print(df.head()) # print(df.count) # 1、使用index查询数据 # 自定义索引,drop=Fasle,让索引列还保持在columns # df.set_index("userId",inplace=True,drop=False) # print(df.head()) # print(df.index) # 使用index的查询方法 # search_index=df.loc[500].head(5) # print(search_index) # 使用column的condition查询方法 # search_col = df.loc[df["userId"]==500].head() # print(search_col) # 2、使用index会提升查询性能 """ 如果index是唯一的,Pandas会使用哈希表优化,查询性能为O(1); 如果index不是唯一的,但是有序,Pandas会使用二分查找算法,查询性能为O(logN); 如果index是完全随机的,那么每次查询都要扫描全表,查询性能为O(N). """ # 实验1:完全随机的顺序查询 # 将数据随机打散 # from sklearn.util import shuffle # df_shuffle = shuffle(df) # df_shuffle.head() # # # 索引是否是递增的 # df_sh_index=df_shuffle.index.is_monotonic_increasing # print(df_sh_index) # # 索引是否有序 # df_is_unique=df_shuffle.index.is_unique # print(df_is_unique) # 计时,查询id==500数据性能 # %timeit df_shuffle.loc[500] # %timeit 是ipython的函数 """ pycharm计时方式: start = time.clock() end = time.clock() times = end - start """ # 实验2:将index排序后的查询 # df_sorted = df_shuffle.sort_index() # print(df_sorted.head()) # # 索引是否是递增的 # df_sh_index=df_shuffle.index.is_monotonic_increasing # print(df_sh_index) # # 索引是否有序 # df_is_unique=df_shuffle.index.is_unique # print(df_is_unique) # 计时,查询id==500数据性能 # %timeit df_shuffle.loc[500] # %timeit 是ipython的函数 # 3、使用index能自动对齐数据,包括Series 和 DataFrame s1 = pd.Series([1,2,3],index=list("abc")) print(s1) s2 = pd.Series([2,3,4],index=list("bcd")) print(s2) print(s1+s2) # 4、使用index更多更强大的数据结构支持 """ 很多强大的索引数据结构 CategoricalIndex,基于分类数据的index,提升性能 MultiIndex,多维索引,用于groupby多维聚合后结果等 DatetimeIndex,时间类索引,强大的日期和时间的方法支持 """
十三、Pandas的Merge语法
Pandas怎样实现DATaFrame的Merge
Pandas的Merge,相当于Sql的Join,将不同的表按key关联到一个表
merge的语法:
pd.merge(left,right,how=’inner’,on=None,left_on=None,right_on=None,left_index=False,right_index=False,
sort=True,suffixes=(‘_x’,’_y’),copy=True,indicator=False,validate=None)
left,right:要merge的dataframe或者有name的Series
how:join类型,’left’,’right’,’outer’,’inner’
on:join的key,left和right都需要这个key
left_on:left的df或者series的key
right_on:right的df或者series的key
left_index,right_index:使用index而不是普通的column做join
suffixes:两个元素的后缀,如果列有重名,自动添加后缀,默认是(’_x’,’_y’)
官方文档地址:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.merge.html
import pandas as pd # 1、电影数据集的join实例 # 读取数据 # df_ratings = pd.read_csv( # "./movielens-1m/ratings.dat", # sep="::", # engine="python", # names="UserID::MoveID::Rating::Timestamp".split("::") # ) # print(df_ratings.head()) # df_users = pd.read_csv( # "movielens-1m/users.dat", # sep="::", # engine="python", # names="UserId::Gender::Age::Occupation::Zip-code".split("::") # ) # print(df_users.head()) # df_movies = pd.read_csv( # "movielens-1m/movies.dat", # sep="::", # engine="python", # names="moveID::Title::Genres".split("::") # ) # print(df_movies.head()) # inner,两边都有数据才会保留 # df_ratings_users = pd.merge( # df_ratings,df_users,left_on="UserID",right_on="UserId",how="inner" # ) # print(df_ratings_users.head()) # df_ratings_users_moives = pd.merge( # df_ratings_users,df_movies,left_on="MoveID",right_on="moveID",how="inner" # ) # print(df_ratings_users_moives.head(10)) # 2、理解merge时数量的对齐关系 """ 以下关系要正确理解: one-to-one:一对一关系,关联的key都是唯一的 比如(学号,姓名)merge(学号,年龄) 结果条数为:1*1 one-to-many:一对多关系,左边唯一key,右边不唯一key 比如(学号,姓名) merge(学号,[语文成绩、数学成绩、英语成绩]) 结果条数为:1*N many-to-many:多对多关系,左边都不是唯一的 比如(学号,[语文成绩、数学成绩、英语成绩]) merge (学号,[蓝球、足球、乒乓球]) 结果条数为: M*N """ # 2.1 one-to-one:一对一关系,关联的key都是唯一的 name = pd.DataFrame({ 'sno':[11,12,13,14], 'name':['name_a','name_b','name_c','name_d'] }) # print(name) age = pd.DataFrame({ 'sno':[11,12,13,14], 'age':['21','22','22','23'] }) # print(age) stud = pd.merge(name,age,on='sno') # print(stud) # 2.2 one-to-many:一对多关系,左边唯一key,右边不唯一key,数目以多的一边为准 grade = pd.DataFrame({ 'sno':[11,11,11,12,12,13], 'grade':['语文88','数学90','英语89','语文99','数字87','英语77'] }) grade = pd.merge(name,grade,on='sno') # print(grade) # 2.3 多对多关系merge,注意结果会出现 乘法 lovely = pd.DataFrame({ 'sno':[11,11,12,12,13], '爱好':['篮球','羽毛球','乒乓球','篮球','足球'] }) lovely = pd.merge(grade,lovely,on='sno') # print(lovely) # 3、理解left join、right join、inner join、outer join的区别 left = pd.DataFrame({ 'key':['k0','k1','k2','k3'], 'A':['A0','A1','A2','A3'], 'B':['B0','B1','B2','B3'] }) right = pd.DataFrame({ 'key':['k0','k1','k4','k5'], 'C':['C0','C1','C4','C5'], 'D':['D0','D1','D4','D5'] }) # 3、1 inner join,默认,左边和右边的key都有,才会出现在结果里 inner_join= pd.merge(left,right,how='inner') print(inner_join) # 3.2 left join,左边的都会出现在结果里,右边的如果无法匹配则为Null left_join = pd.merge(left,right,how="left") print(left_join) # 3.3 right join,右边的都会出现在结果里,左边的如果无法匹配则为Null right_join = pd.merge(left,right,how="right") print(right_join) # 3.4 outer join,两边的都会出现在结果里,如果无法匹配则为Null outer_join = pd.merge(left,right,how="outer") print(outer_join) # 4、如果出现非Key的字段重名怎么办 left = pd.DataFrame({ 'key':['k0','k1','k2','k3'], 'A':['A0','A1','A2','A3'], 'B':['B0','B1','B2','B3'] }) right1 = pd.DataFrame({ 'key':['k0','k1','k4','k5'], 'A':['C0','C1','C4','C5'], 'D':['D0','D1','D4','D5'] }) # 默认是 suffixes=('_x','_y') suff1 = pd.merge(left,right1,on='key') print(suff1) suff = pd.merge(left,right1,on='key',suffixes= ('_left','_right')) print(suff)
十四、Pandas实现数据的合并concat
使用场景:
批量合并相同格式的excel、给DATaFrame添加行、给DATaFrame添加列
一句话说明concat语法:
使用某种合并方式(inner/outer)
沿着某个轴向(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, 也可以是inner join
ignore_index: 是否忽略掉原来的数据索引append语法:DATaFrame.append(other,ignore_index=False)
append只有按行合并,没有按列合并,相当于concat按行的简写形式
other: 单个dataframe、series、dict,或者列表
ignore_index: 是否忽略掉原来的数据索引
参考文档:
pandas.concat的api文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.concat.html
pandas.concat的教程:https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html
pandas.append的api文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.append.html
import pandas as pd import warnings warnings.filterwarnings('ignore') # 忽略报警 # 一、使用pandas.concat合并数据 # df1 = pd.DataFrame({'A':['a0','a1','a2','a3'], # 'B':['b0','b1','b2','b3'], # 'C':['c0','c1','c2','c3'], # 'D':['d0','d1','d2','d3'], # 'E':['e0','e1','e2','e3'] # }) # # df2 = pd.DataFrame({'A':['a4','a5','a6','a7'], # 'B':['b4','b5','b6','b7'], # 'C':['c4',F'c5','c6','c7'], # 'D':['d4','d5','d6','d7'], # 'F':['f4','f5','f6','f7'] # }) # 1、默认的concat,参数为axis=0,join=outer,ignore_index=False # default_concat = pd.concat([df1,df2]) # print(default_concat) # 2、使用ignore_index=True可以忽略原来的索引 # default_concat = pd.concat([df1,df2],ignore_index=True) # print(default_concat) # 3、使用join=inner过滤掉不匹配的列 # inner_concat = pd.concat([df1,df2],ignore_index=True,join='inner') # print(inner_concat) # 4、使用axsi=1相当于添加新列 # 4.1 添加一列Series # s1 = pd.Series(list(range(4)),name='F') # add_series = pd.concat([df1,s1],axis=1) # print(add_series) # 4.2 添加多列Series # s2= df1.apply(lambda x:x['A'] + "_GG",axis=1) # print(s2) # s2.name = "G" # new_df = pd.concat([df1,s1,s2],axis=1) # print(new_df) # 列表可以只有Series # new_series = pd.concat([s1,s2],axis=1) # print(new_series) # 列表是可以混合顺序的 # new_df = pd.concat([s1,df1,s2],axis=1) # print(new_df) # 二、使用DATaFrame.append按行合并数据 # df1 = pd.DataFrame([[1,2],[3,4]],columns=list('AB')) # print(df1) # df2 = pd.DataFrame([[5,6],[7,8]],columns=list('AB')) # print(df2) # 1、给1个DATaFrame添加另一个DATaFrame # df = df1.append(df2) # print(df) # 2、 忽略原来的索引 # df = df1.append(df2,ignore_index=True) # print(df) # 3、可以一行一行的给DataFrame添加数据 # 一个空的DataFrame df = pd.DataFrame(columns=['A']) # print(df) # A 、低性能版 # for i in range(5): # # 注意:这里每次都在复制 # df = pd.append({'A': i}, ignore_index=True) # print(df) # B、性能好的版本 # 第一个入参是一个列表,避免了多次复制 df = pd.concat( [pd.DataFrame([i],columns=['A'])for i in range(5)], ignore_index=True ) print(df)
十五、Pandas批量拆分与合并excel文件
Pandas批量拆分 Excel 与合并Excel
实例演示:
1、将一个大Excel等份拆成多个Excel
2、将多个小Excel合并成一个大Excel并标记来源
import os import pandas as pd word_dir = "./datas" splits_dir = f"{word_dir}/splits" # 工作目录没有 splits_dir 目录则创建 if not os.path.exists(splits_dir): os.mkdir(splits_dir) # 0、读取源Excel到Pandas df_source = pd.read_excel(f"{word_dir}/crazyant_blog_articles_source.xlsx") # print(df_source.head()) # print(df_source.index) # 返回RangeIndex RangeIndex(start=0, stop=258, step=1) # print(df_source.shape) # 返回行数和列数 (258, 3) # 统计总行数 total_row_count = df_source.shape[0] # print(total_row_count) # 一、将一个大Excel等份拆成多个Excel """ 1、使用 df.iloc方法,将一个大的dataframe拆分成多个小dataframe 2、将使用dataframe.to_excel保存每个小Excel """ # 1、计算拆分后的每个Excel的行数 # 这个大Excel,会拆分给这几个人 user_name = ["xiao_shuai","xiao_wang","xiao_ming","xiao_lei","xiao_bo","xiao_hong"] # 每个人的任务数目 splits_size = total_row_count // len(user_name) # 不能均分的处理 if total_row_count % len(user_name) != 0: splits_size += 1 # print(splits_size) # 拆分成多个DataFrame df_subs = [] # 遍历用户列表 for idx, user_name in enumerate(user_name): # .iloc的开始索引 begin = idx * splits_size # .iloc的结束索引 end = begin + splits_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) # 二、合并多个小Excel到一个大Excel """ 1、遍历文件夹,得到要合并的Excel文件列表 2、分别读取到dataframe,给每个df添加一列用于标记来源 3、使用pd.concat进行df批量合并 """ # 1、遍历文件夹,得到要合并的Excel名称列表 excel_names = [] for excel_name in os.listdir(splits_dir): excel_names.append(excel_name) excel_name # 2、分别读取到dataframe df_list = [] for excel_name in excel_names: # 读取每个Excel到df excel_path = f"{splits_dir}/{excel_name}" df_split = pd.read_excel(excel_path) # 得到username username = excel_name.replace("crazyant_blog_articles_","").replace(".xlsx","")[2:] # print(excel_name) # 给每个df添加1列,即用户名 df_split["username"] = username df_list.append(df_split) # 3、使用pd.concat进行合并 df_merged = pd.concat(df_list) print(df_merged.shape) print(df_merged.head()) print(df_merged['username'].value_counts()) # 4、将合并后的dataframe输出到excel df_merged.to_excel(f"{word_dir}/crazyant_blog_articles_merged.xlsx",index=False)
十六、Pandas怎样实现groupby分组统计
类似:SQL
select city,max(temperature) from city_weather group by city;
groupby:先对数据分组,然后在每个分组上应用聚合函数、转换函数
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 加上这句,能在jupyter notebook展示 matplot图表 # %matplotlib inline df = pd.DataFrame({'A':['foo','bar','foo','bar','foo','bar','foo','foo'], 'B':['one','two','one','one','three','two','one','three'], 'C':np.random.randn(8), 'D':np.random.randn(8)}) print(df) # 1、单个groupby,查询所有数据列的统计,求和 gro_sum = df.groupby('A').sum() print(gro_sum) # groupby中的A变成了数据的索引列,因为要统计sum,但B列不是数字,所以被自动忽略掉 # 2、多个列groupby,查询所有数据列的统计,平均值 gro_mean = df.groupby(['A','B']).mean() print(gro_mean) # 我们看到:(‘A','B')成对变成了二级索引 gro_mean1 = df.groupby(['A','B'],as_index=False).mean() print(gro_mean1) # 加上as_index=False,不让A变成索引 # 3、同时查看多种数据统计 gro_agg = df.groupby('A').agg([np.sum,np.mean,np.std]) print(gro_agg) # 4、查看单列的结果数据统计 # 方法一:预过滤,性能更好 gro_agg1 = df.groupby('A')['C'].agg([np.sum,np.mean,np.std]) print(gro_agg1) # 单独筛选出 C 列 # 方法二: gro_agg2 = df.groupby('A').agg([np.sum,np.mean,np.std])['C'] print(gro_agg2) # 5、不同列使用不同的聚合函数 gro_agg3 = df.groupby('A').agg({'C':np.sum,'D':np.mean}) print(gro_agg3) # 二、遍历groupby 的结果理解执行流程 # for循环可以直接遍历每个group # 1、遍历单个列聚合的分组 for_group = df.groupby('A') print(for_group) for name,group in for_group: print(name) print(group) print() # 可以获取单个分组的数据 for_bar = for_group.get_group('bar') print(for_bar) # 2、遍历多个列聚合的分组 # 可以看到,name是一个2个元素的tuple,代表不同的列 for_group1 = df.groupby(['A','B']) for name,group in for_group1: print(name) print(group) print() for_foo = for_group1.get_group(('foo','one')) print(for_foo) # 可以直接查询group后的某几列,生成Series或者子DataFrame for_C = for_group1['C'] for name,group in for_C: print(name) print(group) print(type(group)) print() # 其实,所有的聚合统计,都是在DATaFrame和Series上进行的 # 三、实例分组,探索天气数据 fpath = "./beijing_tianqi_2018.csv" df = pd.read_csv(fpath) print(df) # 替换掉温度后面的“” df.loc[:,'bWendu'] = df['bWendu'].str.replace('℃','').astype('int32') df.loc[:,'yWendu'] = df['yWendu'].str.replace('℃','').astype('int32') print(df.head()) # 新增一列为月份 df['month'] = df['ymd'].str[:7] print(df.head()) data = df.groupby('month')['bWendu'].max() print(data) print(type(data)) # 绘图 plt.plot(data) # plt.show() # 查看每个月的最高温度,最低温度,平均空气质量指数 print(df.head) group_data = df.groupby('month').agg({'bWendu':np.max,'yWendu':np.min,'aqi':np.mean}) print(group_data) print(type(group_data)) # 绘图 plt.plot(group_data) plt.show()
十七、Pandas的分层索引MultiIndex
为什么要学习分层索引?
分层索引:在一个轴向上拥有多个索引层级,可以表达更高维度数据的形式
可以更方便的进行数据筛选,如果有序则性能更好
groupby等操作的结果,如果是多KEY,结果是分层索引,需要会使用
一般不需要自己创建分层索引(MultiIndex有构造函数但一般不用)演示数据:百度、阿里巴巴、爱奇艺、京东四家公司的10天股票数据
数据来自:英为财经 https://cn.investing.com
import pandas as pd path = "datas/互联网公司股票.xlsx" stocks = pd.read_excel(path) # print(stocks.shape) # print(stocks.head()) # 查看包含哪些公司 coump = stocks['公司'].unique() # print(coump) # # print(stocks.index) # 查收收盘价的平均值 # print(stocks.groupby('公司')['收盘'].mean()) # 一、Series的分层索引MultiIndex ser = stocks.groupby(['公司','日期'])['收盘'].mean() # print(ser) # 多维索引中,空白的意思是:使用上面的值 # print(ser.index) # unstack把二级索引变成列 # print(ser.unstack()) # print(ser.reset_index()) # 二、Series有多索引MultiIndex怎样筛选数据? # print(ser) # print(ser.loc['BIDU']) # 多层索引,可以用元组的形式筛选 # print(ser.loc[('BIDU','2019-10-03')]) # # print(ser.loc[:,'2019-10-02']) # 三、DataFrame的多层索引MultiIndex # print(stocks.head()) # 输入列表做为分层索引 stocks.set_index(['公司','日期'],inplace=True) # print(stocks) # print(stocks.index) # 四、DataFrame有多层索引MultiIndex怎样筛选数据? """ 【重要知识】 在选择数据时: 元组(key1,key2)代表筛选多层索引,其中key1是索引第一级,key2是第二级,比如key1=JD,key2=2019-10-02 列表[key1,key2]代表同一层的多个KEY,其中key1和key2是并列的同级索引,比如key1=JD,Key2=BIDU """ print(stocks.loc['BIDU']) print(stocks.loc[('BIDU','2019-10-02'),:]) print(stocks.loc[('BIDU','2019-10-03'),'开盘']) print(stocks.loc[['BIDU','JD'],:]) print(stocks.loc[(['BIDU','JD'],'2019-10-03'),:]) print(stocks.loc[(['BIDU','JD'],'2019-10-03'),'收盘']) print(stocks.loc[('BIDU',['2019-10-02','2019-10-03']),'收盘']) # slice(None)代表选这一索引的所有内容 print(stocks.loc[(slice(None),['2019-10-02','2019-10-03']),:]) stocks.reset_index() print(stocks)
十八、Pandas的数据转换函数map,apply,applymap
数据转换函数对比: map、apply、applymap:
1、map:只用于Series,实现每个值–>值的映射;
2、apply:用于Series实现每个值的处理,用于DataFrame实现某个轴的Series的处理;
3、applymap:只能用于DataFrame,用于处理该DataFrame的每个元素。
# 1、map用于Series值的转换 # 实例:将股票代码英文转换成中文名字 # Series.map(dict) 或 Series.map(function)均可 import pandas as pd stocks = pd.read_excel("datas/互联网公司股票.xlsx") print(stocks.head(3)) print(stocks['公司'].unique()) # 公司股票代码到中的映射,注意这里是小写 dict_company_names={ 'bidu':'百度', 'baba':'阿里巴巴', 'iq':'爱奇艺', 'jd':'京东' } # 方法一:将'公司'列的名转为小写,再从字典中取值,成为新列 stocks['公司中文名1'] = stocks['公司'].str.lower().map(dict_company_names) print(stocks.head()) # 方法二:Series.map(function) # function的参数是Series的每个元素的值 stocks['公司中文名2'] = stocks['公司'].map(lambda x:dict_company_names[x.lower()]) print(stocks.head()) # 2、apply用于Series和DataFrame的转换 ''' Series.apply(function),函数的参数是每个值 DataFrame.apply(function),函数的参数是Series ''' # Series.apply(function) function的参数是Serises的每个值 stocks['公司中文名3'] = stocks['公司'].apply(lambda x:dict_company_names[x.lower()]) print(stocks.head()) # DataFrame.apply(funciton) function的参数是对应轴的Series stocks['公司中文名4'] = stocks.apply(lambda x:dict_company_names[x['公司'].lower()],axis=1) print(stocks.head()) """ 注意这个代码: 1、apply是在stocks这个DataFrame上调用; 2、lambda x的x是一个Series,因为指定了axis=1所以seires的key是列名,可以用x['公司']获取 """ # 3、applymap用于DataFrame所有值的转换 sub_df = stocks[['收盘','开盘','高','低','交易量']] print(sub_df) # 将数值取整数,应用于所有元素 print(sub_df.applymap(lambda x:int(x))) # 直接修改原df的这几列 stocks.loc[:,['收盘','开盘','高','低','交易量']] = sub_df.applymap(lambda x:int(x)) print(stocks.head())
十九、Pandas怎样对每个分组应用apply函数?
知识:Pandas的GroupBy遵从split、apply、comine模式。
这里的split指的是pandas的groupby,我们自己实现apply函数,apply返回的结果由pandas进行combine得到结果GroupBy.apply(function)
function的第一个参数是dataframe
function的返回结果,可是dataframe、series、单个值,甚至和输入dataframe完全没关系
本次实例演示:
1、怎样对数值列按分组的归一化?
2、怎样取每个分组的TOPN数据?
""" 实例一:怎样对数值列按分组的归一化? 归一化:将不同范围的数值列进行归一化,映射到[0,1]区间: 好处:a、更容易做数据横向对比,比如价格字段是几百到几千,增幅字段是0到100 b、机器学习模型学的更快性能更好 归一化的公式: (X - X minimum) X normalized = —————————————————————————— (X maximum - X minimum) 演示:用户对电影评分的归一化 每个用户的评分不同,有的乐观派评分高,有的悲观派评分低,按用户做归一化 """ import pandas as pd # 0、获取数据 # ratings = pd.read_csv( # "datas/ratings.dat", # sep = "::", # engine="python", # names="UserID::MovieID::Rating::Timestamp".split("::") # ) # print(ratings.head()) # 1、封闭函数ratings_norm, 实现按照用户ID分组,然后对其中一列归一化 def ratings_norm(df): """ @param df:每个用户分组的dataframe """ # min_value = df['Rating'].min() # max_value = df['Rating'].max() # # 新增Rating_norm列,保存归一化后的结果 # df['Rating_norm'] = df['Rating'].apply( # # 归一化的公式 # lambda x:(x - min_value) / (max_value - min_value)) # return df # 对 UserID 一列归一化 # ratings = ratings.groupby("UserID").apply(ratings_norm) # print(ratings[ratings['UserID'] == 1].head()) """ 实例2:怎样取每个分组的TOPN数据? 获取2018年每个月温度最高的2天数据 """ fpath = "beijing_tianqi_2018.csv" df = pd.read_csv(fpath) print(df.head()) # 替换掉温度的后缀℃ df['bWendu'] = df['bWendu'].str.replace('℃','').astype('int32') df['yWendu'] = df['yWendu'].str.replace('℃','').astype('int32') print(df.head()) # 新增一列为月份 df['month'] = df['ymd'].str[:7] print(df.head()) def getWenduTopN(df,topn): """ 这里的df,是每个月份分组group的df """ # 降序排序后,用切片语法,[-topn:]取最后的值 return df.sort_values(by='bWendu')[['ymd','bWendu']][-topn:] # 获取月份中列中最高温度三天的数据 print(df.groupby("month").apply(getWenduTopN,topn=3).head()) # 我们看到,grouby的apply函数返回的dataframe,其实和原来的dataframe其实可以完全不一样
二十、Pandas的stack和pivot实现数据透视
将列式数据变成二维交叉形式,便于分析,叫做重塑或透视
1、经过统计得到多维度指标数据
2、使用unstack实现数据二维透视
3、使用pivot简化透视
4、stack、unstack、pivot的语法
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 1、经过统计得到多维度指标数据 """ 非常场景的统计场景,指定多个维度,计算聚合后的指标 实例:统计得到电影评分数据集,每个月份的每个分数被评分多少次:(月份,分数1~5,次数) """ # 获取数据 df = pd.read_csv( "datas/ratings.dat", header=None, sep="::", engine="python", names="UserID::MovieID::Rating::Timestamp".split("::") ) print(df.head()) # 新增列,更改时间格式 df['pdata'] = pd.to_datetime(df['Timestamp'],unit='s') # print(df.head()) # print(df.dtypes) # 实现数据统计 df_group = df.groupby([df['pdata'].dt.month,'Rating'])['UserID'].agg(pv=np.sum) # print(df_group.head()) """ 对这样格式的数据,我想查看按月份,不同评分的次数趋势,是没法实现的 需要将数据变成每个评分是一列才可以实现 """ # 2、使用unstack实现数据二维透视 # 目的:想要画图对比按照月份的不同评分的数量趋势 # df_stack = df_group.unstack() # print(df_stack) # df_stack.plot() # plt.show() # unstack和stack是互逆操作 # print(df_stack.stack().head()) # 3、使用pivot简化透视 # print(df_group.head()) df_reset = df_group.reset_index() # print(df_reset.head()) df_pivot = df_reset.pivot("pdata","Rating","pv") print(df_pivot.head()) df_pivot.plot() plt.show() # pivot方法相当于对df使用set_index创建分层索引,然后调用unstack # 4、stack、unstack、pivot的语法 """ stack: DataFrame.stack(level=-1,dropna=True), 将column变成index,类似把横放的书籍变成竖放 level=-1代表多层索引的最内层,可以通过==0、1、2指定多层索引的对应层 unstack: DataFrame.unstack(level=-1,fill_value=None), 将index变成column,类似把竖放的书籍变成横放 pivot: DataFrame.pivot(index=None,columns=None,values=None), 指定index、columns、values实现二维透视 """