机器学习入门 05 —— Pandas使用

Posted 土豆的热爱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器学习入门 05 —— Pandas使用相关的知识,希望对你有一定的参考价值。


系列文章

机器学习入门 01 —— 机器学习概述
机器学习入门 02 —— 环境搭建(Jupyter Notebook 及扩展库的安装与使用)
机器学习入门 03 —— Matplotlib使用
机器学习入门 04 —— Numpy使用
机器学习入门 05 —— Pandas使用
机器学习入门 06 —— Seaborn使用


5 Pandas

学习目标:

  • 了解Numpy与Pandas的不同

  • 说明Pandas的Series与Dataframe两种结构的区别

  • 了解Pandas的MultiIndex结构

  • 应用Pandas实现基本数据操作

  • 应用Pandas实现数据的合并

  • 应用crosstab和pivot_table实现交叉表与透视表

  • 应用groupby和聚合函数实现数据的分组与聚合

  • 了解Pandas的plot画图功能

  • 应用Pandas实现数据的读取和存储

5.1 Pandas介绍

 

  • 是专门用于数据挖掘的开源Python库
  • 以Numpy为基础,利用了Numpy模块在计算方面高性能的优势
  • 基于Matplotlib,能够简便快速地画图
  • 有着独特的数据结构

有了numpy和matplotlib,为什么还要使用Pandas?

  • 读取文件方便

  • 封装了Matplotlib和Numpy的画图与计算

  • Pandas可以增强图表可读性:左边是原生的数据显示,右边是用Pandas的显示。

  • 便捷的数据处理能力:Pandas可以显示的数据长度更长

 

5.2 Pandas数据结构

Pandas中有三种数据结构:

  • Series:对应一维数组
  • DataFrame:对应二维数组
  • MultiIndex(Panel):对应三维数组

 

1 Series

Series是类似于一维数组的数据结构,它能存储任何类型的数据。Series由索引和数据构成。

 

创建Series

import pandas as pd
pd.Series(data=None, index=None, dtype=None)
data:传入的数据,可以是ndarry、列表、字典、元祖等。
index:索引,要求是唯一值,且数量和data一一对应。如果没有传入索引,则默认从0开始。如果data是字典,索引就是key。
dtype:数据类型。

 

Series属性

 

2 DataFrame

DataFrame类似于二维数组,它就像一个表格,所以既有行索引又有列索引。

 

创建DataFrame

import pandas as pd
pd.DataFrame(data=None, index=None, columns=None)

index:行标签。如果没有传入,则默认创建0-N作为索引。
columns:列标签。如果没有传入,则默认创建0-N作为索引。

 

DataFrame属性

 

重置索引

reset_index(drop=False)设置新的下标索引(0-N)。drop如果为True表示要删除原来的索引值。

 

设置某列值为新索引

set_index(keys, drop=True)设置keys为新索引,drop默认为True,删除原索引。

上面把年份和月份都设置为索引,这其实就是一个MultiIndex(多重索引)

 

3 MultiIndex

MultiIndex是三维的数据结构,多重索引,其实就是在Series、DataFrame对象上拥有两个或两个以上的索引的结构。

我们打印下刚刚的年月份的索引:

创建MultiIndex

 

5.3 基本数据操作

为了更好的理解这些基本操作,这里的例子会先读取一个真实的文件数据。(关于文件操作后面会介绍,这里看看就行)

# 读取文件(csv文件其实就是Excel)
data = pd.read_csv('./stock_day.csv')

# 删除一些列,让数据更简单,再进行后面操作
data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)

data.head(3)

 

1 索引操作

直接操作

要特别注意,Pandas直接操作索引是先列后行,和列表、Numpy的先行后列不同!!

# 直接使用列行操作(注意,是先列后行且不能切片。这和列表、Numpy的先行后列不同)
data['open']['2018-02-27'] # 获取到 23.53

# 下面的用法是错误的
data['2018-02-27']['open'] # 不能先行后列

