pandas是python中一个数据处理和科学分析的工具,它能做的很多,不过最为强大的就是数据处理。由于它可以很轻松的处理excel数据,所以,也是自动化办公的一个神器,也是我学习的主要目标。
安装 使用pip来安装pandas,pip需要先配置国内源,不然下载速度很慢
处理excel数据,还需要一个插件(openpyxl)来读取/写入excel
1 2 # openpyxl (3.0.3) - A Python library to read /write Excel 2010 xlsx/xlsm files pip install openpyxl
三种数据结构
数据结构
维度
特点
Series
一维
同构(数据类型相同),表示一列column
DataFrame
二维
异构,表示一个表格table
Panel
三维
异构,使用的少
由于具有DataFrame这种二维数据结构,所以可以处理很多类似数据结构的文件,比如:excel,sql,json等
简单读取写入 读取数据的时候可以直接指定index列index_col=
数据如果太长显示不了,可以设置显示宽度pandas.options.display.max_columns=num
excel 1 2 3 4 5 6 7 8 9 10 import pandas as pddata = {"name" :["韩信" ,"李白" ,"杜甫" ], "age" :[21 ,22 ,24 ], "score" :[80 ,90 ,100 ]} df = pd.DataFrame(data) df.to_excel('/home/narcissus/Desktop/1.xlsx' ) pe = pd.read_excel("/home/narcissus/Desktop/1.xlsx" , index_col='name' ) print(pe)
mysql 需要安装数据库连接驱动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import pandasimport pymysqlhost = '192.168.0.105' user = 'pi' password = input("password for mysql connection: " ) database = 'mytestdb' con = pymysql.connect(host,user,password,database) df = pd.read_sql_query('select * from ssacount limit 0,10' ,con) print(df) df.to_excel('~/Desktop/1.xlsx' )
sqlite 1 2 3 4 5 import sqlite3con = sqlite3.connect("testdatabase.db" ) df = pd.read_sql_query("SELECT * FROM ssacount" , con) print(df)
json 1 df = pd.read_json('test.json' )
csv/tsv/txt pandas只有一个read_csv()
函数,但是却可以读取这三种文件(文本文件都可以),默认读取csv文件,其分隔符为逗号,所以在读取tsv和txt的时候,要手动设置分隔符sep=''
1 2 3 df = pd.read_csv('1.csv' ) df = pd.read_csv('1.tsv' , sep='\t' ) df = pd.read_csv('1.txt' , sep='文件中的特殊分隔符号' )
写入 值得注意的是在写入文件之前要确保去掉默认的index,需要设置成自己指定的index,否则再读取文件时,会有一个unamed的列(之前的index列)。其实可以用后面学习的skiprows
在读取时指定跳过多少行,以及usecols
来跳过指定列
1 2 3 4 5 6 7 8 9 10 import pandas as pddata = {"name" :["韩信" ,None ,"李白" ,"杜甫" ], "age" :[21 ,None ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) df.set_index('name' , inplace=True ) df.to_excel('~/Desktop/1.xlsx' ) df = pd.read_excel('~/Desktop/1.xlsx' , index_col='name' ) print(df)
1 2 3 4 5 df.to_excel('~/Desktop/1.xlsx' ) df.to_json('~/Desktop/test.json' ) df.to_sql('ssacount' , con)
PS: 按照目前我的理解,pandas可以完美的完成这些数据文件之间的转换。可以将json,数据库中的数据导入到excel中进行可视化操作。
DataFrame 作为最重要的一个部分,DataFrame包含了几百种方法和操作,可以对数据进行任何的分析与处理。
创建 创建的方式比较多,但通常都是使用dict
来创建。
1 2 3 4 5 6 7 8 9 import pandas as pddata = { "name" :["韩信" ,"李白" ,"杜甫" ], "age" :[21 ,22 ,24 ], "score" :[80 ,90 ,100 ] } df = pd.DataFrame(data) print(df)
每一对key-value作为一个Series(column),key作为表头,value作为数据
自己指定index 默认会自动创建一个index列,为从0开始的连续数据。可以自己指定某列为索引列
1 2 3 4 5 df = df.set_index("name" ) df = pd.DataFrame(data, index=['一班' ,'二班' ,'二班' ])
需要注意的是这个index的数据是可以重复的,并不需要唯一性
通过index找出对应数据 可以通过loc
找出来的条件是设置了index,否则无法找到
1 2 3 4 5 6 7 sear = df.loc['一班' ] print(sear) name 韩信 age 21 score 80 Name: 一班, dtype: object
可以看出index与其对应数据也是一个dict
数据类型
即使设置了index,也可以通过默认的index来查找iloc
默认header=0,会使用第0行(index为空)/excel中的第一行作为header,即columns
1 df = pd.read_excel('~/Desktop/1.xlsx' , header=1 )
重新自定义header,能够自定义成功的前提是这个文件本身就没有header,否则原来的header会作为一个数据行成为index=0的那一行
1 2 3 4 5 df = pd.read_excel('~/Desktop/1.xlsx' , header=None ) df = df[[1 ,3 ]] df.columns = [1 ,2 ]
查看开头和结尾 1 2 3 4 5 6 7 df.head() df.tail() df.head(20 ) df.tail(20 )
查看数据信息 .info()
提供了很重要的一些信息,包括行,列,数据是否为空,数据类型,内存占用等
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import pandas as pddata = {"name" :["韩信" ,"李白" ,"杜甫" ], "age" :[21 ,22 ,24 ], "score" :[80 ,80 ,100 ]} df = pd.DataFrame(data) info = df.info() print(info) <class 'pandas .core .frame .DataFrame '> RangeIndex : 3 entries, 0 to 2 Data columns (total 3 columns): --- ------ -------------- ----- 0 name 3 non-null object 1 age 3 non-null int64 2 score 3 non-null int64 dtypes: int64(2 ), object(1 ) memory usage: 200.0 + bytes None
查看行列数 .shape
提供了一个简单快速查看总行数,列数的信息(rows,columns)
1 2 3 4 info = df.shape print(info) (3 ,3 )
添加与去重 添加DataFrame
df.append()
pandas.concat([])
.append()
可以将已有的DataFrame追加。但是index不会自动变化,要是index自动变化,需要调用reset_index(drop=True)
append如果需要将Series追加到行后面,必须加一个参数ignore_index=True
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import pandas as pdimport pymysqldata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) tmp_df = df.append(df) print(tmp_df) name age score 0 韩信 21 80 1 韩信 21 80 2 李白 22 80 3 杜甫 24 100 0 韩信 21 80 1 韩信 21 80 2 李白 22 80 3 杜甫 24 100
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import pandas as pddata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) tmp_df = df.append(df).reset_index(drop=True ) print(tmp_df) name age score 0 韩信 21 80 1 韩信 21 80 2 李白 22 80 3 杜甫 24 100 4 韩信 21 80 5 韩信 21 80 6 李白 22 80 7 杜甫 24 100
使用concat默认y轴添加,使用axis=1则x轴添加
1 2 3 4 5 6 import pandas as pddata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) tmp_df = pd.concat([df,df], axis=0 ).reset_index(drop=True ) print(tmp_df)
添加Series 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import pandas as pddata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) add = pd.Series({'name' :'筱倩' , 'age' :30 , 'score' :88 }) df = df.append(add, ignore_index=True ) print(df) name age score 0 韩信 21 80 1 韩信 21 80 2 李白 22 80 3 杜甫 24 100 4 筱倩 30 88
添加列 1 2 df['column_name' ] = [] tmp_df['add' ] = [i for i in range(max(tmp_df.index)+1 )]
找到重复数据 df.dumpllicateed(subset='column_name')
可以找出指定列的重复index,和True/False的Series。那么如何通过index来找到真正的重复数据?可以通过循环,其实更加简单的方式是使用df.iloc[index]
定位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import pandas as pdimport pymysqldata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) dum = df.duplicated(subset='name' ) print(dum.any()) dum = dum[dum == True ] info = df.iloc[dum.index] print(info) True name age score 1 韩信 21 80
去重 .drop_duplicates()
可以将追加的重复数据清除,需要加上inplace=True
这个参数,否则不会生效。
默认会对整个表的数据进行去重,如果需要对指定列,那么添加参数subset='column_name'
1 2 3 4 5 6 tmp_df.drop_duplicates(subset='score' , inplace=True ) name age score 0 韩信 21 80 2 李白 22 80 3 杜甫 24 100
.drop_duplicates()
的keep
参数:
first,保留第一次出现的,默认
last,保留最后一次出现的
False,去除所有重复数据
1 2 3 4 5 6 tmp_df.drop_duplicates(inplace=True , keep='first' ) name age score 0 韩信 21 80 2 李白 22 80 3 杜甫 24 100
1 2 3 4 5 6 tmp_df.drop_duplicates(inplace=True , keep='last' ) name age score 1 韩信 21 80 2 李白 22 80 3 杜甫 24 100
1 2 3 4 5 tmp_df.drop_duplicates(inplace=True , keep=False ) Empty DataFrame Columns: [name, age, score] Index: []
修改 通过df[‘column_name’]/df.column_name可以获取Series,通过Series[index]可以获取到指定的值
1 2 3 4 5 6 7 8 9 10 11 12 13 import pandas as pddata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) df.name[1 ] = '筱倩' df.age[1 ] = 99 print(df) name age score 0 韩信 21 80 1 筱倩 99 80 2 李白 22 80 3 杜甫 24 100
替换 使用到了df.iloc[index]
定位,并用Series进行替换
1 2 3 4 5 6 7 import pandas as pddata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) alert = pd.Series({'name' :'筱倩' , 'age' :30 , 'score' :88 }) df.iloc[1 ] = alert print(df)
插入 行 使用到了df[]切片以及追加操作。值得注意的是:在python中可以对list进行切片,但是在pandas中还可以对DataFrame这种二维数据进行切片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import pandas as pddata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) insert = pd.Series({'name' :'筱倩' , 'age' :30 , 'score' :88 }) part1 = df[:2 ] part2 = df[2 :] df = part1.append(insert, ignore_index=True ).append(part2).reset_index(drop=True ) print(df) name age score 0 韩信 21 80 1 韩信 21 80 2 筱倩 30 88 3 李白 22 80 4 杜甫 24 100
列 1 2 df.insert(num, column='column_name' , value=[])
删除 行 两种方法:
使用到了df.drop(index=[], inplace=True)
可以使用切片,将需要的数据切出来然后append组合
1 2 3 4 5 6 7 8 9 10 11 12 import pandas as pddata = {"name" :["韩信" ,"韩信" ,"李白" ,"杜甫" ], "age" :[21 ,21 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) insert = pd.Series({'name' :'筱倩' , 'age' :30 , 'score' :88 }) part1 = df[:1 ] part2 = df[2 :] df.drop(index=2 , inplace=True ) print(df)
列 1 df.drop(columns=[],inplace=True )
columns .columns
可获取所有列名,返回的是一个列表
1 2 3 print(df.columns) Index(['name' , 'age' , 'score' ], dtype='object' )
.rename()
可修改列名
1 df.rename(columns={'name' :'Name' , 'age' :'AGE' }, inplace=True )
col.lower()
搭配列表生成式可以转换小写
1 df.columns = [col.lower() for col in df.columns]
Null数据行清除 .isnull()
找出null数据,null数据显示True,非空数据显示False
.sum()
计算总的null数据
1 print(df.isnull().sum())
.dropna()
删除有null数据的行,只要有一个null数据就会清除
可以看到这种清除数据的缺点,无法对指定列的Null数据进行清除,所以需要使用到过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import pandas as pddata = {"name" :["韩信" ,None ,"李白" ,"杜甫" ], "age" :[21 ,21 ,None ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data).fillna(0 ) miss = df.loc[df.name == 0 ].index df.drop(index=miss, inplace=True ) print(df) name age score 0 韩信 21.0 80 2 李白 0.0 80 3 杜甫 24.0 100
Null数据列的清除 .dropna(axis=1)
使用了一个参数axis
1 df.dropna(inplace=True , axis=1 )
为什么是1?在我们使用df.shape的时候返回一个tuple,(rows,columns),可以看出columns的索引为1
使用mean来填充null数据列 .fillna(column_name, inplace=True)
如果将有null的数据列都删除的话, 那么数据的缺失会比较大,可以用平均值来填充
1 2 3 4 5 6 7 8 9 10 11 12 import pandas as pddata = {"name" :["韩信" ,None ,"李白" ,"杜甫" ], "age" :[21 ,None ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} df = pd.DataFrame(data) age = df['age' ] age_mean = age.mean() age.fillna(age_mean, inplace=True ) print(df)
获取数据描述 前面用.info()
获取了对DataFrame的描述,但是.describe()
可以获取关于数据的描述:包括最大值,最小值,平均值,列数,行数等。既可以是整个DataFrame,也可以是某一列。
1 2 3 4 print(df.describe()) print(df['age' ].describe())
查看某列数据相同数据的个数 .value_counts()
指定列的数据出现个数
1 print(df['score' ].value_counts())
重组DataFrame type(df['age'])
的类型是一个serise,而type(df[['age']])
的类型是一个DataFrame,所以可以使用这种方式来重新选取需要的列构成新的DataFrame
1 2 new_df = df[['name' , 'age' ]] print(new_df)
数据的过滤 在Series的基础上过滤 用条件判断来过滤数据:> < == !=
等
1 2 3 4 5 6 7 8 info = (df['score' ] == 80 ) print(info) 0 True 1 True 2 True 3 False
如果想要直接得到过滤后的数据
1 2 3 4 5 6 7 info = df[df['score' ] == 80 ] print(info) name age score 0 韩信 21.0 80 1 None NaN 80 2 李白 22.0 80
还可以使用逻辑判断
1 info = df[(df['score' ] > 80 ) | (df['age' ] == 22 )]
使用isin()
更加简洁
1 info = df[df['age' ].isin([21 ,22 ])]
上面的所有方法都很简洁,但是数据量比较大的时候,效率就比较低
所以我们需要使用函数来进行过滤,使用.apply()
将column传递给函数
1 2 3 4 5 6 7 8 9 10 def filter_score (x) : if x == 100 : return True else : return False info = df.loc[df['score' ].apply(filter_score)] info = df[df['score' ].apply(filter_score)] info = df[df.score.apply(filter_score)]
可以使用匿名函数简化
1 2 3 info = df[df['score' ].apply(lambda x : x == 100 )] info = df[df.score.apply(lambda x : x == 100 )]
在DataFrame基础上过滤 axis=1
表示每一行(x轴),axis=0
表示每一列(y轴)
1 2 3 4 5 6 7 8 def filter_score (x) : if x.score == 100 : return True else : return False info = df.apply(filter_score, axis=1 ) print(info)
从指定行或列开始读取 可能表格并不是从第一行第一列开始写的,所以需要指定从哪里开始读取,否则会出现许多的unamed row和Nan值
1 2 3 4 5 6 7 8 9 10 11 12 import pandas as pd df = pd.read_excel('~/Desktop/1.xlsx' ) print(df) Unnamed: 0 Unnamed: 1 Unnamed: 2 Unnamed: 3 0 NaN name age score1 0.0 韩信 21 80 2 1.0 韩信 22 80 3 2.0 李白 22 80 4 3.0 杜甫 24 100
使用skiprows(num)
和usecols=[]
来选取需要的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 import pandas as pd df = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=[1 ,2 ,3 ]) df = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=['name' ,'age' ,'score' ]) print(df) name age score 0 韩信 21 80 1 韩信 22 80 2 李白 22 80 3 杜甫 24 100
自动填充功能 用python来实现excel中拖拽自动填充的功能,生成序列数据进行填充,比较复杂的是日期的处理
连续数据:list赋值
交叉数据:三目运算
日期数据:自定义函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 import pandas as pdfrom datetime import date,timedeltadata = {'name' :['李白' ,'杜甫' ,'白居易' ,'王维' ], 'age' :[None ,None ,None ,None ], 'birthday' :[None ,None ,None ,None ], 'drink' :[None ,None ,None ,None ]} df = pd.DataFrame(data) print(df) ======================================================================================= name age birthday drink 0 李白 None None None 1 杜甫 None None None 2 白居易 None None None 3 王维 None None None ======================================================================================= start = date(1600 ,1 ,31 ) def add_month (start_date, add_month) : tmonth = start_date.month + add_month cyear = start_date.year + tmonth // 12 cmonth = 12 if tmonth % 12 == 0 else tmonth % 12 cday = start_date.day if cday > 28 : if cmonth == 2 : cday = 29 if cyear % 4 == 0 and cyear % 100 != 0 or cyear % 400 == 0 else 28 elif cday == 31 and cmonth in [1 ,3 ,5 ,7 ,8 ,10 ,12 ]: cday = 31 elif cday == 31 and cmonth in [2 ,4 ,6 ,9 ,11 ]: cday = 30 return date(cyear,cmonth,cday) df['age' ] = [i+20 for i in range(df.shape[1 ])] for i in df.index: df['drink' ][i] = 'like' if i % 2 == 0 else 'hate' df['birthday' ][i] = start + timedelta(days=i) df['birthday' ][i] = date(start.year+i, start.month, start.day) df['birthday' ][i] = add_month(start,i+10 ) print(df) ======================================================================================= name age birthday drink 0 李白 20 1600 -11 -30 like1 杜甫 21 1601 -12 -31 hate2 白居易 22 1601 -01 -31 like3 王维 23 1601 -02 -28 hate=======================================================================================
计算功能 x轴向乘法 使用到了pandas特有的list相乘,以及list展开相乘(这在python语法中是没有的,乘也是list的复制)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 sr1 = pd.Series([21 ,18 ,22 ,24 ]) sr2 = pd.Series([80 ,80 ,80 ,100 ]) df = pd.DataFrame({'A' :sr1, 'B' :sr2}) print(df) df['C' ] = df['A' ] * df['B' ] df['D' ] = df['C' ] * 100 df['E' ] = df['B' ].apply(lambda x:x+2 ) print(df) A B 0 21 80 1 18 80 2 22 80 3 24 100 A B C D E 0 21 80 1680 168000 82 1 18 80 1440 144000 82 2 22 80 1760 176000 82 3 24 100 2400 240000 102
x轴向求和/平均 前面都是使用的Series来进行计算的,如果需要的不止一列的数据呢?比如说需要每一行的和和平均值,当然也可以将所有列写出来计算,但是有点麻烦,其实可以指定轴。它会自动过滤掉文字列,只计算数字列。(索引不会计算)
axis=1
指定x轴,按行计算,从上到下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import pandas as pddf1 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet1' ) df2 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet2' ) table = df1.join(df2, how='left' ).fillna(0 ) table['qq' ] = table['qq' ].astype(int) table['sum' ] = table.sum(axis=1 ) table['mean' ] = table.mean(axis=1 ).astype(int) print(table) name age score student qq sum mean 0 韩信 21 80 韩信 124242423 124242524 62121262 1 赵云 22 10 赵云 12342356 12342388 6171194 2 李白 22 30 李白 574534563 574534615 287267307 3 杜甫 24 100 杜甫 6785842 6785966 3392983 4 曹操 18 75 曹操 34563342 34563435 17281717 5 姜尚 45 75 姜尚 57845262 57845382 28922691 6 阿狗 23 11 阿狗 45645834 45645868 22822934 7 筱倩 3 99 筱倩 58364743 58364845 29182422 8 夫子 123 107 夫子 4824854834 4824855064 2412427532 9 葛聂 33 90 0 0 123 61
y轴向求和/平均并添加到DataFrame
必须设置ignore_index=True
,否则无法添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import pandas as pddf1 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet1' ) df2 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet2' ) table = df1.join(df2, how='left' ).fillna(0 ) table['qq' ] = table['qq' ].astype(int) total = table.mean() sum = table.sum() total['name' ] = '平均值' sum['name' ] = '总和' table = table.append([total,sum], ignore_index=True ).fillna('' ) print(table) name age score student qq 0 韩信 21.0 80.0 韩信 1.242424e+08 1 赵云 22.0 10.0 赵云 1.234236e+07 2 李白 22.0 30.0 李白 5.745346e+08 3 杜甫 24.0 100.0 杜甫 6.785842e+06 4 曹操 18.0 75.0 曹操 3.456334e+07 5 姜尚 45.0 75.0 姜尚 5.784526e+07 6 阿狗 23.0 11.0 阿狗 4.564583e+07 7 筱倩 3.0 99.0 筱倩 5.836474e+07 8 夫子 123.0 107.0 夫子 4.824855e+09 9 葛聂 33.0 90.0 0 0.000000e+00 10 平均值 33.4 67.7 5.739179e+08 11 总和 334.0 677.0 5.739179e+09
排序 .sort_values(by=[],inplace=True,ascending=[False])
默认生成一个新的DataFrame,使用inplace=True在原DataFrame上修改
默认使用升序排列,用ascending=False来降序排列
对一列数据进行排序
1 2 3 4 5 6 7 8 import pandas as pdsr2 = pd.Series([21 ,18 ,22 ,22 ,24 ]) sr3 = pd.Series([80 ,80 ,60 ,80 ,100 ]) df = pd.DataFrame({'A' :sr2, 'B' :sr3}) df.set_index('A' , inplace=True ) df.sort_values(by='A' , inplace=True , ascending=False ) print(df)
对多列数据进行排序,而且第一列倒序,第二列升序
1 2 3 4 5 6 7 8 import pandas as pdsr2 = pd.Series([21 ,18 ,22 ,22 ,24 ]) sr3 = pd.Series([80 ,80 ,60 ,80 ,100 ]) df = pd.DataFrame({'A' :sr2, 'B' :sr3}) df.set_index('A' , inplace=True ) df.sort_values(by=['A' ,'B' ], inplace=True , ascending=[False ,True ]) print(df)
数据相关性 之前在一篇文章中看到df.corr()
时,没看懂它到底什么意思,有什么作用。今天看了老师讲的视频,才发现这个东西超级无敌厉害。它就是分析一个表中每两列数据之间的相关性的。
1 2 3 4 5 6 7 8 9 10 11 12 import pandas as pdsr2 = pd.Series([21 ,18 ,22 ,22 ,24 ]) sr3 = pd.Series([80 ,80 ,60 ,80 ,100 ]) df = pd.DataFrame({'age' :sr2, 'score' :sr3}) df.corr() age score age 1.000000 0.322749 score 0.322749 1.000000
从不同sheet页读取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import pandas as pddf1 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet1' ) df2 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet2' ) print(df1) print(df2) name age score 0 韩信 21 80 1 赵云 22 10 2 李白 22 30 3 杜甫 24 100 4 曹操 18 75 5 姜尚 45 75 6 阿狗 23 11 7 筱倩 3 99 8 夫子 123 107 9 葛聂 33 90 name qq 0 韩信 124242423 1 赵云 12342356 2 李白 574534563 3 杜甫 6785842 4 曹操 34563342 5 姜尚 57845262 6 阿狗 45645834 7 筱倩 58364743 8 夫子 4824854834
多表联合查询 用到了与数据库类似的操作,merge两个DataFrame,默认为inner join,可以设置left/right join
df.merge()
需要指定关联的列,具有内连接,左/右连接
df.join()
默认使用index作为关联的列,不具有内连接,左/右连接
pandas.concat([],axis=num)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import pandas as pddf1 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet1' ) df2 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet2' ) table = df1.merge(df2, on='name' ) print(table) name age score qq 0 韩信 21 80 124242423 1 赵云 22 10 12342356 2 李白 22 30 574534563 3 杜甫 24 100 6785842 4 曹操 18 75 34563342 5 姜尚 45 75 57845262 6 阿狗 23 11 45645834 7 筱倩 3 99 58364743 8 夫子 123 107 4824854834
可以发现默认是使用的inner join,要df1的数据全部显示出来,使用left join方式
1 table = df1.merge(df2, how='left' , on='name' )
如果要关联的两张表的columns名字不同,那么不能使用on
,而需要使用left_on='',right_on=''
来连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 name age score 0 韩信 21 80 1 赵云 22 10 2 李白 22 30 3 杜甫 24 100 4 曹操 18 75 5 姜尚 45 75 6 阿狗 23 11 7 筱倩 3 99 8 夫子 123 107 9 葛聂 33 90 student qq 0 韩信 124242423 1 赵云 12342356 2 李白 574534563 3 杜甫 6785842 4 曹操 34563342 5 姜尚 57845262 6 阿狗 45645834 7 筱倩 58364743 8 夫子 4824854834
关联之后数据会出现Nan值,使用fillna()
函数来填充null
如果显示的是小数或者科学计数,可以使用astype()
设置为数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import pandas as pddf1 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet1' ) df2 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet2' ) table = df1.merge(df2, how='left' , left_on='name' , right_on='student' ).fillna(0 ) table['qq' ] = table['qq' ].astype(int) print(table) name age score student qq 0 韩信 21 80 韩信 124242423 1 赵云 22 10 赵云 12342356 2 李白 22 30 李白 574534563 3 杜甫 24 100 杜甫 6785842 4 曹操 18 75 曹操 34563342 5 姜尚 45 75 姜尚 57845262 6 阿狗 23 11 阿狗 45645834 7 筱倩 3 99 筱倩 58364743 8 夫子 123 107 夫子 4824854834 9 葛聂 33 90 0 0
使用join()
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import pandas as pddf1 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet1' ) df2 = pd.read_excel('~/Desktop/1.xlsx' , sheet_name='Sheet2' ) table = df1.join(df2, how='left' ).fillna(0 ) table['qq' ] = table['qq' ].astype(int) print(table) name age score student qq 0 韩信 21 80 韩信 124242423 1 赵云 22 10 赵云 12342356 2 李白 22 30 李白 574534563 3 杜甫 24 100 杜甫 6785842 4 曹操 18 75 曹操 34563342 5 姜尚 45 75 姜尚 57845262 6 阿狗 23 11 阿狗 45645834 7 筱倩 3 99 筱倩 58364743 8 夫子 123 107 夫子 4824854834 9 葛聂 33 90 0 0
数据列分割 使用到了Series.str.split()
方法,另外Series.str
有很多方法可以用,可以对字符串进行各种操作。
1 2 3 4 5 6 7 8 9 import pandas as pd data = {'A' :["hello joyce" for i in range(1 ,8 )]} df = pd.DataFrame(data) info = df.A.str.split(expand=True ) df['first' ] = info[0 ] df['last' ] = info[1 ] print(df)
行列转换 df.transpose()
即可,为了避免旋转后第一行为index,所以在读取的时候需要指定index
1 2 3 4 5 import pandas as pddf = pd.read_excel('~/Desktop/1.xlsx' , index_col='name' ) df = df.transpose() print(df)
提取日期 1 2 3 pandas.DatetimeIndex(df['column_name' ]).year pandas.DatetimeIndex(df['column_name' ]).month pandas.DatetimeIndex(df['column_name' ]).day
分组,聚合 模拟透视表功能
1 2 3 4 import pandas as pdimport numpy as npdf.pivot_table(index='column_name' , columns='column_name' , value='column_name' , aggfunc=np.sum)
分组
1 groups = df.groupby('column_name' )
聚合
1 S = groups['column_name' ].sum()
条件颜色 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import pandas as pd def colorlize (x) : colors = 'orange' if x < 60 else 'lime' return f'color:{colors} ' def another (x) : return ['color:red' if v > 90 else 'background-color:black' for v in x] df = pd.read_excel('~/Desktop/1.xlsx' ) df.style.applymap(colorlize, subset=['age' ,'score' ]).apply(another, subset=['age' ,'score' ])
需要注意的:
df.style.applymap()
获取到的是每一个值
df.style.apply()
获取到的是一个Series,但是需要用for循环读取每一个值,这和之前用的df.apply()
自动循环每一个值不同
颜色条 1 2 3 4 import pandas as pd df = pd.read_excel('~/Desktop/1.xlsx' ) df.style.bar(color='pink' , subset=['age' ,'score' ])
渐变颜色 需要下载seaborn模块
1 2 3 4 5 6 7 import pandas as pd import seaborn as sndf = pd.read_excel('~/Desktop/1.xlsx' ) color_map = sn.light_palette('pink' , as_cmap=True ) df.style.background_gradient(color_map, subset=['age' , 'score' ])
Series Series序列 用来生成一维数据。类似list数据类型
1 2 3 4 5 6 7 8 9 import pandas as pddata = {"name" :["韩信" ,"貂蝉" ,"李白" ,"杜甫" ], "age" :[21 ,18 ,22 ,24 ], "score" :[80 ,80 ,80 ,100 ]} sr = pd.Series(data) print(sr) name [韩信, 貂蝉, 李白, 杜甫] age [21 , 18 , 22 , 24 ] score [80 , 80 , 80 , 100 ]
Series组装DataFrame
使用dict
组装。不指定index时,使用默认的index
1 2 3 4 5 6 7 8 9 10 11 12 13 import pandas as pdsr1 = pd.Series(["韩信" ,"貂蝉" ,"李白" ,"杜甫" ]) sr2 = pd.Series([21 ,18 ,22 ,24 ]) sr3 = pd.Series([80 ,80 ,80 ,100 ]) df = pd.DataFrame({'name' :sr1, 'age' :sr2, 'score' :sr3}) print(df) name age score 0 韩信 21 80 1 貂蝉 18 80 2 李白 22 80 3 杜甫 24 100
还可以手动指定index
1 2 3 4 5 6 7 8 9 10 11 12 13 import pandas as pdsr1 = pd.Series(["韩信" ,"貂蝉" ,"李白" ,"杜甫" ], index=(1 ,2 ,3 ,4 ), name='name' ) sr2 = pd.Series([21 ,18 ,22 ,24 ], index=(1 ,2 ,3 ,4 ), name='age' ) sr3 = pd.Series([80 ,80 ,80 ,100 ], index=(1 ,2 ,3 ,4 )) df = pd.DataFrame({sr1.name:sr1, sr2.name:sr2, sr3.name:sr3}) print(df) name age NaN 1 韩信 21 80 2 貂蝉 18 80 3 李白 22 80 4 杜甫 24 100
使用list
组装。如果不指定index和name,那么会用默认的index来填充columns和index
1 2 3 4 5 6 7 8 9 10 11 12 import pandas as pdsr1 = pd.Series(["韩信" ,"貂蝉" ,"李白" ,"杜甫" ], index=(1 ,2 ,3 ,4 ), name='name' ) sr2 = pd.Series([21 ,18 ,22 ,24 ], index=(1 ,2 ,3 ,4 ), name='age' ) sr3 = pd.Series([80 ,80 ,80 ,100 ], index=(1 ,2 ,3 ,4 ), name='score' ) df = pd.DataFrame([sr1, sr2, sr3]) print(df) 1 2 3 4 name 韩信 貂蝉 李白 杜甫 age 21 18 22 24 score 80 80 80 100
可以发现,使用list来组装DataFrame时,会将Series以行的形式展示。如果用dict来组装,那么会将Series以列的形式组装。
DataFrame取出Series 两种方式:
这种就是python自身的语法,DataFrame由字典组成,所以使用df['column_name']
即可
使用pandas DataFrame数据结构的语法,df.column_name
也可以
制图 pandas是构建于matplotlib之上,所以需要先下载
使用到的数据:
柱状图 第一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 import pandas as pd import matplotlib.pyplot as pltdf = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=[1 ,2 ,3 ,4 ]) df.sort_values(by=['score' ,'age' ], inplace=True , ascending=False ) df.plot.bar(x='name' , y=['score' ,'age' ], color=['lightblue' ,'orange' ]) plt.tight_layout() plt.show()
中文支持 默认matplotlib无法显示中文,需要从matplotlib导入font_manager
1 from matplotlib import font_manager
查看有那些中文字体
1 2 3 4 fc-list :lang=zh /usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc: WenQuanYi Micro Hei,文泉驛微米黑,文泉驿微米黑:style=Regular /usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc: WenQuanYi Micro Hei Mono,文泉驛等寬微米黑,文泉驿等宽微米黑:style=Regular
设置font变量
1 font = font_manager.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" )
在需要显示中文的地方加上fontproperties属性。需要注意只有matplotlib才能加这个属性,所以在需要加这个属性的时候,要用matplotlib来设置
1 plt.xticks(rotation=40 , fontproperties=font)
使用matplotlib修饰 matpllotlib比pandas自带的制图功能要多,可定制性更强。导入matplotlib的作用呢就是来补充pandas自身制图功能的一些不足,以及渲染图片。
由于pandas基于matplotlib,所以这两个可完美的搭配使用。在pandas搞不定的地方就用matplotlib来补充
分组柱状图 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import pandas as pd import matplotlib.pyplot as pltfrom matplotlib import font_managerfont = font_manager.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" ) df = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=[1 ,2 ,3 ,4 ]) df.sort_values(by=['score' ,'age' ], inplace=True , ascending=False ) df.plot.bar(x='name' , y=['score' ,'age' ], color=['lightblue' ,'orange' ]) px = plt.gca() px.set_xticklabels(df['name' ], rotation=20 , ha='right' , fontproperties=font, fontsize=14 ) pf = plt.gcf() pf.subplots_adjust(left=0.1 ) plt.xlabel('name' , fontsize=20 ) plt.ylabel('score' , fontsize=20 ) plt.title('学习情况统计表' , fontproperties=font, fontsize=24 , color='lightpink' ) plt.tight_layout() plt.show()
叠加柱状图
需要自己新计算一个新的列,这个列的值为需要叠加的数据之和
使用这个新的列作为排序的标准
y轴仍然为之前的列
只不过在df.plot.bar显示的时候加了一个参数stacked=True
,声明使用叠加的方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import pandas as pd import matplotlib.pyplot as plt from matplotlib import font_managerfont = font_manager.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" ) df = pd.read_excel('~/Desktop/1.xlsx' , usecols=[1 ,2 ,3 ,4 ,5 ], skiprows=1 ) df['total' ] = df['age' ] + df['score' ] df.sort_values(by='total' , inplace=True , ascending=False ) df.plot.bar(x='name' , y=['score' , 'age' ], color=['brown' ,'pink' ], stacked=True ) px = plt.gca() px.set_xticklabels(df['name' ], rotation=10 , ha='right' , fontproperties=font) plt.xlabel('name' ) plt.ylabel('count' ) plt.title('学习情况统计' , fontproperties=font, fontsize=22 , fontweight='bold' ) plt.show()
水平叠加柱状图 其实只需要改一个参数就可以了,将df.plot.bar
改为df.plot.barh
就代表水平展示了。
这个时候的排序可能需要调整一下
如果自定义了x轴,y轴的话,需要交换一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import pandas as pd import matplotlib.pyplot as plt from matplotlib import font_managerfont = font_manager.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" ) df = pd.read_excel('~/Desktop/1.xlsx' , usecols=[1 ,2 ,3 ,4 ,5 ], skiprows=1 ) df['total' ] = df['age' ] + df['score' ] df.sort_values(by='total' , inplace=True ) df.plot.barh(x='name' , y=['score' , 'age' ], color=['brown' ,'pink' ], stacked=True ) px = plt.gca() px.set_yticklabels(df['name' ], rotation=10 , ha='right' , fontproperties=font) plt.xlabel('count' ) plt.ylabel('name' ) plt.title('学习情况统计' , fontproperties=font, fontsize=22 , fontweight='bold' ) plt.show()
饼图 绘制饼图的优点是可以清晰的看出各部分所占的比例
与柱状图不同,饼图需要的数据为一个Series,同时在读取数据的时候指定的index会成为饼图显示的信息
饼图注意点还挺多的,最为重要的就是使用pandas来绘制,无法显示中文,所以采用了plt来绘制
采用matplotlib时,也无法直接设置字体,需要用循环给具体的对象赋值
对序列排序,并通过绘制时的顺时针来设置旋转方向
通过startangle来设置最大值从12点方向开始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import pandas as pd from matplotlib import font_manager as fm from matplotlib import pyplot as plt font = fm.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" ) df = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=[1 ,2 ,3 ,4 ]) df.sort_values(by='score' , inplace=True ) paint = plt.pie(df['score' ], labels=df['name' ], counterclock=True , startangle=-270 ) for i in df.index: paint[1 ][i].set_fontproperties(font) plt.title('学习情况统计' , fontproperties=font, fontsize=22 , fontweight='bold' ) plt.ylabel('score' , fontsize=16 ) plt.show()
对数据进行排序之后会出现,比例较小的部分字重叠,这也是一个问题。
所以不对其进行排序显示的效果可能会更好。
折线图
折线图在绘制的时候,只要直接使用.plot
就可以了。需要指定y轴的数据
x轴的数据可以通过指定index来设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import pandas as pd from matplotlib import pyplot as plt from matplotlib import font_manager as fm font = fm.FontProperties(fname='/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc' ) data = {'score' :[45 ,76 ,56 ,100 ,93 ], 'age' :[16 ,18 ,24 ,29 ,35 ]} df = pd.DataFrame(data) df.plot(y=['score' ,'age' ]) plt.title('年龄与分数走势图' ,fontproperties=font, fontsize=22 ) plt.xlabel('time' ) plt.xticks(df.index) plt.ylabel('count' ) plt.show()
叠加区域图 只需要在折线图的基础上将.plot
改为.plot.area
即可
1 df.plot.area(y=['score' ,'age' ])
散点图 散点图就可以看出pandas的处理速度完胜excel,同时交换x,y轴数据,pandas可以轻松搞定,而excel在数据量多的时候无法操作。
使用到了df.plot.scatter()
来画散点图
1 2 3 4 5 6 7 8 9 10 import pandas as pdfrom matplotlib import pyplot as pltfrom matplotlib import font_manager as fm font = fm.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" ) df = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=[1 ,2 ,3 ,4 ]) df.plot.scatter(x='score' , y='age' , color='brown' ) plt.title('学习与年龄散点图' , fontproperties=font, fontsize=22 ) plt.show()
分布图 可以清晰的看出指定数据的分布情况。分布图只需要Series就可以
使用了Series.plot.hist(bins=num)
参数bins设置划分区间,越多图越精细
plt.xticks()
设置x轴的分段,默认Series分段少,使用range()函数,来设置步长
1 2 3 4 5 6 7 8 9 10 11 12 import pandas as pdfrom matplotlib import pyplot as pltfrom matplotlib import font_manager as fm font = fm.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" ) df = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=[1 ,2 ,3 ,4 ]) df['score' ].plot.hist(bins=10 ) plt.xticks(range(0 ,max(df['score' ]),4 ), rotation=90 ) plt.xlabel('score' ) plt.title('分数分布图' , fontproperties=font, fontsize=20 ) plt.show()
密度图 直接使用会报错,提示缺少一个scipy的科学库
密度图同样使用Series
使用Series.plot.kde()
,其它与分布图类似
1 2 3 4 5 6 7 8 9 10 11 import pandas as pdfrom matplotlib import pyplot as pltfrom matplotlib import font_manager as fm font = fm.FontProperties(fname="/usr/share/fonts/wenquanyi/wqy-microhei/wqy-microhei.ttc" ) df = pd.read_excel('~/Desktop/1.xlsx' , skiprows=1 , usecols=[1 ,2 ,3 ,4 ]) df['score' ].plot.kde() plt.xlabel('score' ) plt.title('密度分布图' , fontproperties=font, fontsize=20 ) plt.show()
终于一口气学完了这个模块,感觉功能确实很多,而且没学到的功能还有很多。但是就目前掌握的这些来说,写个自动化办公的脚本来说已经够了。数据的读取,增删查改,制图等等功能都很好用。虽然是一边看视频,一边敲代码,但是熟悉程度还不够,还的在日常的生活中多用才会熟练。学完一个东西觉得很开心,但是又觉得有点失落,因为我接下来要学什么呢?是个很大的问题。要不学学powershell吧!