机器学习【pandas文件读取与存储、高级处理、电影案例分析】

一 Pandas画图

1 pandas.DataFrame.plot

DataFrame.plot`(*kind='line'*)
kind : str,需要绘制图形的种类
	‘line’ : line plot (default)
	‘bar’ : vertical bar plot
	‘barh’ : horizontal bar plot
    ‘hist’ : histogram
    ‘pie’ : pie plot
    ‘scatter’ : scatter plot

2 pandas.Series.plot

二 文件读取与存储

数据大部分存在于文件当中,所以pandas会支持复杂的IO操作,pandas的API支持众多的文件格式,如CSV、SQL、XLS、JSON、HDF5。

注:最常用的HDF5和CSV文件
在这里插入图片描述

1 CSV

pandas.read_csv(filepath_or_buffer, sep =‘,’, usecols )

​ filepath_or_buffer:文件路径

​ sep :分隔符,默认用","隔开

​ usecols:指定读取的列名,列表形式

读取之前的股票的数据

# 读取文件,并且指定只获取'open', 'close'指标
data = pd.read_csv("./data/stock_day.csv", usecols=['open', 'close'])

            open    close
2018-02-27    23.53    24.16
2018-02-26    22.80    23.53
2018-02-23    22.88    22.82
2018-02-22    22.25    22.28
2018-02-14    21.49    21.92

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:存储不会将索引值变成一列数据
data[:10].to_csv("./data/test.csv", columns=['open'], index=False)

2 HDF5

HDF5文件的读取和存储需要指定一个键,值为要存储的DataFrame

pandas.read_hdf(path_or_buf,key =None,** kwargs),从h5文件当中读取数据

​ path_or_buffer:文件路径

​ key:读取的键

​ return:Theselected object

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

# 读取文件
day_close = pd.read_hdf("./data/day_close.h5")
# 存储文件
day_close.to_hdf("./data/test.h5", key="day_close")
# 再次读取的时候, 需要指定键的名字
new_close = pd.read_hdf("./data/test.h5", key="day_close")

注意:优先选择使用HDF5文件存储

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

3 JSON

JSON是常用的一种数据交换格式,前面在前后端的交互经常用到,也会在存储的时候选择这种格式。所以需要知道Pandas如何进行读取和存储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.按照什么方式进行读取

​ ‘split’ : dict like {index -> [index], columns -> [columns], data -> [values]}

​ split 将索引对索引,列名对列名,数据对数据。将三部分都分开了

​ ‘records’ : list like [{column -> value}, … , {column -> value}]

​ records 以columns:values的形式输出

​ ‘index’ : dict like {index -> {column -> value}}

​ index 以index:{columns:values}...的形式输出

​ ‘columns’ : dict like {column -> {index -> value}},默认该格式

​ colums 以columns:{index:values}的形式输出

​ ‘values’ : just the values array

​ values 直接输出值

​ lines : boolean, default False,按照每行读取json对象

​ typ : 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.to_json(path_or_buf=None, orient=None, lines=False)

​ 将Pandas 对象存储为json格式

path_or_buf=None:文件地址

​ orient:存储的json形式,{‘split’,’records’,’index’,’columns’,’values’}

​ lines:一个对象存储为一行

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

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}...

三 缺省值处理

1 如何处理NaN

NaN为float类型

获取缺失值的标记方式(NaN或者其他标记方式),如果缺失值的标记方式是NaN,则判断数据中是否包含NaN:

  • pd.isnull(df),
  • pd.notnull(df)

存在缺失值nan:①删除存在缺失值的:dropna(axis=‘rows’),不会修改原数据,需要接受返回值,②替换缺失值:fillna(value, inplace=True)

  • value:替换成的值
  • inplace:True:会修改原数据,False:不替换修改原数据,生成新的对象

如果缺失值没有使用NaN标记,比如使用"?",先替换“?”为np.nan,然后继续处理

2 电影数据的缺失值处理

# 读取电影数据
movie = pd.read_csv("./data/IMDB-Movie-Data.csv")
# 是缺失值返回true,否则返回false
pd.isnull(movie)
# 如果有一个缺失值,就返回true
np.any(pd.isnull(movie))
# 是缺失值返回false,否则返回true
pd.notnull(movie)
# 只要有一个缺失值,就返回false
np.all(pd.notnull(movie))

(1)存在缺失值nan,并且是np.nan

删除缺失值

pandas删除缺失值,使用dropna的前提是,缺失值的类型必须是np.nan

# 不修改原数据
movie.dropna()

# 可以定义新的变量接收或者用原来的变量名
data = movie.dropna()
替换缺失值
# 替换存在缺失值的样本的两列
# 替换填充平均值,中位数
# Revenue (Millions)为要进行处理的列名
# fillna中第一个参数为替换成谁,第二个参数为是否对原值进行修改
# movie['Revenue (Millions)'].fillna(value=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)

(2)缺失值不是nan,有默认标记?

# 读取文件
wis = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data")

先替换“?”为np.nan

​ df.replace(to_replace=, value=)

​ to_replace:替换前的值

​ value:替换后的值

# 把一些其它值标记的缺失值,替换成np.nan
wis = wis.replace(to_replace='?', value=np.nan)

进行缺失值的处理

# 删除
wis = wis.dropna()

四 数据离散化

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

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

离散化有很多种方法,这使用一种最简单的方式去操作

  • 原始人的身高数据:165,174,160,180,159,163,192,184
  • 假设按照身高分几个区间段:150~165, 165~180, 180~195

这样将数据分到了三个区间段,可以对应的标记为矮、中、高三个类别,最终要处理成一个"哑变量"矩阵

1 股票的涨跌幅离散化

先读取股票的数据,筛选出p_change数据

data = pd.read_csv("./data/stock_day.csv")
p_change= data['p_change']

(1)将股票涨跌幅数据进行分组

使用的工具:

​ pd.qcut(data, q):

​ 对数据进行分组将数据分组,一般会与value_counts搭配使用,统计每组的个数

​ series.value_counts():统计分组次数

# 自行分组
qcut = pd.qcut(p_change, q=10)
# 计算分到每个组数据个数
qcut.value_counts()

自定义区间分组:

  • pd.cut(data, bins)
# 自己指定分组区间
bins = [-100, -7, -5, -3, 0, 3, 5, 7, 100]
p_counts = pd.cut(p_change, bins)

(2)将股票涨跌幅分组数据变成one-hot编码

把每个类别生成一个布尔列,这些列中只有一列可以为这个样本取值为1,其又被称为热编码。

pandas.get_dummies(data, prefix=None)

​ data:array-like, Series, or DataFrame

​ prefix:分组名字

# 得出one-hot编码矩阵
dummies = pd.get_dummies(p_counts, prefix="rise")

五 合并

如果数据由多张表组成,那么有时候需要将不同的内容合并在一起分析

pd.concat([data1, data2], axis=1)

​ 按照行或列进行合并,axis=0为列索引,axis=1为行索引

# 按照行索引进行
pd.concat([data, dummies], axis=1)

​ pd.merge(left, right, how=‘inner’, on=None)

​ 可以指定按照两组数据的共同键值对合并或者左右各自

left: DataFrame

right: 另一个DataFrame

on: 按照哪个键进行拼接

​ how:按照什么方式连接

Merge methodSQL Join NameDescription
leftLEFT OUTER JOINUse keys from left frame only
rightRIGHT OUTER JOINUse keys from right frame only
outerFULL OUTER JOINUse union of keys from both frames
innerINNER JOINUse intersection of keys from both frames

1 内连接

# 创建左表
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']})

# 默认内连接
result = pd.merge(left, right, on=['key1', 'key2'])

结果如下:只有当K0和K1同时存在时才保留数据
在这里插入图片描述

2 左连接

result = pd.merge(left, right, how='left', on=['key1', 'key2'])

左连接结果:
在这里插入图片描述

3 右连接

result = pd.merge(left, right, how='right', on=['key1', 'key2'])

在这里插入图片描述

4 外连接

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

在这里插入图片描述

六 交叉表与透视表

探索两列数据之间存在的关系

交叉表用于计算一列数据对于另外一列数据的分组个数(用于统计分组频率的特殊透视表)

​ pd.crosstab(value1, value2),返回具体的数量

透视表是将原有的DataFrame的列分别作为行索引和列索引,然后对指定的列应用聚集函数

​ data.pivot_table(),返回百分占比

​ DataFrame.pivot_table([], index=[])

# 寻找星期几跟股票涨跌的关系
# 1、先把对应的日期找到星期几
date = pd.to_datetime(data.index).weekday
data['week'] = date

# 2、假如把p_change按照大小去分类,0为界限
data['posi_neg'] = np.where(data['p_change'] > 0, 1, 0)

# 通过交叉表找寻两列数据的关系
count = pd.crosstab(data['week'], data['posi_neg'])

对于每个星期一等的总天数求和,运用除法运算求出比例

# 算数运算,先求和
sum = count.sum(axis=1).astype(np.float32)

# 进行相除操作,得出比例
pro = count.div(sum, axis=0)

使用plot画出这个比例,使用stacked的柱状图

pro.plot(kind='bar', stacked=True)
plt.show()

使用透视表,刚才的过程更加简单

# 通过透视表,将整个过程变成更简单一些
data.pivot_table(['posi_neg'], index='week')

七 分组与聚合

分组与聚合通常是分析数据的一种方式,通常与一些统计函数一起使用,查看数据的分组情况

交叉表与透视表也有分组的功能,所以算是分组的一种形式,只不过他们主要是计算次数或者计算比例

类似于Hadoop中MapReduce对应的Map与Reduce阶段
在这里插入图片描述

DataFrame.groupby(key, as_index=False)

​ key:分组的列数据,可以多个

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

color    object    price1    price2
0    white    pen    5.56    4.75
1    red    pencil    4.20    4.12
2    green    pencil    1.30    1.60
3    red    ashtray    0.56    0.75
4    green    pen    2.75    3.15

进行分组,对颜色分组,price进行聚合

# 分组,求平均值
col.groupby(['color'])['price1'].mean()
col['price1'].groupby(col['color']).mean()

color
green    2.025
red      2.380
white    5.560
Name: price1, dtype: float64

# 分组,数据的结构不变
col.groupby(['color'], as_index=False)['price1'].mean()

color    price1
0    green    2.025
1    red    2.380
2    white    5.560

2 星巴克零售店铺数据

想知道美国的星巴克数量和中国的哪个多,或者想知道中国每个省份星巴克的数量的情况

数据来源:https://www.kaggle.com/starbucks/store-locations/data

# 导入星巴克店的数据
starbucks = pd.read_csv("./data/starbucks/directory.csv")
# 进行分组聚合
# 按照国家分组,求出每个国家的星巴克零售店数量
count = starbucks.groupby(['Country']).count()
# 绘制图像
count['Brand'].plot(kind='bar', figsize=(20, 8))
plt.show()
# 降序排序,取前20个
count['Brand'].sort_values(ascending=False)[:20].plot(kind='bar', figsize=(20, 8))
# 加入省市一起进行分组
# 设置多个索引,set_index()
starbucks.groupby(['Country', 'State/Province']).count()

这个结构与MultiIndex结构类似

八 案例

1 需求

现在我们有一组从2006年到2016年1000部最流行的电影数据

数据来源:https://www.kaggle.com/damianpanek/sunday-eda/data

问题1:想知道这些电影数据中评分的平均分,导演的人数等信息,应该怎么获取?

问题2:对于这一组电影数据,如果想rating,runtime的分布情况,应该如何呈现数据?

问题3:对于这一组电影数据,如果希望统计电影分类(genre)的情况,应该如何处理数据?

2 实现

首先获取导入包,获取数据

%matplotlib inline
import pandas  as pd 
import numpy as np
from matplotlib import pyplot as plt
#文件的路径
path = "./data/IMDB-Movie-Data.csv"
#读取文件
df = pd.read_csv(path)

2.1 问题一

想知道这些电影数据中评分的平均分,导演的人数等信息,应该怎么获取?

得出评分的平均分,使用mean函数

df["Rating"].mean()

得出导演人数信息,求出唯一值,然后进行形状获取

## 导演的人数
# df["Director"].unique().shape[0]
np.unique(df["Director"]).shape[0]

644

2.2 问题二

对于这一组电影数据,如果想rating,runtime的分布情况,应该如何呈现数据?

直接呈现

以直方图的形式,选择分数列数据,进行plot,但是这种方法显示的横纵轴显示不够直观

df["Rating"].plot(kind='hist',figsize=(20,8))
改进后的

Rating进行分布展示,进行绘制直方图

plt.figure(figsize=(20,8),dpi=80)
plt.hist(df["Rating"].values,bins=20)
plt.show()

修改刻度的间隔

# 增加x轴刻度,求出最大最小值
max_ = df["Rating"].max()
min_ = df["Rating"].min()

# 生成x刻度列表
t1 = np.linspace(min_,max_,num=21)

# [ 1.9    2.255  2.61   2.965  3.32   3.675  4.03   4.385  4.74   5.095  5.45   5.805  6.16   6.515  6.87   7.225  7.58   7.935  8.29   8.645  9.   ]

# 修改刻度
plt.xticks(t1)

# 添加网格
plt.grid()
Runtime (Minutes)分布展示

进行绘制直方图

plt.figure(figsize=(20,8),dpi=80)
plt.hist(df["Runtime (Minutes)"].values,bins=20)
plt.show()

修改间隔

# 求出最大最小值
max_ = df["Runtime (Minutes)"].max()
min_ = df["Runtime (Minutes)"].min()

# # 生成刻度列表
t1 = np.linspace(min_,max_,num=21)

# 修改刻度
plt.xticks(np.linspace(min_,max_,num=21))

# 添加网格
plt.grid()

2.3 问题三

对于这一组电影数据,如果希望统计电影分类(genre)的情况,应该如何处理数据?

思路分析:

  • 创建一个全为0的dataframe,列索引置为电影的分类,temp_df
  • 遍历每一部电影,temp_df中把分类出现的列的值置为1
  • 求和

创建一个全为0的dataframe,列索引置为电影的分类,temp_df

# 进行字符串分割
temp_list = [i.split(",") for i in df["Genre"]]
# 获取电影的分类
genre_list = np.unique([j for i in temp_list for j in i]) 
# 增加新的列,行为电影个数,列为分类个数
temp_df = pd.DataFrame(np.zeros([df.shape[0],genre_list.shape[0]]),columns=genre_list)

遍历每一部电影,temp_df中把分类出现的列的值置为1

for i in range(1000):
    #temp_list[i] ['Action','Adventure','Animation']
    temp_df.ix[i,temp_list[i]]=1
print(temp_df.sum().sort_values())

求和,绘图

temp_df.sum().sort_values(ascending=False).plot(kind="bar",figsize=(20,8),fontsize=20,colormap="cool")

Musical        5.0
Western        7.0
War           13.0
Music         16.0
Sport         18.0
History       29.0
Animation     49.0
Family        51.0
Biography     81.0
Fantasy      101.0
Mystery      106.0
Horror       119.0
Sci-Fi       120.0
Romance      141.0
Crime        150.0
Thriller     195.0
Adventure    259.0
Comedy       279.0
Action       303.0
Drama        513.0
dtype: float64
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneTenTwo76

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值