1 pandas介绍
- 2008年 WesMcKinney开发出的库
- 专门用于数据挖掘的开源 python库
- 以 Numpy为基础,借力 Numpy模块在计算方面性能高的优势
- 基于 matplotlib,能够简便的画图
- 独特的数据结构
pandas:panel + data + analysis,数据处理工具
- panel面板数据:计量经济学领域存储三维数据
问题:Numpy能够处理数据,结合matplotlib可以解决部分数据展示等问题,那么为什么还要使用pandas?
- 便捷的数据处理能力,如缺失值处理等
- 读取文件方便
- 封装了Matplotlib、Numpy的画图和计算
2 核心数据结构
2.1 DataFrame
2.1.1 DataFrame的结构
上节在 Numpy 当中创建的股票涨跌幅数据形式:
import numpy as np
# 创建一个符合正态分布的 10 个股票 5 天的涨跌幅数据
stock_change = np.random.normal(0, 1, (10, 5))
numpy读取的数据形式看不出数据的具体含义,如需要获取某个指定股票的数据
DataFrame对象是既有行索引,又有列索引的二维数组
- 行索引,表明不同行,横向索引,叫
index
- 列索引,表名不同列,纵向索引,叫
columns
import pandas as pd
In[1] : pd.DataFrame(stock_change)
- 添加行(index)索引
stock = ["股票{}".format(i) for i in range(10)]
In[1] : pd.DataFrame(stock_change, index=stock)
- 添加列(columns)索引
date = pd.date_range(start="20180101", periods=5, freq="B")
In[1] : date
Out[1]: DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
'2018-01-05'],
dtype='datetime64[ns]', freq='B')
In[1] : data = pd.DataFrame(stock_change, index=stock, columns=date)
In[1] : data
2.1.2 DataFrame属性与方法
1. 属性:
- 常用属性:
.shape
In[1] : data.shape
Out[1]: (10, 5)
.index
:DataFrame的行索引列表
In[1] : data.index
Out[1]: Index(['股票0', '股票1', '股票2', '股票3', '股票4', '股票5', '股票6', '股票7', '股票8', '股票9'], dtype='object')
.columns
:DataFrame的列索引列表
In[1] : data.columns
Out[1]: DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
'2018-01-05'],
dtype='datetime64[ns]', freq='B')
.values
:获取其中array的值
In[1] : data.values
Out[1]: array([[-0.07726903, 0.40607587, 1.26740233, 1.48676212, -1.35987104],
[ 0.28361364, 0.43101642, -0.77154311, 0.48286211, -0.30724683],
[-0.98583786, -1.96339732, 0.31658224, -1.96541561, -0.39274454],
[ 2.38020637, 1.47056011, -0.45253103, -0.77381961, 0.4822656 ],
[ 2.05044671, -0.0743407 , 0.10900497, 0.00982431, -0.06639766],
[-1.62883603, 2.370443 , -0.14230101, -1.73515932, 1.6128039 ],
[ 0.59420384, 0.09903473, -2.82975368, 0.63599429, -0.40809638],
[ 1.27884397, -0.42832722, 1.07118356, -0.04453698, -0.19217219],
[ 0.35350472, -0.73933626, 0.81653138, -0.40873922, 1.24391025],
[-0.66201232, -0.53088568, -2.01276069, 0.03709581, 0.86862061]])
.T
:转置
In[1]: data.T
2. 方法
.head(int)
:返回前几行,默认返回5行
In[1]: data.head(3)
如果是print(df.head())打印出的是具体数值,如果想转变为pd.DataFrame格式,可以用print(display(df.head()))
。
.tail(int)
:返回后几行,默认返回5行
In[1]: data.tail(2)
2.1.3 DataFrame索引的设置
- 修改行列索引值:不能单独修改,只能整体修改
In[1]: data.head()
注意:以下修改方式是错误的
# data.index[2] = "股票88"
正确方式:
stock_ = ["股票_{}".format(i) for i in range(10)]
data.index = stock_
In[1] : data.index
Out[1]: Index(['股票_0', '股票_1', '股票_2', '股票_3', '股票_4', '股票_5', '股票_6', '股票_7', '股票_8',
'股票_9'],
dtype='object')
In[1]: data
- 重设索引:
reset_index(drop=False)
- drop:默认为False,不删除原来索引,如果为True,删除原来的索引值
In[1]: data.reset_index(drop=False)
In[1]: data.reset_index(drop=True)
- 设置新索引:以某列值设置为新的索引
set_index(keys, drop=True)
- keys:列索引名成或者列索引名称的列表
- drop:boolean, default True.当做新的索引,删除原来的列
# 1. 创建
df = pd.DataFrame({'month': [1, 4, 7, 10],
'year': [2012, 2014, 2013, 2014],
'sale':[55, 40, 84, 31]})
In[1]: df
# 2. 以月份设置新的索引
In[1]: df.set_index("month", drop=True) # 删除原来列,默认
In[1]: df.set_index("month", drop=False)
# 3. 设置多个索引,以年和月份
new_df = df.set_index(["year", "month"])
In[1]: df.set_index(["year", "month"])
In[1] : new_df.index
Out[1]: MultiIndex(levels=[[2012, 2013, 2014], [1, 4, 7, 10]],
labels=[[0, 2, 1, 2], [0, 1, 2, 3]],
names=['year', 'month'])
注意: 通过刚才的设置,这样DataFrame就变成了一个具有MultiIndex的DataFrame,可以存储三维数据。
2.2 Panel
2.2.1 MultiIndex
多级或分层索引对象
- index属性
- names:levels的名称
- levels:每个level的元组值
In[1] : new_df.index.names
Out[1]: FrozenList(['year', 'month'])
In[1] : new_df.index.levels
Out[1]: FrozenList([[2012, 2013, 2014], [1, 4, 7, 10]])
2.2.2 Panel
class pandas.Panel(data=None, items=None, major_ axis=None, minor_axis=None, copy=False, dtype=None)
- 存储3维数组的Panel结构,DataFrame的容器
p = pd.Panel(np.arange(24).reshape(4,3,2),
items=list('ABCD'),
major_axis=pd.date_range('20130101', periods=3),
minor_axis=['first', 'second'])
In[1] : p
Out[1]: <class 'pandas.core.panel.Panel'>
Dimensions: 4 (items) x 3 (major_axis) x 2 (minor_axis)
Items axis: A to D
Major_axis axis: 2013-01-01 00:00:00 to 2013-01-03 00:00:00
Minor_axis axis: first to second
- items - axis 0,每个项目对应于内部包含的数据帧(DataFrame)。
- major_axis - axis 1,它是每个数据帧(DataFrame)的索引(行)。
- minor_ax/s - axis 2,它是每个数据帧(DataFrame)的列。
注:Pandas从版本0.20.0开始弃用:推荐的用于表示3D数据的方法是 DataFrame上的Multiindex方法
In[1] : p["A"]
In[1] : p["D"]
In[1] : p.major_xs("2013-01-01")
In[1] : p.minor_xs("first")
2.3 Series
series结构只有行索引,即带索引的一维数组。
思考:如果获取DataFrame中某个股票的不同时间数据?这样的结构是什么?
In[1] : data
sr = data.iloc[1, :]
In[1] : sr
Out[1]: 2018-01-01 0.283614
2018-01-02 0.431016
2018-01-03 -0.771543
2018-01-04 0.482862
2018-01-05 -0.307247
Freq: B, Name: 股票_1, dtype: float64
In[1] : sr.index
Out[1]: DatetimeIndex(['2018-01-01', '2018-01-02', '2018-01-03', '2018-01-04',
'2018-01-05'],
dtype='datetime64[ns]', freq='B')
In[1] : sr.values
Out[1]: array([ 0.28361364, 0.43101642, -0.77154311, 0.48286211, -0.30724683])
In[1] : type(sr.values)
Out[1]: numpy.ndarray
2.3.1 创建 Series
- 通过已有数据创建:指定内容,默认索引
In[1] : pd.Series(np.arange(10))
- 指定索引
In[1] : pd.Series([6.7, 5.6, 3, 10, 2], index = [1, 2, 3, 4, 5])
Out[1]: 1 6.7
2 5.6
3 3.0
4 10.0
5 2.0
dtype: float64
In[1] : pd.Series(np.arange(3, 9, 2), index=["a", "b", "c"])
Out[1]: a 3
b 5
c 7
dtype: int64
- 通过字典数据创建
In[1] : pd.Series({'red':100, 'blue':200, 'green': 500, 'yellow':1000})
Out[1]: blue 200
green 500
red 100
yellow 1000
dtype: int64
2.3.2 Series获取索引和值
.index
,.values
2.4 总结
- Series:带行索引的一维数组
- DataFrame:带行列索引的二维数组
- DataFrame是Series的容器
- Panel是DataFrame的容器
3 基本数据操作
3.1 读取一个真实的股票数据
# 读取文件
data = pd.read_csv("./stock_day/stock_day.csv")
In[1] : data
# 删除一些列,让数据更简单些,再去做后面的操作
data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)
In[1] : data
3.2 索引操作
pandas支持索引选取序列和切片选择,可以直接使用列名、行名称,甚至组合使用。
不能直接进行数字索引,numpy可以
# data[1, 0] # 报错
获取“2018-02-26”这天的open的结果
3.2.1 直接使用行列索引(先列后行)
In[1] : data.head()
In[1] : data["open"]["2018-02-26"]
Out[1]: 22.8
# data["2018-02-26"]["open"] 必须先列后行
3.2.2 结合.loc
或者.iloc
使用索引
.loc
:按名字索引,必须先行后列
In[1] : data.loc["2018-02-26"]["open"]
Out[1]: 22.8
# 或者
In[1] : data.loc["2018-02-26", "open"]
Out[1]: 22.8
.iloc
:按数字索引
In[1] : data.iloc[1, 0]
Out[1]: 22.8
3.2.3 使用.ⅸ
组合索引
Warning:Starting in 0. 20.0, the
.ix
indexer is deprecated, in favor of the more strict.iloc
and.loc
indexers.
获取行第1天到第4天,[‘open’, ‘close’, ‘high’, ‘low’]这个四个指标的结果
# 使用.ix进行下表和名称组合做引
In[1] : data.ix[0:4, ['open', 'close', 'high', 'low']]
# 推荐使用loc和iloc来获取的方式
In[1] : data.loc[data.index[0:4], ['open', 'close', 'high', 'low']]
In[1] : data.iloc[0:4, data.columns.get_indexer(['open', 'close, 'high', 'low'])]
3.3 赋值操作
对 DataFrame当中的open列进行重新赋值为100
data.open = 100
# 或者
data['open'] = 100
data.iloc[1, 0] = 222
In[1] : data.head()
3.4 排序
排序有两种形式,一种对内容进行排序,一种对索引进行排序。
3.4.1 DataFrame
- 使用
df.sort_values(by= , ascending= )
对内容进行排序- 单个键或者多个键进行排序,默认升序
- ascending= False:降序
- ascending=True:升序,默认
# data.sort_values(by="high", ascending=False)
In[1] : data.sort_values(by=["high", "p_change"], ascending=False).head()
先按“high”列进行排序,如果两行“high”相等,再按照“p_change”排序
- 使用
df.sort_index()
对索引进行排序
这个股票的日期索引原来是从大到小,现在重新排序,从小到大
In[1] : data.sort_index().head()
3.4.2 Series
- 使用
series.sort_values(ascending=True)
对内容进行排序,series排序时,只有一列,不需要参数
sr = data["price_change"]
In[1] : sr.sort_values(ascending=False).head()
Out[1]: 2015-06-09 3.03
2017-10-26 2.68
2015-05-21 2.57
2017-10-31 2.38
2017-06-22 2.36
Name: price_change, dtype: float64
- 使用
series.sort_index()
对索引进行排序,与df一致
In[1] : sr.sort_index().head()
Out[1]: 2015-03-02 0.32
2015-03-03 0.18
2015-03-04 0.20
2015-03-05 0.26
2015-03-06 1.12
Name: price_change, dtype: float64
4 DataFrame运算
4.1 算术运算
- 直接运算
In[1] : (data["open"] + 5).head()
Out[1]: 2018-02-27 105
2018-02-26 227
2018-02-23 105
2018-02-22 105
2018-02-14 105
Name: open, dtype: int64
add(other)
:加,数学运算加上具体的一个数字
In[1] : data["open"].add(3).head()
Out[1]: 2018-02-27 103
2018-02-26 225
2018-02-23 103
2018-02-22 103
2018-02-14 103
Name: open, dtype: int64
sub(other)
:减
In[1] : data.sub(100).head()
如果想要得到每天的涨跌大小?求出每天 close-open价格差
In[1] : data["close"].sub(data["open"]).head()
Out[1]: 2018-02-27 -75.84
2018-02-26 -198.47
2018-02-23 -77.18
2018-02-22 -77.72
2018-02-14 -78.08
dtype: float64
4.2 逻辑运算
4.2.1 逻辑运算符号<
、>
、|
、&
- 例如筛选 p_change > 2 的日期数据,可以采用布尔索引
data['p_change']>2
返回逻辑结果
In[1] : data[data["p_change"] > 2].head()
- 完成一个多个逻辑判断,筛选 p_change > 2并且 open > 15,,布尔索引
In[1] : data[(data["p_change"] > 2) & (data["low"] > 15)].head()
4.2.2 逻辑运算函数
query(expr)
:可以使得上节排序过程更加方便简单- expr:查询字符串
In[1] : data.query("p_change > 2 & low > 15").head()
isin(values)
:可以指定值进行一个判断,从而进行筛选操作
# 判断 turnover是否为4.19,239,布尔索引
In[1] : data[data["turnover"].isin([4.19, 2.39])]
4.3 统计运算
4.3.1 describe()
综合分析:能够直接得岀很多统计结果,count,mean,std,min,max
等
# 计算统计数、平均值、标准差、最小值、分位数、最大值
In[1] : data.describe()
4.3.2 统计函数
Numpy当中已经详细介绍,这里演示min(最小值),max(最大值),mean(平均值), median(中位数),var(方差),std(标准差)结果。
count | Number of non-NA observations |
---|---|
sum | Sum of values |
mean | Mean of values |
median | Arithmetic median of values |
min | Minimum |
max | Maximum |
mode | Mode |
abs | Absolute value |
prod | Product of values |
std | Bessel-corrected sample standard deviation |
var | Unbiased variance |
idxmax | compute the index labels with the maximum,最大值的位置 |
idxmin | compute the index labels with the minimum,最小值的位置 |
- 对于单个函数去进行统计的时候,坐标轴还是按照这些默认为“columns”(axis=0,default为列),如果要对行“index”需要指定(axis=1)
# 使用统计函数:0代表列求结果,1代表行求统计结果
In[1] : data.max(axis=0)
Out[1]: open 222.00
high 36.35
close 35.21
low 34.01
volume 501915.41
price_change 3.03
p_change 10.03
turnover 12.56
dtype: float64
In[1] : data.idxmax(axis=0)
Out[1]: open 2018-02-26
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
dtype: object
4.4 累计统计函数
函数 | 作用 |
---|---|
cumsum | 累加,计算前1/2/3/……/n个数的和 |
cummax | 计算前1/2/3/……/n个数的最大值 |
cummin | 计算前1/2/3/……/n个数的最小值 |
cumprod | 累乘,计算前1/2/3/……/n个数的积 |
In[1] : data["p_change"].sort_index().cumsum().plot()
Out[1]: <matplotlib.axes._subplots.AxesSubplot at 0x24743d39be0>
4.5 自定义运算
apply(func, axis=0)
- func:自定义函数
- axis=0:默认是列,axis=1为行进行运算
定义一个对列,max - min 的函数:
In[1] : data.apply(lambda x: x.max() - x.min())
Out[1]: open 122.00
high 23.68
close 22.85
low 21.81
volume 500757.29
price_change 6.55
p_change 20.06
turnover 12.52
dtype: float64
# 检验
In[1] : data["volume"].max() - data["volume"].min()
Out[1]: 500757.29
5 Pandas画图
5.1 pandas.DataFrame.plot
DataFrame.plot(x=None, y=None, kind='line')
- x:label or position, default None
- y:label, position or list of label, positions, default None
- Allows plotting of one column versus another
- kind:str
- ‘line’:line plot(default),默认折线图
- ‘bar’:vertical bar plot
- ‘barh’:horizontal bar plot
- ‘hist’:histogram
- ‘pie’:pie plot
- ‘scatter’:scatter plot
In[1] : data.plot(x="volume", y="turnover", kind="scatter")
Out[1]: <matplotlib.axes._subplots.AxesSubplot at 0x10ac47e80>
5.2 pandas.Series.plot
见 4.4 累计统计函数,更多参数细节:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.plot.html?highlight=plot#pandas.Series.plot
6 文件读取与存储
数据大部分存在于文件当中,pandas支持复杂的IO操作,pandas的API支持众多的文件格式,如CSV、SQL、XLS、JSON、HDF5。
注:最常用的HDF5和CSV文件
Format Type | Data Description | Reader | Writer |
---|---|---|---|
text | CSV | read_csv | to_csv |
text | JSON | read_json | to_json |
text | HTML | read_html | to_html |
text | Local clipboard | read_clipboard | to_clipboard |
binary | MS Excel | read_excel | to_excel |
binary | HDF5 Format | read_hdf | to_hdf |
binary | Feather Format | read_feather | to_feather |
binary | Parquet Format | read_parquet | to_parquet |
binary | Msgpack | read_msgpack | to_msgpack |
binary | Stata | read_stata | to_stata |
binary | SAS | read_sas | |
binary | Python Pickle Format | read_pickle | to_pickle |
SQL | SQL | read_sql | to_sql |
SQL | Google Big Query | read_gbq | to_gbq |
6.1 CSV
6.1.1 读取csv文件 - read_csv()
pandas.read_csv(filepath_or_buffer, usecols=[ ], sep =',', delimiter= None)
- filepath_or_buffer:文件路径
- usecols:指定读取的列名,列表形式
- 读取之前的股票的数据
In[1] : pd.read_csv("./stock_day/stock_day.csv")
- 读取文件,并且指定只获取’open’,‘high’,’ close’指标
In[1] : pd.read_csv("./stock_day/stock_day.csv", usecols=["high", "low", "open", "close"]).head()
- 读取无索引文件"stock_day2.csv"
In[1] : pd.read_csv("stock_day2.csv") # 自动以第一行为索引值
- 为无索引文件添加字段索引
data = pd.read_csv("stock_day2.csv", names=["open", "high", "close", "low", "volume", "price_change", "p_change", "ma5", "ma10", "ma20", "v_ma5", "v_ma10", "v_ma20", "turnover"])
6.1.2 写入csv文件 - to_csv()
-
DataFrame.to_csv(path_or_buf=None, sep=' , ', columns=None, header=True, index=True, index_label=None, mode='w', encoding=None)
- path_or_buf:string or file handle, default None
- sep:character, default ’ , ’
- columns:sequence, optional,列
- mode:'w:重写, ‘a’:追加
- index:是否写进行索引
- header:boolean or list of string, default True, 是否写进列索引值
-
Series.to_ csv(path=None, index=True, sep=' , ', na_rep=' ', float_format=None, header=False, index_label=None, mode='w', encoding=None, compression=None, date_format=None, decimal=' . ')
Write Series to a comma-separated values(csv) file
# 保存'open'列的数据
In[1] : data[:10].to_csv("test.csv", columns=["open"])
In[1] : pd.read_csv("test.csv")
索引存入到文件时会变成单独的一列数据。如果需要删除,可以指定 index参数,删除原来的文件,重新保存一次。
In[1] : data[:10].to_csv("test.csv", columns=["open"], index=False)
# 追加模式,包含“open”
In[2] : data[:10].to_csv("test.csv", columns=["open"], index=False, mode="a")
# 追加模式,不包含“open”
In[3] : data[:10].to_csv("test.csv", columns=["open"], index=False, mode="a", header=False)
6.2 HDF5
6.2.1 read_hdf()
与 to_hdf()
HDF5文件的读取和存储需要指定一个键,值为要存储的 DataFrame
理解:hdf5 存储 3维数据的文件
key1 → \to → dataframe1 二维数据
key2 → \to → dataframe2 二维数据
pandas.read_hdf(path_or_ buf, key = None, ** kwargs)
:从.h5
文件当中读取数据- path_ or buffer:文件路径
- key:读取的键
- mode:打开文件的模式
- return:Theselected object
DataFrame_to_ hdf(path_or_ buf, key, *\kwargs*)
day_close = pd.read_hdf("./stock_data/day/day_close.h5")
In[1] : day_close
# 必须指定“key”,否则会报错
day_close.to_hdf("test.h5", key="close")
In[1] : pd.read_hdf("test.h5", key="close").head()
day_open = pd.read_hdf("./stock_data/day/day_open.h5")
day_open.to_hdf("test.h5", key="open")
In[1] : pd.read_hdf("test.h5", key="close").head()
6.2.2 拓展
优先选择使用HDF5文件存储
- HDF5在存储的是支持压缩,使用的方式是 bloc,这个是速度最快的也是 pandas默认支持的
- 使用压缩可以提高磁盘利用率,节省空间
- HDF5还是跨平台的,可以轻松迁移到 hadoop上面
6.3 JSON
Json是常用的一种数据交换格式,在前后端的交互经常用到,也会在存储的时候选择这种格式。
案例:这里使用一个新闻标题讽刺数据集,格式为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}
6.3.1 read_json()
pandas.read_ json(path_or_buf=None, orient=None, typ='frame', lines=False)
- 将JSON格式标准换成默认的 Pandas DataFrame格式
- orient:string, Indication of expected JSON string format. 指定存储的json格式
- 'split’:dict like {index -> [index], columns -> [columns], data->[values]}
- ’records’:list like [{column -> value}, ……, {column-> value}]
- ‘index’:dict like {index -> {column -> value}}
- ’columns’:dict like{column -> { index -> value}}, 默认该格式
- ‘values’:just the values array
- lines:boolean. default False. 指定按行作为一个样本
- True:按照每行读取json对象
- typ:default 'frame’,指定转换成的对象类型 series或者 dataframe
sa = pd.read_json("Sarcasm_Headlines_Dataset.json", orient="records", lines=True)
In[1] : sa
6.2.1 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:一个对象存储为一行
In[1] : sa.to_json("test.json", orient="records", lines=True)