Python 数据挖掘 | 第3章 使用 Pandas 数据分析

前言1. Pandas 概述1.1 核心数据结构1.1.1 Series1.1.2 DataFrame1.1.3 Pannelcode1 DataFrame、Panel 和 Series 的构造与访问代码示例

2. 基本数据操作2.1 索引操作2.2 赋值操作2.3 排序

3. DataFrame 运算3.1 算数运算3.2 逻辑运算3.3 统计运算3.4 累计统计函数3.5 自定义运算code2 索引操作、值操作、排序与运算代码示例

4. Pandas 画图code3 简单画图代码示例

5. 文件读取与存储5.1 CSV 文件的读取与存储5.1.1 读取 read_csv()code4 CSV文件的读取与存储代码示例

5.1.2 存储 to_csv()

5.2 hdf5 文件的读取与存储5.2.1 读取 read_hdf()5.2.2 存储 to_hdf()code5 hdf5文件的读取与存储代码示例

5.3 json 文件的读取与存储5.3.1 读取 read_json()5.3.2 存储 to_json()code6 json文件的读取与存储代码示例

6. 缺失值处理6.1 缺失值处理的思路6.2 如何处理 nancode7 nan缺失值处理代码示例code8 其他缺失值处理代码示例

7. 数据离散化7.1 概述7.2 实现离散化code9 数据离散化代码示例

8. 合并8.1 按方向合并code10 按方向合并代码示例

8.2 按索引合并code11 按索引合并代码示例

9. 交叉表与透视表9.1 交叉表9.2 透视表code12 交叉表与透视表代码示例

10. 分组与聚合code13 分组与聚合代码示例

最后

前言

使用 Pandas 数据分析

1. Pandas 概述

Pandas 是 Python 语言的一个扩展程序库,用于数据分析;特点:

便捷的数据处理能力;封装了Matplotlib、Numpy的画图和计算;读取文件方便;

1.1 核心数据结构

三大数据结构:DataFrame、Pannel、Series;

1.1.1 Series

Series 可以理解成带索引的一维数组(只有行索引);API:

pd.Series(np.arange(10)):指定内容,默认索引;pd.Series([1,8,5], index=["a", "b", "c"]):指定索引;pd.Series({'red': 100, 'blue': 200, 'green': 300}):通过字典构造数据; 属性:

index:索引;values:值;

1.1.2 DataFrame

DataFrame 可以理解成即带行索引,又带列索引的二维数组;可以把 DataFrame 理解成 Series 的容器;结构:

既有行索引,又有列索引的二维数组;行索引,表明不同行,横向索引,叫 index;列索引,表明不同列,纵向索引,叫 columns; 常用属性:

shape;index 行索引列表;columns 列索引列表;values 直接获取其中array的值;T 行列转置; 常用方法:

head() 开头几行;tail() 最后几行; API:

pd.DataFrame(ndarray, index, columns):构造一个 DataFrame;pd.date_range(start="20200101", periods=5, freq="B"):添加日期作为索引;

start:开始日期;end:结束时间;periods:指定生成时间序列的数量;freq:生成频率,默认‘D’,可以是’H’、‘D’、‘M’、‘5H’、‘10D’; 索引的设置:

修改行列索引:只能整体修改,不能单独改;

stock_ = ["股票_{}".format(i) for i in range(10)];data.index = stock_ 重设索引:用的不多;

data.reset_index(drop=False):drop:False 表示将索引加入到数据中。drop:True 表示直接删掉索引; 设置新索引:

data.set_index(keys, drop=True):

keys:列索引名称或列索引名称列表,当索引名称为列表时,返回 MultiIndex 对象;drop:False 表示将索引加入到数据中。True 表示删掉索引; MultiIndex:多级或分层索引对象;

index 属性:

names:levels 的名称;levels:每个 level 的元组值;

1.1.3 Pannel