data[:1][:2] # 不能使用切片

loc和iloc

# 使用loc就是先行后列,还可以使用切片(注意,不能用[][],只能[: , :])
data.loc['2018-02-27':'2018-02-23','open':'close']
# 使用iloc也是先行后列,但用的是索引下标而不是索引值
data.iloc[:4, :3]
# loc和iloc混合使用(原理上还是一样的)
# 第一个参数实质上还是传递索引值
data.loc[data.index[0:4], ['open', 'close', 'high', 'low']] 
# 第二个参数实质上还是传递索引下标
data.iloc[0:4, data.columns.get_indexer(['open', 'close', 'high', 'low'])]

 

2 赋值操作

# 把'close'列全部赋值为1
data.close = 1 # 或者 data['close'] = 1

# 把'close'列 '2018-02-27'行 赋值为2
data.loc['2018-02-27', 'close'] = 2

# 把第4列大于23的赋值为0
data[data.iloc[:,3]>22]=0

data.head(3)

 

3 排序

Series和DataFrame都可以进行排序,根据索引排序,也可以根据值排序。

DataFrame排序

  • sort_values(by=keys,ascending=True):根据值排序。by是排序参考的键(可以多个),ascending为True是升序(默认)。
  • sort_index(ascending=True):根据索引排序。升序。
# 根据值排序,返回一个新对象,不会改变原来对象; 根据'open'列,升序;
data.sort_values('open', ascending=True).head(3)

# 根据'open'列和'high'列,降序;(如果open相同才比较high)
data.sort_values(['open','high'], ascending=False).head(3)

# 根据索引 从小到大
data.sort_index().head(3)

Series排序

由于Series只有一列,所以不需要传入参数,要么根据值排序要么根据索引排序。

  • sort_values(ascending=True):根据值排序。ascending=True升序(默认)。
  • sort_index(ascending=True):根据索引排序。
# 将DataFrame中某一列取出来就是Series
# 利用Series的值排序 升序
data['open'].sort_values(ascending=True).head(3)

# 利用Series的索引 降序
data['open'].sort_index(ascending=False).head(3)

 

5.4 运算

1 算数运算

# 加法 'open'列每个元素+10
data['open'].add(10) # 等价于 data['open']+10

# 减法 'open'
data['open'].sub(10)

# 乘法
data['open'].mul(10)

# 除法
data['open'].div(10)

 

2 逻辑运算

# 筛选 'open' > 23的数据
a = data['open'] > 23 # 每一行 会返回True或False
data[a] # 获取 'open' > 23的数据

# 多个逻辑运算符
data[(data['open'] > 23) & (data['open'] < 24) ]

# 使用逻辑运算符函数 query(表达式)
data.query('open > 23 & open < 24')

# 判断 ‘open'列 有某个元素
b = data['open'].isin([23.53, 23.85]) # 会对每行的'open'进行判断,返回True或False
data[b] # 获取'open'是23.53 或者 23.85的数据

 

3 统计运算

下面的函数可以对Series和DataFrame操作。对于DataFrame的统计函数,都有参数axisaxis=0表示对列进行统计(默认),axis=1表示对行进行统计。

统计函数描述
sum()求和
mean()平均值
median()中位数(是从小到大的中间一位数字)
min()最小值
max()最大值
mode()众数(出现次数最多的)
abs()绝对值
prod()标准差
std()标准差
var()方差
idxmax()最大值的索引
idxmin()最小值的索引
cumsum()对某一列累计求和
cummax()对某一列累计求最大值
cummin()对某一列累计求最小值
cumprod()对某一列累计求积

 

4 自定义运算

可以自己定义函数进行运算

'''
apply(function, axis=0)
function:自定义的函数;axis:0 对列,1对行。
'''

def function(x):
    return x.max() - x.min()

# 举例 下面定义一个队列 求最大值与最小值的差值
# 等价于 data[['open', 'close']].apply(function)
data[['open', 'close']].apply(lambda x: x.max() - x.min())

 

