Pandas高频使用技巧
import pandas as pd import numpy as np
导入文件
1.read_excel
Pandas能够读取很多文件:Excel、CSV、数据库、TXT,甚至是在线的文件都是OK的
to_csv
-
DataFrame.to_csv(path_or_buf=None, sep=', ’, columns=None, header=True, index=True, mode='w', encoding=None)
- path_or_buf :文件路径
- sep :分隔符,默认用","隔开
- columns :选择需要的列索引
- header :boolean or list of string, default True,是否写进列索引值
- index:是否写进行索引
- mode:‘w’:重写, ‘a’ 追加
举例:保存读取出来的股票数据
保存’open’列的数据,然后读取查看结果:
# 选取10行数据保存,便于观察数据 data[:10].to_csv("./data/test.csv", columns=['open']) # 读取,查看结果 pd.read_csv("./data/test.csv") Unnamed: 0 open 0 2018-02-27 23.53 1 2018-02-26 22.80 2 2018-02-23 22.88 3 2018-02-22 22.25 4 2018-02-14 21.49 5 2018-02-13 21.40 6 2018-02-12 20.70 7 2018-02-09 21.20 8 2018-02-08 21.79 9 2018-02-07 22.69会发现将索引存入到文件当中,变成单独的一列数据。如果需要删除,可以指定index参数,删除原来的文件,重新保存一次。
下面例子把index指定为False,那么保存的时候就不会保存行索引了:
# index:存储不会将索引值变成一列数据 data[:10].to_csv("./data/test.csv", columns=['open'], index=False)
当然我们也可以这么做,就是把索引保存到文件中,读取的时候变成了一列,那么可以把这个列再变成索引,如下:
# 把Unnamed: 0这一列,变成行索引 open.set_index(["Unnamed: 0"]) # 把索引名字变成index open.index.name = "index"
read_json
-
pandas.read_json(path_or_buf=None, orient=None, typ='frame', lines=False)
- 按照每行读取json对象
- (1)‘split’ : dict like {index -> [index], columns -> [columns], data -> [values]}
- (2)‘records’ : list like [{column -> value}, … , {column -> value}]
- (3)‘index’ : dict like {index -> {column -> value}}
- (4)‘columns’ : dict like {column -> {index -> value}},默认该格式
- (5)‘values’ : just the values array
- split 将索引总结到索引,列名到列名,数据到数据。将三部分都分开了
- records 以columns:values的形式输出
- index 以index:{columns:values}…的形式输出
- colums 以columns:{index:values}的形式输出
- values 直接输出值
path_or_buf
: 路径orient
: string,以什么样的格式显示.下面是5种格式:lines
: boolean, default Falsetyp
: default ‘frame’, 指定转换成的对象类型series或者dataframe
案例:
- 数据介绍:
这里使用一个新闻标题讽刺数据集,格式为json。is_sarcastic:1讽刺的,否则为0;headline:新闻报道的标题;article_link:链接到原始新闻文章。存储格式为:
{"article_link": "https://www.huffingtonpost.com/entry/versace-black-code_us_5861fbefe4b0de3a08f600d5", "headline": "former versace store clerk sues over secret 'black code' for minority shoppers", "is_sarcastic": 0} {"article_link": "https://www.huffingtonpost.com/entry/roseanne-revival-review_us_5ab3a497e4b054d118e04365", "headline": "the 'roseanne' revival catches up to our thorny political mood, for better and worse", "is_sarcastic": 0}
- 读取
orient指定存储的json格式,lines指定按照行去变成一个样本:
json_read = pd.read_json("./data/Sarcasm_Headlines_Dataset.json", orient="records", lines=True)
结果为:
创建DataFrame
在以前的文章中介绍过10种DataFrame的方法
Series的创建
Series是一个类似于一维数组的数据结构,它能够保存任何类型的数据,比如整数、字符串、浮点数等,主要由一组数据和与之相关的索引两部分构成。
# 导入pandas import pandas as pd pd.Series(data=None, index=None, dtype=None)
- 参数:
- data:传入的数据,可以是ndarray、list等
- index:索引,必须是唯一的,且与数据的长度相等。如果没有传入索引参数,则默认会自动创建一个从0-N的整数索引。
- dtype:数据的类型
通过已有数据创建:
-
(1)指定内容,默认索引:
pd.Series(np.arange(10))
# 运行结果 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 dtype: int64
(2)指定索引:
pd.Series([6.7,5.6,3,10,2], index=[1,2,3,4,5])
# 运行结果 1 6.7 2 5.6 3 3.0 4 10.0 5 2.0 dtype: float64
(3)通过字典数据创建
color_count = pd.Series({'red':100, 'blue':200, 'green': 500, 'yellow':1000}) color_count
# 运行结果 blue 200 green 500 red 100 yellow 1000 dtype: int64
(2)Series的属性
为了更方便地操作Series对象中的索引和数据,Series中提供了两个属性index和values:
index:
color_count = pd.Series({'red':100, 'blue':200, 'green': 500, 'yellow':1000}) color_count.index # 结果 Index(['blue', 'green', 'red', 'yellow'], dtype='object')
values:
color_count.values # 结果 array([ 200, 500, 100, 1000])
也可以使用索引来获取数据:
color_count[2] # 结果 100
MultiIndex
(1)MultiIndex
MultiIndex是三维的数据结构;
多级索引(也称层次化索引)是pandas的重要功能,可以在Series、DataFrame对象上拥有2个以及2个以上的索引。
- (1)multiIndex的特性
打印刚才的df的行索引结果
df sale year month 2012 1 55 2014 4 40 2013 7 84 2014 10 31 df.index MultiIndex(levels=[[2012, 2013, 2014], [1, 4, 7, 10]], labels=[[0, 2, 1, 2], [0, 1, 2, 3]], names=['year', 'month'])
多级或分层索引对象。
- index属性
- names:levels的名称
- levels:每个level的元组值
df.index.names # FrozenList(['year', 'month']) df.index.levels # FrozenList([[2012, 2013, 2014], [1, 4, 7, 10]])
(2)multiIndex的创建
arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']] pd.MultiIndex.from_arrays(arrays, names=('number', 'color')) # 结果 MultiIndex(levels=[[1, 2], ['blue', 'red']], codes=[[0, 0, 1, 1], [1, 0, 1, 0]], names=['number', 'color'])
T 转置
data.T
删除列
删除一些列,让数据更简单些,再去做后面的操作 data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)
赋值操作
对DataFrame当中的close列进行重新赋值为1。
# 直接修改原来的值 data['close'] = 1 # 这一列都变成1 # 或者 data.close = 1
查看头尾数据
头尾都是默认5行数据,可以指定行数
# df2.head() 默认头部5行 df2.head(3) # 指定3行 # df2.tail() 默认尾部5行 df2.tail(2) # 指定尾部2行
显示全部列名
显示索引
查看列的数据类型
查看行列数
查看数据大小
查看缺失值
修改列名
两种方式:使用rename函数和直接使用columns属性
统计元素
统计每个元素的个数
转成列表数据
提取列中数据
提取文本数据
数值范围数据提取
提取整列数据
缺失值填充
1、替换缺失值:fillna(value, inplace=True)
- value:替换成的值
- inplace:True:会修改原数据,False:不替换修改原数据,生成新的对象
- 指定填充的值
- 用计算值
- 用其他值
2.删除存在缺失值的:dropna(axis='rows')
注:不会修改原数据,需要接受返回值
判断数据中是否包含NaN:
pd.isnull(df),
-
这个和上面的正好相反,判断是否是缺失值,是则返回True。
# 判断是否是缺失值,是则返回True pd.isnull(movie).head() # 结果: Rank Title Genre Description Director Actors Year Runtime (Minutes) Rating Votes Revenue (Millions) Metascore 0 False False False False False False False False False False False False 1 False False False False False False False False False False False False 2 False False False False False False False False False False False False 3 False False False False False False False False False False False False 4 False False False False False False False False False False False False
这个也不好观察,我们利用np.any()
来判断是否有缺失值,若有则返回True,下面看例子:
np.any(pd.isnull(movie)) # 返回 True
存在缺失值nan:
pd.notnull(df)
# 判断是否是缺失值,是则返回False pd.notnull(movie) # 结果: Rank Title Genre Description Director Actors Year Runtime (Minutes) Rating Votes Revenue (Millions) Metascore 0 True True True True True True True True True True True True 1 True True True True True True True True True True True True 2 True True True True True True True True True True True True 3 True True True True True True True True True True True True 4 True True True True True True True True True True True True 5 True True True True True True True True True True True True 6 True True True True True True True True True True True True 7 True True True True True True True True True True False True
但是上面这样显然不好观察,我们可以借助np.all()
来返回是否有缺失值。np.all()
只要有一个就返回False,下面看例子:
np.all(pd.notnull(movie)) # 返回 False
存在缺失值nan,并且是np.nan 删除或替换
- 1、删除
pandas删除缺失值,使用dropna的前提是,缺失值的类型必须是np.nan
# 不修改原数据 movie.dropna() # 可以定义新的变量接受或者用原来的变量名 data = movie.dropna()
2、替换缺失值
# 替换存在缺失值的样本的两列 # 替换填充平均值,中位数 movie['Revenue (Millions)'].fillna(movie['Revenue (Millions)'].mean(), inplace=True)
替换所有缺失值:
# 这个循环,每次取出一列数据,然后用均值来填充 for i in movie.columns: if np.all(pd.notnull(movie[i])) == False: print(i) movie[i].fillna(movie[i].mean(), inplace=True)
不是缺失值nan,有默认标记的
# 读入数据 wis = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data")
以上数据在读取时,可能会报如下错误:
URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)>
解决办法:
# 全局取消证书验证 import ssl ssl._create_default_https_context = ssl._create_unverified_context
处理思路分析:
- 1、先替换‘?’为np.nan
- to_replace:替换前的值
- value:替换后的值
df.replace(to_replace=, value=)
# 把一些其它值标记的缺失值,替换成np.nan wis = wis.replace(to_replace='?', value=np.nan)
2、再进行缺失值的处理
# 删除 wis = wis.dropna()
3、验证:
np.all(pd.notnull(wis)) # 返回True,说明没有了缺失值 # 或者 np.any(pd.isnull(wis)) # 返回False,说明没有了缺失值
数据去重
计算统计值
计算统计值,比如最值和均值等
算术运算(1)add(other)
比如进行数学运算加上具体的一个数字
data['open'].head().add(1) 2018-02-27 24.53 2018-02-26 23.80 2018-02-23 23.88 2018-02-22 23.25 2018-02-14 22.49 Name: open, dtype: float64
算术运算(2)sub(other)
整个列减一个数
data.open.head().sub(2) 2018-02-27 21.53 2018-02-26 20.80 2018-02-23 20.88 2018-02-22 20.25 2018-02-14 19.49 Name: open, dtype: float64
逻辑运算函数查询字符串
-
(1)
query(expr)
- expr:查询字符串
通过query使得刚才的过程更加方便简单,下面是使用的例子:
data.query("open<24 & open>23").head()
结果:
-
(2)
isin(values)
例如判断’open’是否为23.53和23.85:
# 可以指定值进行一个判断,从而进行筛选操作 data[data["open"].isin([23.53, 23.85])]
对于单个函数去进行统计的时候,坐标轴还是按照默认列“columns” (axis=0, default),如果要对行“index” 需要指定(axis=1)。
(1)max()、min()
# 使用统计函数:0 代表列求结果, 1 代表行求统计结果 data.max(axis=0) # 最大值 open 34.99 high 36.35 close 35.21 low 34.01 volume 501915.41 price_change 3.03 p_change 10.03 turnover 12.56 my_price_change 3.41 dtype: float64
(2)std()、var()
# 方差 data.var(axis=0) open 1.545255e+01 high 1.662665e+01 close 1.554572e+01 low 1.437902e+01 volume 5.458124e+09 price_change 8.072595e-01 p_change 1.664394e+01 turnover 4.323800e+00 my_price_change 6.409037e-01 dtype: float64 # 标准差 data.std(axis=0) open 3.930973 high 4.077578 close 3.942806 low 3.791968 volume 73879.119354 price_change 0.898476 p_change 4.079698 turnover 2.079375 my_price_change 0.800565 dtype: float64
(3)median()
:中位数
中位数为将数据从小到大排列,在最中间的那个数为中位数。如果没有中间数,取中间两个数的平均值。
data.median(axis=0) open 21.44 high 21.97 close 10.00 low 20.98 volume 83175.93 price_change 0.05 p_change 0.26 turnover 2.50 dtype: float64
(4)idxmax()、idxmin()
# 求出最大值的位置 data.idxmax(axis=0) open 2015-06-15 high 2015-06-10 close 2015-06-12 low 2015-06-12 volume 2017-10-26 price_change 2015-06-09 p_change 2015-08-28 turnover 2017-10-26 my_price_change 2015-07-10 dtype: object # 求出最小值的位置 data.idxmin(axis=0) open 2015-03-02 high 2015-03-02 close 2015-09-02 low 2015-03-02 volume 2016-07-06 price_change 2015-06-15 p_change 2015-09-01 turnover 2016-07-06 my_price_change 2015-06-15 dtype: object
累计统计函数
统计函数
看一下min(最小值)
, max(最大值)
, mean(平均值)
, median(中位数)
, var(方差)
, std(标准差)
,mode(众数)
是怎么操作的:
对p_change进行求和
stock_rise = data['p_change'] stock_rise.cumsum() 2015-03-02 2.62 2015-03-03 4.06 2015-03-04 5.63 2015-03-05 7.65 2015-03-06 16.16 2015-03-09 16.37 2015-03-10 18.75 2015-03-11 16.36 2015-03-12 15.03 2015-03-13 17.58 2015-03-16 20.34 2015-03-17 22.42 2015-03-18 23.28 2015-03-19 23.74 2015-03-20 23.48 2015-03-23 23.74
# plot显示图形, plot方法集成了直方图、条形图、饼图、折线图
如果要使用plot函数,需要导入matplotlib.下面是绘图代码:
-
DataFrame.plot(kind='line')
- ‘line’ : 折线图
- ‘bar’ : 条形图
- ‘barh’ : 横放的条形图
- ‘hist’ : 直方图
- ‘pie’ : 饼图
- ‘scatter’ : 散点图
- kind : str,需要绘制图形的种类
import matplotlib.pyplot as plt # plot显示图形, plot方法集成了直方图、条形图、饼图、折线图 stock_rise.cumsum().plot() # 需要调用show,才能显示出结果 plt.show()
结果:
自定义运算apply(func, axis=0)
apply(func, axis=0)
- func:自定义函数
- axis=0:默认是列,axis=1为行进行运算
- 定义一个对列,最大值-最小值的函数
下面看个例子:
data[['open', 'close']].apply(lambda x: x.max() - x.min(), axis=0) open 22.74 close 22.85 dtype: float64
计算中位数
提取最值所在的行
Pandas切片
df2.iloc[22] # 提取某个行的数据 df2.iloc[:,1:6] # 行和列上的切片
大小排序
分组聚合
使用groupby分组之后,对不同的字段可以使用不同的聚合函数
索引重排
注意和上面例子的比较。使用的是reset_index函数
以某列值设置为新的索引
- set_index(keys, drop=True)
- keys : 列索引名成或者列索引名称的列表
- drop : boolean, default True.当做新的索引,删除原来的列
设置新索引案例:
1、创建
f = pd.DataFrame({'month': [1, 4, 7, 10], 'year': [2012, 2014, 2013, 2014], 'sale':[55, 40, 84, 31]}) month sale year 0 1 55 2012 1 4 40 2014 2 7 84 2013
2、以月份设置新的索引
df.set_index('month') sale year month 1 55 2012 4 40 2014 7 84 2013 10 31 2014
3、设置多个索引,以年和月份
df = df.set_index(['year', 'month']) df sale year month 2012 1 55 2014 4 40 2013 7 84 2014 10 31
注:通过刚才的设置,这样DataFrame就变成了一个具有MultiIndex的DataFrame。
去掉原索引
使用索引重排之后我们需要去掉原来的索引;比较上下两个结果的区别。通过drop=True来实现
apply函数
两个列相加
DataFrame合并
1、先看看两个原始数据
2、默认情况:求的两个DF的交集
3、保留左边全部数据
4、保留右边全部数据
how="inner"其实就是默认情况:
导出数据
导出数据的时候通常是不需要索引的
to_json
DataFrame.to_json(path_or_buf=None, orient=None, lines=False)
- 将Pandas 对象存储为json格式
- path_or_buf=None:文件地址
- orient:存储的json形式,{‘split’,’records’,’index’,’columns’,’values’}
- lines:一个对象存储为一行
案例:
- 存储文件
# 不指定lines=Treu,则保存成一行 json_read.to_json("./data/test.json", orient='records')
结果:
[{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0},{"article_link":"https:\/\/local.theonion.com\/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697","headline":"mom starting to fear son's web series closest thing she will have to grandchild","is_sarcastic":1},{"article_link":"https:\/\/politics.theonion.com\/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302","headline":"boehner just wants wife to listen, not come up with alternative debt-reduction ideas","is_sarcastic":1},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb","headline":"j.k. rowling wishes snape happy birthday in the most magical way","is_sarcastic":0},{"article_link":"https:\/\/www.huffingtonpost.com\/entry\/advancing-the-worlds-women_b_6810038.html","headline":"advancing the world's women","is_sarcastic":0},....]
修改lines
参数为True
# 指定lines=True,则多行存储 json_read.to_json("./data/test.json", orient='records', lines=True)
结果:
"article_link":"https:\/\/www.huffingtonpost.com\/entry\/versace-black-code_us_5861fbefe4b0de3a08f600d5","headline":"former versace store clerk sues over secret 'black code' for minority shoppers","is_sarcastic":0} {"article_link":"https:\/\/www.huffingtonpost.com\/entry\/roseanne-revival-review_us_5ab3a497e4b054d118e04365","headline":"the 'roseanne' revival catches up to our thorny political mood, for better and worse","is_sarcastic":0} {"article_link":"https:\/\/local.theonion.com\/mom-starting-to-fear-son-s-web-series-closest-thing-she-1819576697","headline":"mom starting to fear son's web series closest thing she will have to grandchild","is_sarcastic":1} {"article_link":"https:\/\/politics.theonion.com\/boehner-just-wants-wife-to-listen-not-come-up-with-alt-1819574302","headline":"boehner just wants wife to listen, not come up with alternative debt-reduction ideas","is_sarcastic":1} {"article_link":"https:\/\/www.huffingtonpost.com\/entry\/jk-rowling-wishes-snape-happy-birthday_us_569117c4e4b0cad15e64fdcb","headline":"j.k. rowling wishes snape happy birthday in the most magical way","is_sarcastic":0}...
实现行转列
第一种:
# 遇事不要慌,先导个包吧 import pandas as pd import numpy as np # 造假数据 data = {'name':['严小样儿','严小样儿','严小样儿','才华横竖都溢','才华横竖都溢','才华横竖都溢','幽兰幽香','幽兰幽香','幽兰幽香'], 'subject':['Python','C','SQL','Python','C','SQL','Python','C','SQL'], 'score':[95,60,95,96,95,80,99,94,88]} # 生成df df = pd.DataFrame(data) df
使用pivot方法即可完成行转列哦~语法如下:
#df.pivot(index=None, columns=None, values=None) df.pivot(index='name',columns='subject',values='score')
不要高兴的太早,遇到重复值就麻烦了!少侠请看:
# 造含有重复值的假数据 data1 = {'name':['严小样儿','严小样儿','严小样儿','严小样儿','才华横竖都溢','才华横竖都溢','才华横竖都溢','幽兰幽香','幽兰幽香','幽兰幽香'], 'subject':['Python','Python','C','SQL','Python','C','SQL','Python','C','SQL'], 'score':[95,95,60,95,96,95,80,99,94,88]} df1 = pd.DataFrame(data1) df1
df1.pivot(index='name',columns='subject',values='score') # 一旦有重复值,就会报错。 ValueError: Index contains duplicate entries, cannot reshape
别急别急,去个重不就可以了吗?!
df1.drop_duplicates().pivot(index='name',columns='subject',values='score')
方法二:数据透视表
# pivot_table(data, values=None, index=None, columns=None, aggfunc='mean') pd.pivot_table(df1,index='name',columns='subject',values='score',aggfunc={'score':'max'})
聚合
刚刚说了,要求每个人的总分,其实使用透视表就可以完成。
不过,稍微动动脑筋哦。遇到重复值数据的话,只能使用下面的方法一,去重后的数据集,方法一,二都支持。
计算每个人的总分,语法如下:
# 重复数据集也可以 df_pivot = pd.pivot_table(df1,index='name',columns='subject',values='score',aggfunc={'score':'max'}) # 增加一个新列:Total df_pivot['Total'] = df_pivot.apply(lambda x:np.sum(x),axis = 1) df_pivot
方法二,必须是去重后的数据集,否则会出现计算错误。
# 使用去重数据集才可以 pd.pivot_table(df,index='name',values='score',aggfunc='sum')
# 使用join方法把总分列加进去。 total = pd.pivot_table(df,index='name',values='score',aggfunc='sum') pd.pivot_table(df,index='name',columns='subject',values='score').join(total)
--需求方:算是算出来了,可是,这个score看着怪怪的,能不能改成“总分”呢?
--严小样儿:我改(卑微)!安排~
total1 = pd.pivot_table(df,index='name',values='score',aggfunc='sum').rename({'score':'总分'},axis=1) pd.pivot_table(df,index='name',columns='subject',values='score').join(total1)