Pannel 可以理解成一个三维数据的结构;Pandas 从 0.20.0 开始弃用 Pannel,推荐使用 DateFrame 上的 MultiIndex 表示 3D 数据;API:

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']):构造一个三维 Pannel,可以理解成为 DataFrame 容器,直接打印不能展示数据,要通过维度访问;

items:维度。可以通过 p[“A”] 访问其中一个维度;major_axis:时间。可以通过 p.major_xs("2013-01-01") 访问该时间维度;minor_axis:次序。可以通过 p.minor_xs("first") 访问该次序维度;

code1 DataFrame、Panel 和 Series 的构造与访问代码示例

# 创建一个符合正态分布的10个股票5天的涨跌幅数据

stock_change = np.random.normal(0, 1, (10, 5))

# 1.构造 DataFrame

## 1.1 通过 ndarray 数组生成

stock = ["股票{}".format(i) for i in range(10)] # 行索引

date = pd.date_range(start="20180101", periods=5, freq="B") # 列索引

data = pd.DataFrame(stock_change, index=stock, columns=date)

## 1.2 通过字典生成

df = pd.DataFrame({'month': [1, 4, 7, 10],

'year': [2012, 2014, 2013, 2014],

'sale':[55, 40, 84, 31]})

# 1.3修改行列索引

stock_ = ["股票_{}".format(i) for i in range(10)]

data.index = stock_

# 1.4 重设索引

# data.reset_index(drop=False)

# 1.5 设置新索引

df.set_index("month", drop=True) # 以月份设置新的索引

new_df = df.set_index(["year", "month"]) # 设置多个索引,以年和月份

print(new_df.index) # 返回 MultiIndex 可以表示三维数据

# 1.6 MultiIndex

print(new_df.index.names) # levels 的名称

print(new_df.index.levels) # 每个 level 的元组值

# 2.构造 Panel

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'])

# 2.1 访问维度

print(p["A"])

p.major_xs("2013-01-01")

p.minor_xs("first")

# 3.构造 Series

pd.Series(np.arange(10)) # 指定内容,默认索引;

pd.Series([1, 8, 5], index=["a", "b", "c"]) # 指定索引;

pd.Series({'red': 100, 'blue': 200, 'green': 300}) # 通过字典构造数据;

2. 基本数据操作

2.1 索引操作

直接索引(先列后行)

a = data["open"]["2018-02-26"] 按名字索引

b = data.loc["2018-02-26", "open"] 按数字索引

c = data.iloc[1, 0] 组合索引

d = data.loc[data.index[0:4] , ['open', 'close', 'high', 'low']]:获取第1天到第4天的 [‘open’, ‘close’, ‘high’, ‘low’];e = data.iloc[0:4 , data.columns.get_indexer(['open', 'close', 'high', 'low'])]

2.2 赋值操作

修改多个值:

data.open = 100:将open列所有值改成100;data["open"] = 100:将open列所有值改成100; 修改单个值:

data.iloc[1, 0] = 222:修改某个值;

2.3 排序

对内容进行排序:

data.sort_values(by=["xxx", "yyy"], ascending=False):ascending=False降序,ascending=True升序; 对索引进行排序:

data.sort_index();

3. DataFrame 运算

3.1 算数运算

算数运算:data["yyy"].add(x):yyy 下所有元素值加 x;data1.sub(data2):data1 一一对应减去 data2;

3.2 逻辑运算

逻辑运算:data[data["yyy"] > x]:筛选 yyy 下所有值大于 x 的元素;data[(data["xxx"] > n) & (data["yyy"] < m)]:筛选 xxx 下所有值大于 n,并且 yyy 小于 m的元素;data.query("xxx > n & yyy < m"):使用逻辑运算函数;data[data["xxx"].isin([n, m])]:判断 xxx 是否为 n, m;

3.3 统计运算

统计运算:(默认列计算) data.describe():获取常用统计值;data.max(axis=0):获取最大值;data.idxmax(axis=0):获取最大值所在位置;