5.5 画图

Pandas中封装了Matplotlib的画图,所以用法大致相同。在Pandas中使用画图函数plot,同时,需要先导入Matplotlib。

无论是DataFrame还是Series都是使用plot()画图。

DataFrame.plot(kind='line')

  • kind=‘line’,表示要画折线图(默认)
  • kind=‘bar’,柱状图,加上参数stacked=True就是堆积柱状图
  • kind=‘barh’,水平方向柱状图
  • kind=‘hist’,直方图
  • kind=‘pie’,饼图
  • kind=‘scatter’,散点图

下面举个简单例子:

import matplotlib.pyplot as pltimport pandas as pd# 读取文件data = pd.read_csv('./Pandas测试数据.csv')# 删除一些列,让数据更简单,再进行后面操作data = data.drop(["ma5","ma10","ma20","v_ma5","v_ma10","v_ma20"], axis=1)# 排序data = data.sort_index()data = data['p_change'].cumsum()data.plot()plt.show() # 之所以要导入matplotlib,是因为show()后才能显示

 

5.6 文件读取与存储

我们的数据大部分都存储在文件中,而Pandas支持多种文件操作,例如CSV、HDF5、JSON、SQL、XLS等。

最常用的是HDF5和CSV。优先选择HDF5:

  • HDF5在存储的时候支持压缩,使用的方式是blosc,这个是速度最快的也是pandas默认支持的
  • 使用压缩可以提磁盘利用率,节省空间
  • HDF5还是跨平台的,可以轻松迁移到hadoop 上面

下面这张表是常用API

 

1 CSV

'''
读取CSV
pandas.read_csv(filepath_or_buffer, sep=',', usecols)
filepath_or_buffer:文件路径
sep:分隔符,默认用,
usecols:指定读取的列名(用列表类型)
''' 
data = pd.read_csv('./Pandas测试数据.csv', usecols=['open', 'close'])


'''
写入csv
DataFrame.to_csv(path_or_buf=None, sep=',', columns=None, header=True, index=True, mode='w', encoding=None)
path_of_buf:文件路径
sep:分隔符
columns:要写入的列索引
header:是否写入【列索引】
index:是否写入【行索引】
mode: 'w'重写,'a'追加
encoding:编码格式
'''
# 通常我们写入文件时,会把行索引也写入进去,行索引会变成一列数据,所以我们可以用index=False不写入行索引
data[:10].to_csv('test.csv', columns=['open'],index=False)

 

2 HDF5

'''
写入HDF5
DataFrame.to_hdf(path_or_buf, key)
path_or_buffer:文件路径
key:读取的键(HDF5的读取和存储都要指定一个key)
'''
data.to_hdf('hdf5_data.hdf', 'HDF5_DATA')


'''
读取HDF5(读取需要导入tables模块)
pandas.read_hdf(path_or_buf, key=None)
path_or_buffer:文件路径
key:读取的键(HDF5的读取和存储都要指定一个key)
'''
data = pd.read_hdf('hdf5_data.hdf','HDF5_DATA')

 

3 JSON

JSON存储形式有几种:

  • ‘split’:将索引、列名、数据三种分开。形如{index -> [index], columns -> [columns], data -> [values]}
  • ’records’:形如columns:values,通常用这种。
  • ‘index’:形如index:{columns:values}...
  • ’columns’:形如columns:{index:values}
  • ‘values’:直接输出值
'''
JSON的存储
DataFrame.to_json(path_or_buf=None, orient=None, lines=False)
path_or_buf:文件路径
orient:存储JSON的形式 【'split'、'records','index','colummns','values'】
lines:一个对象存储一行(建议设置为True)
'''
data.to_json('jsondata.json', orient='records')

'''
pandas.read_json(path_or_buf=None, orient=None, typ='frame', lines=False)
typ : default ‘frame’, 指定转换成的对象类型series或者dataframe
'''
pd.read_json('jsondata.json',orient='records')

 

5.7 缺失值处理

