Python __ Pandas
简介
可以看做是Excel
是基于Numpy的.
优点:处理表格数据(混杂数据)
需要引用:import pandas as pd
Series(无用)
类似于Numpy的一维数组
优点:相较于Nump索引功能强大
输出默认带索引:(当为字典是,,默认键是索引)
s4 = pd.Series([9.53,9.62,9.72])
创建时可以指定索引:
s5 = pd.Series([1, np.nan, 7.0, 'abc'], index=['a','b','c','d'])
DataFrame(常用)
类似于Numpy的二维数组
基本操作
获取行列数据
在 Pandas 中,有多个方法可以选取和重新组合数据,如表所示:
方法 | 说明 |
---|---|
df[val] | 从DataFrame中选取单列或多列。val为布尔型数组时,过滤行; val为切片时,行切片 |
df.loc[val] | 通过val选取单行或多行 |
df.loc[;,val] | 通过val选取单列或多列 |
df.loc[val1,val2] | 选取val1行、val2列的值 |
df.iloc[val] | 通过整数位置,选取单行或多行 |
df.iloc[;,val] | 通过整数位置,选取单列或多列 |
df.iloc[val1, val2] | 通过整数位置,选取val1 行、val2列的值 |
具体说明如下:
1、读取行
如果想从 DataFrame 中获取某一行数据,可以通过位置或名称进行获取。
读取行有三种方法,分别是loc,iloc,ix。
方法名 | 参数 | 备注 |
---|---|---|
loc | 行标签 | 可以使用元组 |
iloc | 行号 | 可以进行切片 |
ix | iloc和loc的并 | 不推荐使用IX索引器,已弃用 |
示例:
- loc通过行标签索引来确定行的
import pandas as pd
d=[[1,2,3,4],[5,6,7,8]]
index=["one","two"]
df=pd.DataFrame(d, index=index)
print df.loc["one"]
- iloc通过行号索引来确定行
import pandas as pd
d=[[1,2,3,4],[5,6,7,8]]
index=["one","two"]
df=pd.DataFrame(d, index=index)
print df.iloc[0]
2、读取列
如果想从 DataFrame 中获取某一列数据为一个 Series, 可以通过类似字典标记或属性的方式:
[]
括号里可以是列标签/列号
实例:
print df5['浦发银行'] #也可以是 df5[0]
#2020-10-14 9.53
#2020-10-15 9.62
#2020-10-16 9.72
#Name: 浦发银行, dtype: float64
df5[['浦发银行','民生银行']] #可以是个元组
# 浦发银行 民生银行
#2020-10-14 9.53 5.33
#2020-10-15 9.62 5.35
#2020-10-16 9.72 5.39
df5[df5['浦发银行'] > 9.6] # 同时可以进行筛选数据
# 浦发银行 民生银行
#2020-10-15 9.62 5.35
#2020-10-16 9.72 5.39
对某列进行 单值筛选
找出df中A列值为100的所有数据
1 df[df.A==100]
# A B C
# 0 100 a 1
用序列对某列筛选:isin
找出df中A列,值为100、200、300的所有数据
num = [100, 200, 300]
df[df.A.isin(num)] #筛选出A列值在num列表的数据条
# A B C
# 0 100 a 1
# 1 200 b 2
# 2 300 c 3
对多列 进行筛选
多条件筛选的时候,必须加括号()
- 找出df中A列值为100且B列值为‘a’的所有数据
df[(df.A==100)&(df.B=='a')]
# A B C
# 0 100 a 1
- 找出df中A列值为100或B列值为‘b’的所有数据
df[(df.A==100)|(df.B=='b')]
# A B C
# 0 100 a 1
# 1 200 b 2
对行列赋值
对DataFrame中某一列的值进行修改,可通过直接赋值一个标量值或一组值:
df5 = pd.DataFrame({'a':[1,2,3],'b':[5,6,7],
'c':[9,10,11],'d':[13,14,15]},
index=['x','y','z'])
# a b c d
#x 1 5 9 13
#y 2 6 10 14
#z 3 7 11 15
df5['d'] = 1 # 对d列赋值为1
# a b c d
#x 1 5 9 1
#y 2 6 10 1
#z 3 7 11 1
df5['d'] = np.arange(3) # 对d列赋值为np.arange(3)
# a b c d
#x 1 5 9 0
#y 2 6 10 1
#z 3 7 11 2
如果赋值给一个 Series, 则会精准匹配对应索引的数值, 若 Series 缺失 DataFrame 某些索引,则对应位置为空:
df5['d'] = pd.Series([2,5,9],index = ['y','z','a'])
df5
增删数据
找出df中A列值为100的所有数据
1 df[df.A==100]
# A B C
# 0 100 a 1
保留想要的列或删除指定列
保留想要的列
# 方法1:
df=df.loc[:,[‘name1’,‘name2’,‘name3’]]
# 方法2:
df2=df[[‘name1’,‘name2’,‘name3’]]
删除指定列
# 方法1:指定列名删除
df.drop([‘name1’,‘name2’],axis=1,inplace=True)
# 方法2:指定列数删除
df.drop(df.columns[0:n], axis=1, inplace=True)
修改行标签和列标签
修改列名
问题:
有一个DataFrame,列名为:['\(a', '\)b', '\(c', '\)d', '$e']
现需要改为:['a', 'b', 'c', 'd', 'e']
import pandas as pd
df = pd.DataFrame({'$a': [1], '$b': [1], '$c': [1], '$d': [1], '$e': [1]})
解决:
方式一:columns属性
# ①暴力
df.columns = ['a', 'b', 'c', 'd', 'e']
# ②修改
df.columns = df.columns.str.strip('$')
# ③修改
df.columns = df.columns.map(lambda x:x[1:])
方式二:rename方法、columns参数
# ④暴力(好处:也可只修改特定的列)
df.rename(columns=('$a': 'a', '$b': 'b', '$c': 'c', '$d': 'd', '$e': 'e'}, inplace=True)
# ⑤修改
df.rename(columns=lambda x:x.replace('$',''), inplace=True)
获取列名列表
DataFrame.columns.values.tolist()
常用方法
reindex()
表示重新索引,如果某个索引值当前不存在,就会引入
缺失值;可以通过fill_value参数填充默认值,也可以通过method参数设置填充方法;
reindex方法的methon参数的选项:
ffill或pad 前向填充值
bfill或backfill 后向填充值
或者是fill_value直接指定缺失值为多少
汇总,计算和描述性统计
Pandas 拥有一套常用的数学和统计方法, 但都是基于没有缺失数据的假设而构建的。
常用方法
读取excel表中的多个sheet
对于导入xlsx,pandas默认只导入第一个sheet,如果想导入多个/其他sheet需要指定:
# 按照index读取,1代表第二张表,默认是0 即默认只读取第一张表
>>> df = pd.read_excel(r'D:\myExcel/1.xlsx', sheet_name=1)
>>> df
name Chinese
0 lc 78
1 lb 79
# 按照表名读取
>>> df = pd.read_excel(r'D:\myExcel/1.xlsx', sheet_name='Sheet2')
>>> df
name Chinese
0 lc 78
1 lb 79
# 同时读取两张表,输入参数为列表
# 返回的是一个有序字典
>>> dfs = pd.read_excel(r'D:\myExcel/1.xlsx', sheet_name=[0, 'Sheet3'])
>>> dfs
OrderedDict([(0, name math science
0 bob 23 12
1 millor 32 32
2 jiken 61 89
3 tom 34 94
4 json 83 12
5 dela 96 67
6 rison 90 34), ('Sheet3', name English
0 ld 32
1 by 98)])
找到缺失值的位置
问题描述:
判断缺失值一般采用 isnull()
,然而生成的却是所有数据的true/false矩阵,对于庞大的数据dataframe,很难一眼看出来哪个数据缺失,一共有多少个缺失数据,缺失数据的位置。
首先对于存在缺失值的数据,如下所示
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.randn(10,6))
# Make a few areas have NaN values
df.iloc[1:3,1] = np.nan
df.iloc[5,3] = np.nan
df.iloc[7:9,5] = np.nan
# 0 1 2 3 4 5
# 0 0.520113 0.884000 1.260966 -0.236597 0.312972 -0.196281
# 1 -0.837552 NaN 0.143017 0.862355 0.346550 0.842952
# 2 -0.452595 NaN -0.420790 0.456215 1.203459 0.527425
# 3 0.317503 -0.917042 1.780938 -1.584102 0.432745 0.389797
# 4 -0.722852 1.704820 -0.113821 -1.466458 0.083002 0.011722
# 5 -0.622851 -0.251935 -1.498837 NaN 1.098323 0.273814
# 6 0.329585 0.075312 -0.690209 -3.807924 0.489317 -0.841368
# 7 -1.123433 -1.187496 1.868894 -2.046456 -0.949718 NaN
# 8 1.133880 -0.110447 0.050385 -1.158387 0.188222 NaN
# 9 -0.513741 1.196259 0.704537 0.982395 -0.585040 -1.693810
df.isnull()
df.isnull()
会产生如下结果
0 1 2 3 4 5
0 False False False False False False
1 False True False False False False
2 False True False False False False
3 False False False False False False
4 False False False False False False
5 False False False True False False
6 False False False False False False
7 False False False False False True
8 False False False False False True
9 False False False False False False
判断哪些”列”存在缺失值
df.isnull().any()
则会判断哪些”列”存在缺失值
0 False
1 True
2 False
3 True
4 False
5 True
dtype: bool
只显示存在缺失值的行列
df[df.isnull().values==True]
可以只显示存在缺失值的行列,清楚的确定缺失值的位置。
df[df.isnull().values==True]
# Out[126]:
# 0 1 2 3 4 5
# 1 1.090872 NaN -0.287612 -0.239234 -0.589897 1.849413
# 2 -1.384721 NaN -0.158293 0.011798 -0.564906 -0.607121
# 5 -0.477590 -2.696239 0.312837 NaN 0.404196 -0.797050
# 7 0.369665 -0.268898 -0.344523 -0.094436 0.214753 NaN
# 8 -0.114483 -0.842322 0.164269 -0.812866 -0.601757 NaN
日期数据的处理
日期数据转化
对于转成int常常除以\(10^9\)
# string to datetime
df['date'] = pd.to_datetime(df['date'])
# datetime to int
pd.to_datetime('1970-01-01').value// 10 ** 9
# 整列datetime to int
df['date'] = df['date'].apply(lambda x: x.value)// 10 ** 9
df['time'] = (df['time']* 10 ** 9).apply(pd.Timestamp)
按日期筛选数据
按年度获取数据
print('---------获取2013年的数据-----------')
print(df['2013'].head(2)) # 获取2013年的数据
print(df['2013'].tail(2)) # 获取2013年的数据
---------获取2013年的数据-----------
number
date
2013-10-24 3
2013-10-25 4
number
date
2013-12-27 2
2013-12-30 2
获取2016至2017年的数据
print('---------获取2016至2017年的数据-----------')
print(df['2016':'2017'].head(2)) #获取2016至2017年的数据
print(df['2016':'2017'].tail(2)) #获取2016至2017年的数据
---------获取2016至2017年的数据-----------
number
date
2016-01-04 4
2016-01-07 6
number
date
2017-02-14 6
2017-02-22 6
获取某月的数据
print('---------获取某月的数据-----------')
print(df['2013-11']) # 获取某月的数据
---------获取某月的数据-----------
number
date
2013-11-04 1
2013-11-06 3
2013-11-08 1
2013-11-12 5
2013-11-14 2
2013-11-25 1
2013-11-29 1
获取具体某天的数据
* 请注意dataframe类型的数据,获取具体某天的数据时,跟series是有些差异的,详细情况如下述代码所示:
# 按日期筛选数据
print('---------获取具体某天的数据-----------')
# 获取具体某天的数据
print(s['2013-11-06'])
# 获取具体某天的数据,用datafrme直接选取某天时会报错,而series的数据就没有问题
# print(df['2013-11-06'])
#可以考虑用区间来获取某天的数据
print(df['2013-11-06':'2013-11-06'])
---------获取具体某天的数据-----------
3
number
date
2013-11-06 3
* dataframe的truncate函数可以获取某个时期之前或之后的数据,或者某个时间区间的数据
* 但一般建议直接用切片(slice),这样更为直观,方便
# dataframe的truncate函数可以获取某个时期之前或之后的数据,或者某个时间区间的数据
# 但一般建议直接用切片(slice),这样更为直观,方便
print('---------获取某个时期之前或之后的数据-----------')
print('--------after------------')
print(df.truncate(after = '2013-11'))
print('--------before------------')
print(df.truncate(before='2017-02'))
---------获取某个时期之前或之后的数据-----------
--------after------------
number
date
2013-10-24 3
2013-10-25 4
2013-10-29 2
2013-10-30 1
--------before------------
number
date
2017-02-07 8
2017-02-14 6
2017-02-22 6
按日期显示数据
to_period()方法
- 请注意df.index的数据类型是DatetimeIndex;
- df_peirod的数据类型是PeriodIndex
按月显示,但不统计
df_period = df.to_period('M') #按月显示,但不统计
print(type(df_period))
print(type(df_period.index))
# 请注意df.index的数据类型是DatetimeIndex;
# df_peirod的数据类型是PeriodIndex
print(df_period.head())
<class 'pandas.core.frame.DataFrame'>
<class 'pandas.tseries.period.PeriodIndex'>
number
date
2013-10 3
2013-10 4
2013-10 2
2013-10 1
2013-11 1
按季度显示,但不统计
print(df.to_period('Q').head()) #按季度显示,但不统计
number
date
2013Q4 3
2013Q4 4
2013Q4 2
2013Q4 1
2013Q4 1
按年度显示,但不统计
print(df.to_period('A').head()) #按年度显示,但不统计
number
date
2013 3
2013 4
2013 2
2013 1
2013 1
asfreq()方法
按年度频率显示
df_period.index.asfreq('A') # 'A'默认是'A-DEC',其他如'A-JAN'
PeriodIndex(['2013', '2013', '2013', '2013', '2013', '2013', '2013', '2013',
'2013', '2013',
...
'2017', '2017', '2017', '2017', '2017', '2017', '2017', '2017',
'2017', '2017'],
dtype='period[A-DEC]', name='date', length=425, freq='A-DEC')
df_period.index.asfreq('A-JAN') # 'A'默认是'A-DEC',其他如'A-JAN'
PeriodIndex(['2014', '2014', '2014', '2014', '2014', '2014', '2014', '2014',
'2014', '2014',
...
'2017', '2017', '2017', '2017', '2017', '2017', '2017', '2018',
'2018', '2018'],
dtype='period[A-JAN]', name='date', length=425, freq='A-JAN')
- 按年度频率在不同情形下的显示,可参考下图所示:
按季度频率显示
df_period.index.asfreq('Q') # 'Q'默认是'Q-DEC',其他如“Q-SEP”,“Q-FEB”
PeriodIndex(['2013Q4', '2013Q4', '2013Q4', '2013Q4', '2013Q4', '2013Q4',
'2013Q4', '2013Q4', '2013Q4', '2013Q4',
...
'2017Q1', '2017Q1', '2017Q1', '2017Q1', '2017Q1', '2017Q1',
'2017Q1', '2017Q1', '2017Q1', '2017Q1'],
dtype='period[Q-DEC]', name='date', length=425, freq='Q-DEC')
df_period.index.asfreq('Q-SEP') # 可以显示不同的季度财年,“Q-SEP”,“Q-FEB”
# df_period.index = df_period.index.asfreq('Q-DEC') # 可以显示不同的季度财年,“Q-SEP”,“Q-FEB”
# print(df_period.head())
PeriodIndex(['2014Q1', '2014Q1', '2014Q1', '2014Q1', '2014Q1', '2014Q1',
'2014Q1', '2014Q1', '2014Q1', '2014Q1',
...
'2017Q2', '2017Q2', '2017Q2', '2017Q2', '2017Q2', '2017Q2',
'2017Q2', '2017Q2', '2017Q2', '2017Q2'],
dtype='period[Q-SEP]', name='date', length=425, freq='Q-SEP')
- 按季度频率在不同情形下的显示,可参考下图所示:
按月度频率显示
df_period.index.asfreq('M') # 按月份显示
PeriodIndex(['2013-10', '2013-10', '2013-10', '2013-10', '2013-11', '2013-11',
'2013-11', '2013-11', '2013-11', '2013-11',
...
'2017-01', '2017-01', '2017-01', '2017-01', '2017-01', '2017-01',
'2017-01', '2017-02', '2017-02', '2017-02'],
dtype='period[M]', name='date', length=425, freq='M')
按工作日显示
- method 1
df_period.index.asfreq('B', how='start') # 按工作日期显示
PeriodIndex(['2013-10-01', '2013-10-01', '2013-10-01', '2013-10-01',
'2013-11-01', '2013-11-01', '2013-11-01', '2013-11-01',
'2013-11-01', '2013-11-01',
...
'2017-01-02', '2017-01-02', '2017-01-02', '2017-01-02',
'2017-01-02', '2017-01-02', '2017-01-02', '2017-02-01',
'2017-02-01', '2017-02-01'],
dtype='period[B]', name='date', length=425, freq='B')
- method 2
df_period.index.asfreq('B', how='end') # 按工作日期显示
PeriodIndex(['2013-10-31', '2013-10-31', '2013-10-31', '2013-10-31',
'2013-11-29', '2013-11-29', '2013-11-29', '2013-11-29',
'2013-11-29', '2013-11-29',
...
'2017-01-31', '2017-01-31', '2017-01-31', '2017-01-31',
'2017-01-31', '2017-01-31', '2017-01-31', '2017-02-28',
'2017-02-28', '2017-02-28'],
dtype='period[B]', name='date', length=425, freq='B')
按日期统计数据
按日期统计数据
按周统计数据
print(df.resample('w').sum().head())
# “w”,week
number
date
2013-10-27 7.0
2013-11-03 3.0
2013-11-10 5.0
2013-11-17 7.0
2013-11-24 NaN
按月统计数据
print(df.resample('M').sum().head())
# "MS"是每个月第一天为开始日期, "M"是每个月最后一天
number
date
2013-10-31 10
2013-11-30 14
2013-12-31 27
2014-01-31 16
2014-02-28 4
按季度统计数据
print(df.resample('Q').sum().head())
# "QS"是每个季度第一天为开始日期, "Q"是每个季度最后一天
number
date
2013-12-31 51
2014-03-31 73
2014-06-30 96
2014-09-30 136
2014-12-31 148
按年统计数据
print(df.resample('AS').sum())
# "AS"是每年第一天为开始日期, "A是每年最后一天
number
date
2013-01-01 51
2014-01-01 453
2015-01-01 743
2016-01-01 1552
2017-01-01 92
- 关于日期的类型,按参考下图所示来选择合适的分期频率:
按日期统计后,按年或季度或月份显示
按年统计并显示
print(df.resample('AS').sum().to_period('A'))
# 按年统计并显示
number
date
2013 51
2014 453
2015 743
2016 1552
2017 92
按季度统计并显示
print(df.resample('Q').sum().to_period('Q').head())
# 按季度统计并显示
number
date
2013Q4 51
2014Q1 73
2014Q2 96
2014Q3 136
2014Q4 148
按月度统计并显示
print(df.resample('M').sum().to_period('M').head())
# 按月度统计并显示
number
date
2013-10 10
2013-11 14
2013-12 27
2014-01 16
2014-02 4
按日期和其他条件组合分组
要按日期和其他条件组合分组,可以使用 Pandas 的 groupby
方法。具体来说,
- 首先使用
set_index
按照日期将DataFrame
转换为时间序列格式, - 再使用 groupby 按照其他条件进行分组。
以一个包含日期、城市和销售额的示例数据集为例:
import pandas as pd
data = {
'date': ['2022-01-01', '2022-01-01', '2022-01-02', '2022-01-02'],
'city': ['Shanghai', 'Beijing', 'Shanghai', 'Beijing'],
'sales': [1000, 2000, 1500, 2500]
}
df = pd.DataFrame(data)
df['date'] = pd.to_datetime(df['date'])
现在我们可以使用 set_index 将 date 列设置为索引,从而转换为时间序列格式:
df = df.set_index('date')
此时 df 的索引变成了日期类型。接下来,我们可以使用 groupby 方法按照 city 和日期进行分组:
grouped = df.groupby([pd.Grouper(freq='D'),'city'])
这里 [pd.Grouper(freq='D'),'city'] 表示按照天为频率(日历日),并按照城市进行分组。现在,我们可以对分组后的数据进行聚合操作,如求和等:
result = grouped.sum()
这样,我们就可以得到按照日期和城市进行分组后的销售额总和。
DataFrame 新增列的五种方法
分组和统计个数
根据不同列分组,分组后对不同列使用不同的聚合函数
对所有列求和,求平均,统计
import pandas as pd
student = pd.read_excel(".../Students.xlsx",index_col="ID")
temp = student[["Test_1","Test_2","Test_3"]]
student["total"] = temp.sum(axis=1)#axis 0为列,1为行
student["avg"] = temp.mean(axis=1)
print(student)
注意: 该操作自动忽略了空值进行均值
案例
【例】与书本不同,本节利用tushare读取招商银行股票数据,并进行 Pandas 基本操作。tushare为金融数据分析提供便捷、快速的接口,与投研和量化策略无缝对接 数据丰富 拥有丰富的数据内容,如股票、基金、期货、数字货币等行情数据,公司财务、基金经理等基本面数据。tushare是第三方库,因此,在首次使用时,需要通过pip安装。
import pandas as pd
import tushare as ts
import datetime
ZSYH = ts.get_hist_data('600036', '2020-08-31', '2020-09-11')
ZSYH.head(3)
ZSYH.tail(3)