3.4 累计统计函数

累计统计函数:data.cumsum():计算前1/2/3/…/n个数的和;data.cummax():计算前1/2/3/…/n个数的最大值;data.cummin():计算前1/2/3/…/n个数的最小值;data.cumprod():计算前1/2/3/…/n个数的积;

3.5 自定义运算

自定义运算(默认列计算)data.apply(lambda x: x.max() - x.min());

code2 索引操作、值操作、排序与运算代码示例

# 1.读取数据

data = pd.read_csv("../../resources/p00_data_mining/stock_day.csv")

# 删除一些列

data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)

# 2.索引操作

## 2.1 直接索引(先列后行)

a = data["open"]["2018-02-26"]

## 2.2 按名字索引

b = data.loc["2018-02-26", "open"]

## 2.3 按数字索引

c = data.iloc[1, 0]

## 2.4 组合索引

d = data.loc[data.index[0:4] , ['open', 'close', 'high', 'low']] # 获取第1天到第4天的 ['open', 'close', 'high', 'low']

e = data.iloc[0:4 , data.columns.get_indexer(['open', 'close', 'high', 'low'])]

# 3.值操作

data.open = 100 # 将open列所有值改成100

data["open"] = 100 # 将open列所有值改成100

data.iloc[1, 0] = 222 # 修改某个值

# 4.排序

data.sort_values(by=["high", "p_change"], ascending=False).head() # 对内容进行排序。ascending=False降序,ascending=True升序

data.sort_index()

# 5.DataFrame 运算

## 5.1 算数运算

data["open"].add(3).head() # 加法

data.sub(100).head() # 加法

data["close"].sub(data["open"]).head() # 减法

## 5.2 逻辑运算

data[data["p_change"] > 2].head() # 例如筛选p_change > 2的日期数据

data[(data["p_change"] > 2) & (data["low"] > 15)].head() # 完成一个多个逻辑判断, 筛选p_change > 2并且low > 15

data.query("p_change > 2 & low > 15").head() # 逻辑运算函数

f = data[data["turnover"].isin([4.19, 2.39])] # 判断'turnover'是否为4.19, 2.39

## 5.3 统计运算

data.describe() # 获取常用统计值

data.max(axis=0) # 获取最大值

data.idxmax(axis=0) # 获取最大值所在位置

## 5.4 累计统计函数

data["p_change"].sort_index().cumsum().plot() # plot()画图

## 5.5 自定义运算

data.apply(lambda x: x.max() - x.min())

4. Pandas 画图

API:pandas.DataFrame.plot(x=None, y=None, kind=‘line’)

x: 标签或索引,默认 None;y: 标签、索引或者列表的标签、索引,默认 None;

允许绘制一列与另一列的对比图 kind: str;

‘line’:折线图(默认);''bar":柱状图;“barh”:水平条形图;“hist”: 直方图;“pie”:饼图;“scatter”:散点图; pandas.Series.plot(kind="line");

code3 简单画图代码示例

# 1.读取数据

data = pd.read_csv("../../resources/p00_data_mining/stock_day.csv")

# 删除一些列

data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)

# 2.画图

#更简易用matplotlib

data.plot(x="volume", y="turnover", kind="scatter")

data.plot(x="high", y="low", kind="scatter")

data['volume'].plot()

5. 文件读取与存储

5.1 CSV 文件的读取与存储

5.1.1 读取 read_csv()

pandas.read_csv(filepath_or_buffer, sep=',', delimiter=None, usecols=[], names=[]):

filepath_or_buffer:文件路径;sep:分隔符;usecols:指定读取的列名,列表形式;names:如果列没有列名,用names传入;

code4 CSV文件的读取与存储代码示例

# 1.读取数据

data0 = pd.read_csv("../../resources/p00_data_mining/stock_day.csv", usecols=["high", "low", "open", "close"]).head() # 读哪些列