我们获取到的数据不一定都是完整的,可能某个数据有缺失,所以我们需要先对错误数据进行处理。

  • 缺失的表现形式可能是NaN或者?之类的,需要我们先查看数据进行判断。
  • 如果缺失值的标记方式是NaN
    • 用来判断NaN的函数:pd.isnull(DataFrame)pd.notnull(DataFrame)
    • 存在缺失值:
      • 如果缺失值数量少,则删除。数量多,则替换。
      • 删除缺失值(不会改变原表,只返回新表):dropna(axis='rows)'
      • 替换缺失值:fillna(value, inplace=True),其中value替换的值,inplace=True会修改原表。
  • 如果缺失值不是NaN而是?之类的
    • 先将?替换为NaN(),再按上述方式处理。

下面进行举例说明:

  1. 判断缺失值是否存在
  1. 删除缺失值NaN
  1. 替换缺失值NaN
  1. 对于非NaN的缺失值,例如?这是下面的链接

 

5.8 数据离散化

1 数据离散化介绍

为什么要数据离散化

连续数据离散化是为了简化数据结构,数据离散化技术可以用来减少给定连续属性值的个数。离散化方法经常作为数据挖掘的工具。

 

什么是数据离散化

就是在连续数据的值域上,将值域划分为若干个离散的区间,最后用不同的符号或整数值代表落在每个子区间中的属性值。下面举个栗子:

  • 原始人的身高数据:165,174,160,180,159,163,192,184
  • 假设按照身高分几个区间段:150~165, 165~180, 180~195
  • 我们将数据分到了三个区间段,每个数据可以对应到矮、中、高三个类别的区间,最终要处理成一个"哑变量"矩阵(后面有解释)

 

One-Hot编码

在很多学习任务中,特征并不总是连续值,而有可能是分类值。

离散特征的编码分为两种情况:

1、离散特征的取值之间没有大小的意义,比如color:[red,blue],那么就使用one-hot编码

2、离散特征的取值有大小的意义,比如size:[X,XL,XXL],那么就使用数值的映射{X:1,XL:2,XXL:3}

One-Hot编码又称为独热编码(或哑变量 dummy variable),我们把数据离散化后的每个类别区间转为布尔列,这些列中只有一个可以为True(1)。例如下面这种表格,把【Human、Penguin、Octopus、Alien】分为了四个布尔列。

 

2 API介绍

  • pd.qcut(data, q):返回Series。对数据进行分组(区间是自动分配的),q是分组个数。通常会再搭配value_counts()用来统计每组里数据个数。
  • pd.cut(data, bins):返回Series。也是对数据分组,但区间由自己指定。bins是分组区间。
  • pd.get_dummines(data, prefix=None):data是Series或者DataFrame,prefix是分组的名称。

下面举例:

# 读取CSV数据(某日股票数据)
data = pd.read_csv('stock_day.csv')
p_change = data['p_change']
qcut = pd.qcut(p_change, 10) # 将p_change分10组
qcut.value_counts() # 查看每组的数据个数

 

bins = [-100, -7, -5, -3, 0, 3, 5, 7, 100]
cut = pd.cut(p_change, bins) # 将p_change按bins分组
cut.value_counts() # 查看每组的数据个数

 

# 查看热编码
pd.get_dummies(cut).head()

 

5.9 表格合并

有时候我们会想讲多张表格合并在一起,就需要用到pd.concat()或者pd.merge()

  • pd.concat([data1, data2], axis=1),第一个参数是表格数据的列表,第二个参数为1则按行索引合并,为0则按列索引合并。
# 将刚刚的One-Hot编码与原数据合并
data = pd.read_csv('stock_day.csv')
bins = [-100, -7, -5, -3, 0, 3, 5, 7, 100]
cut = pd.cut(p_change, bins)
dummies = pd.get_dummies(cut, prefix='rise')

pd.concat([data, dummies], axis=1) # 按行索引
  • pd.merge(left, right, how='inner', on=None)
    • 可以指定安装两组数据的共同键值对合并或按照左右各自合并。
    • left:左表(DataFrame)
    • right:右表(DataFrame)
    • on:指定共同的键(如果不指定就是左右表各自合并)
    • how:按什么方式连接(和数据库的表连接类似,inner、left、right、outer)
left = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
                     'B': ['B0', 'B1', 'B2', 'B3'],
                     'key1': ['K0', 'K0', 'K1', 'K2'], 
                     'key2': ['K0', 'K1', 'K0', 'K1']}) 