data = pd.read_csv("../../resources/p00_data_mining/stock_day2.csv", names=["open", "high", "close", "low", "volume", "price_change", "p_change", "ma5", "ma10", "ma20", "v_ma5", "v_ma10", "v_ma20", "turnover"]) # 如果列没有列名,用names传入

# 2.写入数据

data[:10].to_csv("../../resources/p00_data_mining/test1.csv", columns=["open"]) # 保存open列数据前10行

data[:10].to_csv("../../resources/p00_data_mining/test2.csv", columns=["open"], index=False, mode="a", header=False) # 保存opend列数据,index=False不要行索引,mode="a"追加模式|mode="w"重写,header=False不要列索引

5.1.2 存储 to_csv()

DataFrame.to_csv(filepath_or_buffer, sep=',', columns=None, header=True, index=True, index_label=None, mode='w', encoding=None):

filepath_or_buffer:文件路径;sep:分隔符;columns:列,列表形式;model:读写模式:w-重写,a-追加;index:是否写进 行索引;header:是否写进 列索引; Series.to_csv(...)

5.2 hdf5 文件的读取与存储

5.2.1 读取 read_hdf()

pandas.read_hdf(path_or_buf, key=None, **kwargs)

path_or_buffer: 文件路径;key: 读取的键;model: 打开文件的模式;reurn: The Selected object

5.2.2 存储 to_hdf()

DataFrame.to_hdf(path_or_buf, key, **kwargs))

code5 hdf5文件的读取与存储代码示例

# 1.读取数据

day_close = pd.read_hdf("../../resources/p00_data_mining/day_close.h5")

# 2.写入数据

day_close.to_hdf("../../resources/p00_data_mining/test3.h5", key="close")

# 测试

day_close_test = pd.read_hdf("../../resources/p00_data_mining/test3.h5")

5.3 json 文件的读取与存储

5.3.1 读取 read_json()

pandas.read_json(path_or_buf=None,orient=None,typ=“frame”,lines=False);

将JSON格式转换成默认的 Pandas DataFrame 格式;orient: string,以怎样的格式展示读取进来的 json 文件;

‘split’: 字典 like {index -> [index], columns -> [columns], data -> [values]};‘records’: 列表 like [{column -> value}, …, {column -> value}];‘index’: 字典 like {index -> {column -> value}};‘columns’: 字典 like {column -> {index -> value}}, 默认该格式;‘values’: just the values array; lines: boolean, default False;

按照每行读取json对象 type: default ‘frame’,指定转换成的对象类型series或者dataframe

5.3.2 存储 to_json()

DataFrame.read_json(path_or_buf=None,orient=None,lines=True);

code6 json文件的读取与存储代码示例

sa = pd.read_json("../../resources/p00_data_mining/Sarcasm_Headlines_Dataset.json", orient="records", lines=True)

##主要是path,orient是一种确定索引与数值的对应,以本例来看,列索引就是‘key’,values就是key对应的值

sa.to_json("../../resources/p00_data_mining/test4.json", orient="records", lines=True)

6. 缺失值处理

6.1 缺失值处理的思路

删除含有缺失值的样本;替换/插补缺失值;

6.2 如何处理 nan

判断缺失值:pd.isnull(data):判断数据是否为 nan。一般会结合 any() 函数使用;

np.any(pd.isnull(movie)):返回True,说明数据中存在缺失值;pd.isnull(movie).any():返回True,说明数据中存在缺失值; pd.notnull(data):判断数据是否为 nan。一般会结合 all() 函数使用;

np.all(pd.notnull(movie)):返回False,说明数据中存在缺失值;pd.notnull(movie).all():返回False,说明数据中存在缺失值; 处理缺失值 nan:data.dropna(axis='rows', inplace=):删除缺失值;

axis:默认删除行;inplace:True 时会修改原数据。False 时不会替换修改原数据,生成新对象(默认); data.fillna(value, inplace=):替换缺失值;