right = pd.DataFrame({'C': ['C0', 'C1', 'C2', 'C3'],
                      'D': ['D0', 'D1', 'D2', 'D3'],
                      'key1': ['K0', 'K1', 'K1', 'K2'], 
                      'key2': ['K0', 'K0', 'K0', 'K0']}) 

内连接:

# 默认用内连接 inner,使用两个表共同键作为连接点
pd.merge(left, right) # 可以不指定on=['key1', 'key2']

左连接:

# 左连接 
pd.merge(left, right, how='left', on=['key1', 'key2'])

右连接:

# 右连接 
pd.merge(left, right, how='right', on=['key1', 'key2'])

外连接:

# 外连接
pd.merge(left, right, how='outer', on=['key1', 'key2'])

 

5.10 交叉表与透视表

交叉表:用于统计两列数据之间的关系。

透视表:是将原有的DataFrame的列分别作为行索引和列索引,然后对指定的列应用聚集函数【pd.crosstab(列1,列2)

下面用案例进行说明:探究股票涨跌与星期之间的关系(交叉表)。【data.pivot_table([列1..], 索引)

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# 读取股票数据 (索引是 '2018-02-27')
data = pd.read_csv('stock_day.csv')

# 将行索引转换为datatime类型,再将日期转换为对应的星期几。
week = pd.to_datetime(data.index).weekday

# 增加一个新列 星期
data['week'] = week

# 判断涨跌 p_change列,大于0则置为1(涨),小于0则置为0(跌)。并将结果作为新列p_n
data['p_n'] = np.where(data['p_change'] > 0, 1, 0)

# 交叉表:此时得到的是 0 和 1 的统计数量。(即涨跌)———— 看图1
count = pd.crosstab(data['week'], data['p_n'])

# 现在将上面的表转为百分比[例如 63/(63+62)] ———— 看图2
img = count.div(count.sum(axis=1).astype(np.float32), axis=0)

# 绘图 ———— 看图3
img.plot(kind='bar', stacked=True)
plt.show()

图1:

图2:

图3:

从上面可看出,交叉表是统计出两列的数量关系,而透视表是直接得出百分比关系。

data.pivot_table(['p_n'], 'week')

 

5.11 分组与聚合

分组与聚合通常是分析数据的一种方式,通常与一些统计函数一起使用,查看数据的分组情况。其实刚才的交叉表与透视表也有分组的功能,所以算是分组的一种形式,只不过他们主要是计算次数或者计算比例。下面这张图就非常形象。

聚合的内置函数:sum(), mean(), max(), min(), count(), size(), describe()

下面用代码演示:

星巴克案例:

# 读取数据 (数据来自Kaggle)
starbucks = pd.read_csv("directory.csv")

# 按国家分组,并求出每个国家星巴克零售店的数量
count = starbucks.groupby(['Country']).count()

# 绘图显示
count['Brand'].pl ot(kind='bar', figsize=(20, 8))
plt.show()

# 对国家和省份进行分组
starbucks.groupby(['Country', 'State/Province']).count()Pandas高级数据分析快速入门之五——机器学习特征工程篇

Pandas高级数据分析快速入门之六——机器学习预测分析篇

机器学习Numpy&Pandas 快速入门笔记

Python机器学习入门——科学计算库(Pandas)

程序员用于机器学习编程的Python 数据处理库 pandas 入门教程

高端实战 Python数据分析与机器学习实战 Numpy/Pandas/Matplotlib等常用库