value:替换成的值;inplace:True 时会修改原数据。False 时不会替换修改原数据,生成新对象(默认); data.replace(to_replace="?", value=np.nan):如果缺失值不是 np.nan 时,需要先把缺失值替换成 np.nan,再进行缺失值处理;

to_replace:需要处理的缺失值;value:替换成的值;

code7 nan缺失值处理代码示例

# 1.读取数据

movie = pd.read_csv("../../resources/p00_data_mining/IMDB-Movie-Data.csv")

# 2.判断是否存在缺失值

np.any(pd.isnull(movie)) # 返回True,说明数据中存在缺失值

np.all(pd.notnull(movie)) # 返回False,说明数据中存在缺失值

pd.isnull(movie).any()

pd.notnull(movie).all()

# 3.缺失值处理

# 方法1:删除含有缺失值的样本

data1 = movie.dropna()

# 方法2:替换

# 含有缺失值的字段:Revenue (Millions) 和 Metascore

movie["Revenue (Millions)"].fillna(movie["Revenue (Millions)"].mean(), inplace=True)

movie["Metascore"].fillna(movie["Metascore"].mean(), inplace=True)

code8 其他缺失值处理代码示例

# 1.读取数据

path = "https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data"

name = ["Sample code number", "Clump Thickness", "Uniformity of Cell Size", "Uniformity of Cell Shape", "Marginal Adhesion", "Single Epithelial Cell Size", "Bare Nuclei", "Bland Chromatin", "Normal Nucleoli", "Mitoses", "Class"]

data = pd.read_csv(path, names=name)

# 2.将缺失值替换成 np.nan

# 1)替换

data_new = data.replace(to_replace="?", value=np.nan)

# 2)删除缺失值

data_new.dropna(inplace=True)

data_new.isnull().any() # 全部返回False说明不存在缺失值了

7. 数据离散化

7.1 概述

定义:连续属性的离散化就是将连续属性的值域上,将值域划分为若干个离散的区间,最后用不同的符号或整数 值代表落在每个子区间的属性值;目的:连续属性离散化的目的是为了简化数据结构,数据离散化技术可以用来减少给定连续属性值的个数。离散化方法经常作为数据挖掘的工具;

7.2 实现离散化

对数据进行分组:pd.qcut(data, bins):自动分组;

data:需要分组的数据,Series;bins:组数; pd.cut(data, bins):自定义分组;data.value_counts():统计分组次数。对数据分组一般会与 vaule_counts 搭配使用,统计每组个数;对分好的数据求哑变量(one-hot 编码):pandas.get_dummies(data, prefix=None);

data:数据,Series、DataFrame;prefix:分组名字;

code9 数据离散化代码示例

# 1)准备数据

data = pd.Series([165,174,160,180,159,163,192,184], index=['No1:165', 'No2:174','No3:160', 'No4:180', 'No5:159', 'No6:163', 'No7:192', 'No8:184'])

# 2)分组

# 自动分组

sr1 = pd.qcut(data, 3)

# 自定义分组

bins = [150, 165, 180, 195]

sr2 = pd.cut(data, bins)

# 查看分组情况

sr1.value_counts()

sr2.value_counts()

# 3)转换成one-hot编码

pd.get_dummies(sr1, prefix="height1")

pd.get_dummies(sr2, prefix="height2")

8. 合并

8.1 按方向合并

pd.concat([data1, data2], axis=1):axis:0为列索引,列值2;1为行索引,行值2。字段不一致时会产生缺失值 nan;

code10 按方向合并代码示例

# 1.读取数据

stock = pd.read_csv("../../resources/p00_data_mining/stock_day.csv")

p_change = stock["p_change"]

# 2.自定义分组

bins = [-100, -7, -5, -3, 0, 3, 5, 7, 100]

sr = pd.cut(p_change, bins)

# 3.离散化 one-hot

stock_change = pd.get_dummies(sr, prefix="rise")

# 4.处理好的one-hot编码与原数据合并

pd.concat([stock, stock_change], axis=1) # 列索引合并,行值*2

pd.concat([stock, stock_change], axis=0).head()

8.2 按索引合并

pd.merge(left, right, how="inner", on=[]):

left:DataFrame 数据;right:DataFrame 数据;on:索引;how:如何合并。inner:内连接(共有字段做全连接);outer:外连接(全连接);left:左连接(左表保留做全连接);right:右连接; 以 key1,key2 作为索引链接为例:内连接: 左连接: 右连接: 外连接:

code11 按索引合并代码示例

left = pd.DataFrame({'key1': ['K0', 'K0', 'K1', 'K2'],

'key2': ['K0', 'K1', 'K0', 'K1'],

'A': ['A0', 'A1', 'A2', 'A3'],

'B': ['B0', 'B1', 'B2', 'B3']})

right = pd.DataFrame({'key1': ['K0', 'K1', 'K1', 'K2'],

'key2': ['K0', 'K0', 'K0', 'K0'],

'C': ['C0', 'C1', 'C2', 'C3'],

'D': ['D0', 'D1', 'D2', 'D3']})

# 内连接

pd.merge(left, right, how="inner", on=["key1", "key2"])

# 左连接

pd.merge(left, left, how="left", on=["key1", "key2"])

# 外连接

pd.merge(left, right, how="outer", on=["key1", "key2"])

9. 交叉表与透视表

交叉表和透视表:寻找两个列之间的关系,相当于以某个标签进行分组,一个统计分组个数,一个统计分组比例;交叉表:计算一列数据对于另外一列数据的分组个数;透视表:计算一列数据对于另外一列数据的分组比例;

9.1 交叉表

pd.crosstab(data["value1"], data["value2"]):生成交叉表;

9.2 透视表

data.pivot_table(["value1"], index=["value2"]):生成透视表;

code12 交叉表与透视表代码示例

# 探究星期数据以及涨跌幅是好是坏数据

# 1.读取数据

stock = pd.read_csv("../../resources/p00_data_mining/stock_day.csv")

# 2.准备数据

# 星期数据:pandas日期类型

date = pd.to_datetime(stock.index)

stock["week"] = date.weekday

# 涨跌幅数据

stock["pona"] = np.where(stock["p_change"] > 0, 1, 0)

# 3.交叉表

data = pd.crosstab(stock["week"], stock["pona"])

# 3.1 做除法后画图

data.div(data.sum(axis=1), axis=0).plot(kind="bar", stacked=True)

# 4.透视表操作

stock.pivot_table(["pona"], index=["week"])

10. 分组与聚合

分组分组后不能直接看到结果,还要聚合;data.groupby(by="yyy", as_index=False):DataFrame 方式进行分组。按 yyy 进行分组;data["xxx"].groupby(data["yyy"]):Series 方式进行分组。效果同上;分组+聚合:data.groupby(by="yyy", as_index=False)["xxx"].max():按 yyy 进行分组,然后输出每组 xxx 中的最大值;data["xxx"].groupby(data["yyy"]):效果同上,先根据标签拿到 Series,再进行分组;

code13 分组与聚合代码示例

# 1.准备数据

col =pd.DataFrame({'color': ['white','red','green','red','green'], 'object': ['pen','pencil','pencil','ashtray','pen'],'price1':[5.56,4.20,1.30,0.56,2.75],'price2':[4.75,4.12,1.60,0.75,3.15]})

# 2.分组+聚合:进行分组,对颜色分组,price1进行聚合

# 2.1 用dataframe的方法进行分组

col.groupby(by="color")["price1"].max()

# 2.2 Series 方式进行分组

col["price1"].groupby(col["color"]).max()

最后

新人制作,如有错误,欢迎指出,感激不尽!

如需转载,请标注出处!

推荐阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。