Skip to content

Latest commit

 

History

History
1331 lines (1210 loc) · 65.2 KB

udacity_data-mining-course.org

File metadata and controls

1331 lines (1210 loc) · 65.2 KB

udacity的核心课程:数据挖掘工程师直通班,纳米学位。目标:在3到7天的时间里,完成所有数据挖掘课程, 同时还要进行项目练习。用了三天时间看了课程(的绝大多数),第四天先进行总结与整体梳理, 之后再进行项目练习。

总结

project1和project2的许多内容有所重复,project1以概括为主。project2更加深入, 但也不是很深入。虽然project2的许多函数我都用过,并且也可能使用地更细致,但这种课程形式 的讲解正是我所欠缺的。课程的学习可以将之前学会的零碎知识串联起来,对big picture有更好地 理解。可以消除只见树木不见森林的迷惘,与不踏实感,是很有必要的。主体结构有了之后,再自学就 更高效了。

整个流程再现

# 1.提问
# 2.整理数据
# 3.EDA
# 4.得出结论
# 5.传达结果

# 提问
## 1.1.我想要研究的问题是什么?
## 1.2.我对于这个问题有什么假设?需要什么数据来验证?
## 1.3.如何来获得数据?数据的每列都代表什么?

# 2.整理数据
## 2.1 收集数据(从html文件解析,加载到pandas)
import os
path = '/home/ligy/Documents/workspace-data_analysis'
file_name = 'downllad_html.txt'
if not os.path.exists(path):
    os.makedirs(path)
url = 'http://www.lzu.edu.cn' # 这个网址可以吗?

import requests
response = requests.get(url)
with open(os.path.join(path, file_name)) as f:
    f.write(response.content)

from bs4 import BeautifulSoup
import glob
l = []
for files in glob.glob('/home/ligy/Download/workspace-data_analysis/*_html*.txt'):
    with open(files, 'r') as f:
        soup = BeautifulSoup(f, 'lxml')
        title = soup.find('title').contents[0]
        dates = soup.find_all('div', class_= 'datetime').contents[0]
        d = {'title': title, 'date': dates}
        l.append(d)
df = pd.DataFrame(l)

## 2.1 收集数据(从csv文件加载到pandas)
new_columns = list('abcdef')
df = pd.read_csv(os.path.join(path, filename),
                 header=0, # {0, None, int}默认0,从文件第int列开始读取,以第int列作为列名
                 skiprows=4, # 跳过前4行
                 name=new_columns# 以新的列名替换旧列名
                 index_col='Name') # 以name作为列指标

## 2.1 收集数据(从zip文件载入文件)
import zipfile
with zipfile.ZipFile('file.zip', 'r') as f_zip:
    f_zip.extractall() # 解压zip文件
pd.read_csv('file.csv')
#pd.read_csv('file.csv.gz.tar') # 直接读取压缩文件?

## 2.2 评估数据(目测、编程)
### 质量问题(脏数据):完整性(缺失值)、有效性(冗余、异常值、类型错误)、准确性、一致性
### 结构问题(乱数据)
### 发现问题(可以用初步的可视化)、记录问题
df.info()
df.head()
df.tail()
df.sample(10)
df.sex.value_counts()
df.isnull().sum()
df[df.isnull().T.any()] # 显示有空值的行
df[df.age.isnull()]
df.age.notna()
df.describe()
df.loc[df.age > 50, :]
df.duplicated()
df.age.duplicated()
df.sex.value_counts().plot(kind='bar') # (针对分类型变量)绘制柱状图
df.height.plot(kind='box')             # (针对离散数值型变量)绘制箱线图
df.age.hist(bins=30)                   # (针对连续数值型变量)绘制直方图

## 2.3 清理数据
### pandas快速入门
#https://pandas.pydata.org/pandas-docs/stable/getting_started/10min.html
#https://pandas.pydata.org/pandas-docs/stable/getting_started/basics.html
### 清理方案
### 清理记录
### 检验效果

### 备份原数据!
df_clean = df.copy()
### 先清理缺失值
df_clean.fillna(0, inplace=True)
df_clean.dropna(axis=0, # 0或index, 1或columns,丢弃有空值的行或列
                subset=['age'], # 不是要丢弃维度的另一维度的数组,如为columns时丢弃这一列的空行
                thresh=10, # 超过阀值时丢弃
                how='any', # any指只要有空值就丢弃;all指当行或列全为空时丢弃
                inplace=True) # 是否inplace改变
df_clean.drop('age', axis=1) # 0或index, 1或columns,丢弃行或列
df_clean.drop(labels=['age', 'height'], index=150, inplace=True)
# 用每个国家的GDP平均值填充缺失值
df_clean.groupby('Country Name')['GDP'].transform(lambda x: x.fillna(x.mean()))
# 向前向后填充(要先排序!)
df_clean.sort_values('year').groupby('Country Name')['GDP'].fillna(method='ffill')
df_clean.sort_values('year').groupby('Country Name')['GDP'].fillna(method='bfill')

### 再解决整洁度问题
### 合并merge,共用列为['Country Name', 'year']
df_clean = gdp.merge(population, on=('Country Name', 'year'))
### 融合melt,以下操作后变成三列,相当于short form变long form
df_clean = pd.melt(df_clean, id_vars=['Country Name', 'Country Code'], var_name='year', value_name='GDP')
### 拼接concat, append
df_clean = pd.concat([df, dummies], axis=1)
### 字符串操作
df_clean.contact.str.extract(pat, expand=True)
### 邮件地址
pat_email = '([a-zA-Z][a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+[a-zA-Z])'
pat_phone = '((?:\+?\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4})'
df_clean['phone'] = df.contact.str.extract(pat_phone, expand=True)
df_clean['email'] = df.contact.str.extract(pat_email, expand=True)

### 最后解决质量问题
df_clean = pd.to_datetime(df_clean['year'], format='%d-%m-%Y') # 转换时间序列格式
df_clean.dt.year
pd.to_numeric(df_clean.age) # 轮换为数字格式
### Tukey 规则可以找到一维数据中的离群值。其步骤是:
### 找到上四分位数  (ie .25 分位数)
Q1 = df_clean.age.quantile(0.25)
### 找到下四分位数  (ie .75分位数)
Q3 = df_clean.age.quantile(0.75)
### 计算分位数区间 (Q3 - Q1)
IQR = Q3 - Q1
### 任何比Q3 + 1.5 * IQR 大的数是离群值
max_value = Q3 + 1.5 * IQR
### 任何比 Q1 - 1.5 * IQR 小的数是离群值
min_value = Q1 - 1.5 * IQR
outliers = population[(population['population'] > max_value) | (population['population'] < min_value)]
df_clean.drop_duplicates()
df_clean['name'] = df.name.str[2:]
df_clean.zipcode = df_clean.zipcode.astype(str)
### 缩放只能对训练集使用,不能对测试集用!
### scikit-learn 可以实现这个功能,但是在数据工程中,你并不总能找到可用的工具包
### 标准化(standardization)
from sklearn.preprocessing import StandardScaler
### 归一化/正则化 (normalization)
from sklearn.preprocessing import MinMaxScaler
### 每列减去最小值,然后除以范围
from sklearn.preprcessing import normalize
normalize(X_train)
# 3.EDA 探索性数据分析
## 绘图包seaborn, matplotlib,以及pandas自带的绘图功能
## 探索性可视化:用来寻找变量间的关系或隐藏的模式,不必完美
## 解释性可视化:呈现给观众,为了用图或表来回答之前提出的问题
## 特征工程
## 可以用pandas_profiling包方便地一次性完成,但数据时会很慢。

## 3.1 单变量可视化
import seaborn as sns
plt.xtics(rotation=90) # 横坐标刻度旋转90度
# 分类变量用柱状图
sns.countplot(data = df_clean,
              x = 'sex', # 纵向柱状图
              #y = 'sex', # 横向柱状图
              color = sns.color_palette()[0]
              )
df_clean.education.plot(kind='bar')
df_clean.education.plot(kind='pie')
# 3.2 连续数值变量用直方图
df_clean.age.hist(bins=30)
df_clean.age.plot(kind='hist')

## 双变量可视化(研究相关性)
### 数值变量vs数值变量 用 scatterplots(散点图)
plt.scatter(data = df, x = 'num_var1', y = 'num_var2', alpha=0.3)
### Seaborn 的 regplot 函数可以创建具有回归拟合的散点图:
sns.regplot(data = df, x = 'num_var1', y = 'num_var2')
### 热图
bins_x = np.arange(0.6, 7+0.3, 0.3)
bins_y = np.arange(0.6, 7+0.3, 0.3)
plt.hist2d(df, x = 'var1', y = 'var2', bins=[bins_x, bins_y])
plt.colorbar()
### 数值变量vs分类变量 用 violin plots(小提琴图)或箱线图。它们都可以通过交换xy变量横过来
sns.violinplot(df_clean, # 小提琴图
               x = 'sex',
               y = 'age',
               color = base_color,
               inner == 'quartile')
sns.boxplot() # 箱线图, 参数同上。上下限之外的点表示异常值

### 分类变量vs分类变量 用 clustered bar charts(分组柱状图)或热图
### 分组柱状图
sns.countplot(data = df_clean, x = 'cat_var1', hue = 'cat_var2')
### 热图
ct_counts = df_clean.groupby(['cat_var1', 'cat_var2']).size()
ct_counts = ct_counts.reset_index(name = 'count')
ct_counts = ct_counts.pivot(index = 'cat_var1', columns = cat_var2', values = 'count'')
sns.heatmap(ct_counts)

## 3.3 多变量可视化
### 两两变量间的关系图
pd.plotting.scatter_matrix(df_clean, figsize=(15,15))
### 对于数值变量,创建相关系数矩阵也是很好的数据探索方式
df_clean.corr() # 有时相关系数也存在误导性

## 3.4 特征工程
# 用旧的特征产生有意义的新特征,来帮助验证你的假设,或提供新的见解
df_clean['ratio'] = df_clean.criminals / df_clean.population
# 将连续数值离散化,可以消除数据噪声
df_clean.age.cut() # 怎么用?

# 4. 得出结论(描述性统计或机器学习建模)
# 对于不同的问题选择适用的机器学习模型,学习并进行预测,并将学习的知识可视化(怎样从结论发掘出知识?)
## 4.1 监督学习
### 4.1.1 回归
### 4.1.2 分类
## 4.2 非监督学习
### 4.2.1 聚类
### 4.2.1 降维
## 4.3 评估模型
### 外部评估指数
### 内部评估指数

## 4.1 监督学习
### 线性模型
from sklearn.linear_model import LinearRegression ## 线性回归
from sklearn.linear_model import SGDRegressor ## 随机梯度下降回归
from sklearn.linear_model import Ridge ## 岭回归,l_{1}正则化
from sklearn.linear_model import Lasso ## Lasso回归,l_{2}正则化
from sklearn.linear_model import ElasticsNet ## 弹性网络,l_{1}与,l_{2}的插值正则化
from sklearn.linear_model import LogisticRegression ## 逻辑回归
### 支持向量机(kernel技巧)
from sklearn.svm import LinearSVR
from sklearn.svm import SVR
from sklearn.svm import LinearSVC
from sklearn.svm import SVC
### 决策树
from sklearn.tree import DecisionTreeRegressor
from sklearn.tree import DecisoinTreeClassifier
### 集成方法
from sklearn.ensemble import VotingClassifier
from sklearn.ensemble import VotingRegressor
from sklearn.ensemble import BaggingClassifier
from sklearn.ensemble import BaggingRegressor
from sklearn.ensemble import RandomForestClassifier
from skelarn.ensemble import RandomForestRegressor
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import ExtraTreesRegressor
from sklearn.ensemble import AdaBoostClassfier
from sklearn.ensembel import GradientBoostingClassifier

## 4.2 非监督学习
### 4.2.1 聚类clustering
from sklearn.cluster import KMeans
from skelarn.cluster import AgglomerativeClustering # 凝聚聚类
agglomerativeClustering(linkage='complete') # ‘ward’, ‘complete’, ‘average’,‘single’
from sklearn.cluster import DBSCAN # 可基于密度降噪
from sklearn.cluster import GaussianMixture
### 4.2.2 PCA主成份分析
from sklearn.decomposition import PCA
### pca的结果要怎么解释呢?
from sklearn.decomposition import RandomizedPCA
### 4.2.3 随机投影(用于特征提取和降维)
from sklearn.random_projection import SparseRandomProjection
### 4.2.4 ICA独立成份分析(用于特征提取和降维)
from sklearn.decomposition import FastICA

## 4.3 评估模型
### 外部评估指数
### 回归
from sklearn.metrics import mean_squared_error
np.sqrt(mean_squared_error(y_pred, y_test)) # 均方根
### 决定系数(coefficient of determination), 𝑅2  结果在0到1之间,1表示完美拟合,
### 一个负的𝑅2表示模型不能够拟合数据决定系数(coefficient of determination),
### 𝑅2结果在0到1之间,1表示完美拟合,一个负的  𝑅2  表示模型不能够拟合数据
dt.score(X_test, y_test) # 决策树回归的计分方式,R2系数
### 或者
from sklearn.metrics import r2_score
r2_score(y_test, y_pred)
### 分类
from sklearn.metrics import classification_report, confusion_matrix
classification_report(y_test, y_pred, target_names=target_names) # 返回多种指标
confusion_matrix(y_test, y_pred, labels=range(n_classes))
### 聚类
# 外部评估指数 adjusted Rand index
from sklearn.metrics import adjusted_rand_score
adjusted_rand_score(y_test, y_pred)
### 内部评估指数 silhouette coeffient 轮廓系数
form sklearn.metrics import silhouette_score
model.fit(X)
labels = model.labels_
silhouette_score(X, labels)
### 相对评估指数

# 5. 传达结果
# 5.1 解释性数据可视化

project1: 用python进行基础数据分析

数据分析的五个步骤

  • 提问
  • 整理数据wrangling(收集,评估,清理)
  • 执行EDA
  • 得出结论(或甚至是做出预测,通常使用机器学习和推理性统计完成),本课使用描述性统计
  • 传达结果

第 1 步:提问 你要么获取一批数据,然后根据它提问,要么先提问,然后根据问题收集数据。在这两种情况下, 好的问题可以帮助你将精力集中在数据的相关部分,并帮助你得出有洞察力的分析。

第 2 步:整理数据 你通过三步来获得所需的数据:收集,评估,清理。你收集所需的数据来回答你的问题, 评估你的数据来识别数据质量或结构中的任何问题,并通过修改、替换或删除数据来清理数据, 以确保你的数据集具有最高质量和尽可能结构化。

第 3 步:执行 EDA(探索性数据分析) 你可以探索并扩充数据,以最大限度地发挥你的数据分析、可视化和模型构建的潜力。探索数据涉及在数据中查找模式,可视化数据中的关系,并对你正在使用的数据建立直觉。经过探索后,你可以删除异常值,并从数据中创建更好的特征,这称为特征工程。

第 4 步:得出结论(或甚至是做出预测) 这一步通常使用机器学习或推理性统计来完成,不在本课程范围内,本课的重点是使用描述性统计得出结论。

第 5 步:传达结果 你通常需要证明你发现的见解及传达意义。或者,如果你的最终目标是构建系统,则通常需要分享构建的结果,解释你得出设计结论的方式,并报告该系统的性能。传达结果的方法有多种:报告、幻灯片、博客帖子、电子邮件、演示文稿,甚至对话。数据可视化总会给你呈现很大的价值。

收集数据、评估数据

csv为comma separated values

import pandas as pd
df = pd.read_csv('file', header=1) # 使用第二行为标题,删除上面行的内容
df = pd.read_csv('student_scores.csv', header=None) # 没标题
labels = ['id', 'name', 'attendance', 'hw', 'test1',
'project1', 'test2', 'project2', 'final'] # 自定义标题
df = pd.read_csv('student_scores.csv', names=labels)
# 替换数据的标题行
df = pd.read_csv('student_scores.csv', header=0, names=labels)
#将一个或多个列指定为数据框的索引
df = pd.read_csv('student_scores.csv', index_col='Name')

执行EDA(探索性数据分析)

DataFrame和Series对matplotlib有封装的绘图函数,但比较简单,复杂的还要用matplotlib.

# 在notebook中查看绘图
%matplotlib inline
# 用分号来隐藏不需要的输出
# hist绘直方图
df.hist(figsize=(10, 8));
# 也可以用在Series上
df['age'].hist();
# 统计值的出现次数,并绘图
df['age'].value_counts().plot(kind='bar') # 直方图
df['age'].value_counts().plot(kind='pie') # 饼状图
df.plot(x='age', y='height', kind='scatter')
df['age'].plot(kind='box'); #箱线图

得出结论

传达结果

Python包概述

包是函数和类等的集合,数据分析最常用动的有Numpy, pandas, matplotlib

import numpy as np
l = list(range(9))
print(np.mean(l))

图表呈现风格

project2:数据整理

lesson1:数据整理简介

最好用程序下载数据(API),而不是在网页直接下载。

用python解压缩文件

zipfile是个上下文管理器,支持with语句。

import zipfile
with zipfile.ZipFile('file.zip', 'r') as myzip:
    myzip.extractall()
#import tarzip
#with tarzip.

已经掌握了数据整理的第一步:收集数据。在这个数据集中,这意味着:

  • 从互联网下载文件,在这种情况下文件是来自 Kaggle 的 zip 文件,
  • 打开 Jupyter Notebook,
  • 使用 Python 解压压缩文件,
  • 然后将解压的 CSV 文件导入 Jupyter Notebook 的 pandas DataFrame。

评估数据assess(用pandas查看info,等)

低质量数据通常被称为脏数据,脏数据存在内容问题。不整洁数据通常被称为 “杂乱” 数据, 杂乱数据存在结构问题。

最好将所有评估记录在数据整理模板评估部分的底部,即清洗标题的正上方。定义清洗操作时, 参考这些记录可使数据清洗更简单,还可以避免使你手忙脚乱。

  • 修正 意义不明的非描述性header(记录问题时应只用名词,问题修改后再用动词表示已经完成)
  • df.info() df.head() df.tail() df.value_counts()

编程数据清洗过程:

  • 定义
  • 编码
  • 测试

定义指以书面形式定义数据清洗计划,其中我们需将评估转变为定义的清洗任务。 这个计划也可作为一个指导清单,所以其他人(或我们自己将来)也可以回顾和重现自己的工作。

编码指将这些定义转换为代码并执行该代码。

测试指测试我们的数据集,通常使用代码,以确保有效完成我们的清洗工作。

清洗

  • header中不要有点号 . ,不然就不能用 df.age 来索引。
df_calen = df_clean.rename(columns={'oldname1': 'newname1', 'oldname2': 'newname2'})
(assert 'ASAP' not in x for x in df_clean.columns) # 可以这样写吗?

重新评估与迭代

整个整理数据的流程通常是要反复迭代的,即使在完成分析之后。

整理、EDA与ETL

lesson2:收集数据

import pandas as pd
pd.read_csv('file.csv', sep='\t')

从网页(HTML文件)中抓取数据

  • 将HTML文件保存在本地(如用Request库),并将文件读入 BeautifulSoup 构造函数中
  • 将HTML响应内容直接读入 BeautifulSoup 构造函数(如用Request库)
import requests
url = 'https://www.rottentomatoes.com/m/et_the_extraterrestrial'
response = requests.get(url)
# save html to file
# work with html memory

关于HTML和CSS的介绍课程

html简介

在两个 <body> 标签之间的内容需要重点关注。如:

<body>
<p>This is a paragraph</p>
<h1>this is heading1</h1>
<span>this is a span</span>
<h2>this is heading1</h2>
<h3>this is heading1</h3>
<body>

都被前后标签包含,后标签有slash。

树结构

被包含就是子结构,如 h1 pdiv 的子结构。

<body>
<div>
<h1>this is heading1</h1>
<p>This is a paragraph</p>
<h2>this is heading1</h2>
</div>
<body>

一个有用的小技巧:

s = 'this is a random string to test a little trick.'
print(s[:-len('trick.')]) # 去掉末尾的字符串

练习:

根据对 HTML 文件结构的了解,你将使用 Beautiful Soup 来提取对于每个 HTML 文件, 我们所需的观众评分指标和观众评分得数,以及上面视频中的电影标题(所以我们稍后将合并数据集), 然后将它们保存在 pandas DataFrame 中。你的任务是提取每个 HTML 文件的标题(电影名)、 观众评分和参与评分观众人数,并三个一组作为字典附加到 df_list 。

from bs4 import BeautifulSoup
import os
folder = 'rt_html'
df_list = []
for html_file in os.listdir(folder):
    with open(os.path.join(folder, html_file), 'r') as f:
        soup = BeautifulSoup(f, 'lxml')
        title = soup.find('title').contents[0][:-len('tomato')]
        score = soup.find('div', class_='audience-score meter').find('span').contents[0][:-1]
        rating_counts = soup.find('div', class_='audience-info')# 方法类似,可以逐层打印,寻找标签位置
        rating_counts = rating_counts.find_all('div')[1].contents[1].strip().replace(',', '')
        d = {'title': title,
             'audience_score': int(score),
             'number_audience_ratings': int(rating_counts)}
        df_list.append(d)
df = pd.DataFrame(df_list, columns=['title', 'audience_score', 'number_audience_ratings'])

还需要合并两个DataFrame

用编程的方式下载网络上的文件(http协议+Python Requests)

HTTP全称为超文本传输协议,是web浏览器和Web服务器之间的沟通语言。

import requests
import os
folder_name = 'ebert_reviews'
if not os.path.exists(folder_name):
    os.makedirs(folder_name)
url = 'https://classroom.udacity.com/nanodegrees/nd002-cn-advanced-vip/parts/4ec06ac9-9e53-42c2-a53d-3b4ec9d7e25e/modules/fea8de18-62f3-4b23-9f19-4293ee51871f/lessons/96402d84-c99d-4982-9edf-2430ef30d222/concepts/ed908f34-ce67-44c0-acb1-d81abd5d9e37'
response = requests.get(url)
with open(os.path.join(folder_name, 'down_html.txt'), 'wb') as f:
    f.write(response.content)
print(response) # 200代表请求成功

去掉末尾的换行符可以用 line[:-1]

with open(file_name, 'r', encoding='utf-8') as f:
    title = f.readline()[:-1] # 去掉末尾的换行符
    txt = f.read() # 将剩余内容读入
    d = {'title': title,
         'txt': txt}
    df_list.append(d)
df = pd.DataFrame(df_list) # 将网页内容存在DataFrame中

用API(应用程序编程接口)或访问库来下载网页

有的API可以下载图片,但有的不可以。特定网站的API由网站自己提供,如烂蕃茄的rtsimple, 维基百科的MediaWiki.这是MeidaWiki的使用tutorial

这是MediaWiki的python访问库列表

JSON文件结构

大多数API文件板式都是JSON,它被用来贮存相对复杂的文件内容。JSON代表javascript object notation

JSON文件结构是字典的形式,而且key必须是字符串,值可以是字符串、list、数字等。它也可以嵌套。 JSON 有六种有效的数据类型,其中两种可使层次数据在采用大部分格式时具有灵活性:

  • JSON 数组(被Python解释为list)
  • JSON 对象(被Python解释为dictionary)

这些在 Python 中有类似的数据结构,所以可以使用相同的方法访问。

18.混搭:API、以编程方式下载文件和 JSON

至此

收集:总结

收集数据是数据整理过程的第一步:

  • 收集
  • 评估
  • 清理

根据数据来源及其格式,收集数据的步骤也不同。

高级收集过程:

  • 获取数据(从互联网下载文件、抓取网页、查询 API 等)
  • 将数据导入编程环境(例如 Jupyter Notebook)

lesson3: 维基百科爬虫

  • State “TODO” from [2020-04-09 Thu 12:23]

lesson4: 抓取豆瓣电影信息(案例演练)

  • State “TODO” from [2020-04-09 Thu 12:23]

lesson5: 评估数据 assess

intro

在清理之前要评估,不评估就不知道数据的问题在哪,怎么去清理。 数据问题:

  • 数据质量问题(缺失、重复、错误等)(脏)
  • 数据整洁度问题(结构问题)(乱)

解决方法:

  • 目测寻找
  • 编程寻找(info()等, 可视化EDA)

检测问题、记录问题,以便再现。建议在数据整理过程中,将评估和清理步骤分开进行。所以,第一步仅填写观察值是个不错的做法。

但是如果你在评估之后,马上就对数据进行处理/清理/解决,这也是中很好的方法。 如果是这样的话,你就可以略过观察的步骤,直接进行清理(这是 Define-Code-Test 清理框架的一部分,我们将在第 4 课介绍)。

目测也是了解数据集的一个步骤,要评估,你要先理解这个行列代表的意思及这个数据集的目标及背景知识。

数据质量问题 的几个度量指标

  • 完整性(有无NAN?)
  • 有效性(如负的身高等)
  • 准确性(如身高1cm)
  • 一致性(格式相同)

编程式的评估 数据质量问题

df['age'].duplicated() # 某列重复的数据,返回boolen数组
df['age'].value_counts() # 与上有类似的功能,返回值出现的次数
df['age'].sort_values(ascending=False) # 数值型值的排序
  • 要留意同一客体的不同称谓产生多条记录的问题,可以用某些(不太可能重复但)重复的属性来检查。
  • 要留意object类型的列,是不是有数据类型不一致问题?(比如有空值 - ,但没有被pandas识别)

总结

按以上大纲助逐排查是的重要的!而且收集、评估、清理、分析过程在任何时候都是可迭代的,即你可以随机 收集、评估、清理、分析。

lesson6: 清理数据

大纲

数据清理流程:确定方案,编写代码,检验效果

  • 先解决数据缺失问题(一般要先解决完整性问题,为什么?)
  • 再解决整洁度问题
  • 最后解决质量问题

人工vs程序清理?除非只需要一次,否则不要人工清理,应该用程序清理。 先备份数据,不要在原始的脏乱数据上操作!备份用 df.copy()

import pandas as pd
df = pd.read_csv('file.csv')
df_clean = df.copy()
df_clean['animal'] = df_clean['animal'].str[2:]
df_clean['animal'] = df_clean['animal'].str.replace('!', '')

先处理缺失值

Imputation教程

import pandas as pd
# 用正则表达式提取字符串
df['email'] = df.contact.str.extract('([a-zA-Z][a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+[a-zA-Z])', expand=True)
df['phone'] = df.contact.str.extract('((?:\+?\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4})', expand=True)
# 字符串是否被包含?
print('ac' in 'acbs')
action_movies = df_m[df_m.genres.str.contains('Action')] # 筛选包含特定字符串的行
# 拼接DataFrame
df_new = df1.append(df_2) # 列对齐
# 行对齐
# melt融合DataFrame
# split劈裂DataFrame
# merge合并DataFrame,按照名和姓进行
df = pd.merge(df, df2, on=['given_name', 'surname'], how='left')

正则表达式教程 融合函数 融合函数2

这一节课需要更多的学习和练习,对pandas清理的常用函数还不熟悉,经验也不多!

项目:清洗与分析数据

  • State “TODO” from [2020-04-09 Thu 12:23]

Python数据可视化

主要有两个方面:

  • 探索性数据可视化:用来寻找变量间的关系或隐藏的见解,不必完美,只为自己看。
  • 解释性数据可视化:呈现给观众,为了用图或表来回答之前提出的问题。

收集数据、清理数据、探索数据、分析数据(建立模型)、呈现分析结果

lesson1: 数据分析中的数据可视化

可视化的重要性

有时数据集的一些度量指标完全相同,但实际上却完全不同,如安斯库姆四重奏。

可视化库

Matplotlib(复杂而灵活), Seaborn(简单而高效), pandas(简单而高效). 应该在灵活性与高效性之间权衡。可以先用pandas和Seaborn,来探索,最后用Matplotlib来 呈现。

本课程大纲

  • 可视化设计
  • 数据探索
  • 解释性可视化
  • 可视化案例分析

lesson2: 可视化的设计

数据类型

数据的四个测量级别:

  • 分类类型(非数值类型、定性类型) 柱状图 饼状图
    • 无序分类变量(Nominal data)
    • 有序分类变量 (Ordinal data)
  • 数值类型(Numeric、定量类型) 直方图
    • 定距变量(Interval data):绝对差有意义,可以进行加减运算
    • 定比变量(Ratio data):相对差有意义,可以进行乘除运算

    或者也可以分为:

    • 离散变量
    • 连续变量

在探索数据的时候,首先要考虑的事情就是判断数据是分类的还是数值的。

图表垃圾指的是图表中对理解要展示的信息并无帮助,或者使读者无法关注到重要信息的所有视觉元素。

提高数据墨水比ink-data-ratio

使用颜色

  • 首选黑白(黑,白,灰)
  • 如果要用颜色,尽量不要用鲜艳的颜色(如天然色或淡色)
  • 颜色的选择要有助于信息的表达,凸显你的信息并区分兴趣组,避免因为要有颜色而添加颜色
  • 针对色盲人群:不要用红绿区分数据,用蓝橙代替

额外的视觉编码

颜色与形状是分类变量最好的展现方式,而标志大小有助于数值型数据的表达。只有在绝对必要时才使用这些额外的编码。 如果一个图表中有太多的信息,建议将这些信息分解为多个单独的信息,这样听众反而可以更好地理解信息的各个方面。

lesson3: 单变量数据探索

数据探索应该从单变量探索开始,这有助于理解数据集。

条形图(柱状图)

  • 研究分类类型变量的分布,首选用bar chart, 基线应设为0。
  • 对于无序的分类类型,可以按出现频次从大到小排序
  • 但不要对有序的分类类型排序,因为它的本身的顺序更重要
  • 可以选择,要不要使用横向的bar chart
  • 可以选择是用绝对次数还是出现的相对频率来绘图
import seaborn as sns
import pandas
import matplotlib.pyplot as plt
%matplotlib inline
type_order = df.type1.value_counts().index
sns.countplot(data=df, x='type1', color=sns.color_palette()[0], order=type_order)
# 横向的bar chart 只需要将改成y
sns.countplot(data=df, y='type1', color=sns.color_palette()[0], order=type_order)
# 可以使用 matplotlib 的 xticks 函数及其 "rotation" 参数更改绘制刻度标记的方向
plt.xtics(rotation=90)

缺失值统计

sns.barplot 来绘图。

na_counts = df.isnull().sum()
base_color = sns.color_palette()[0]
sns.barplot(na_counts.index.values, na_counts, color = base_color)

饼状图

饼图是一种应用场合很有限的图表类型,图表创建者很容易将饼图绘制得难以看懂。如果你要使用饼图,请尝试遵守下面的规则:

  • 确保你关心的是相对频率。每个扇区应该表示整体的一部分,而不是单独的数值(除非变量能够求和成某个整体)。
  • 将扇区限制在一定数量内。饼图最好只包含两到三个扇区,如果扇区足以明确区分,也可以包含四到五个。如果你有很多个类别, 并且某些类别所占的比例很小,那可以将它们组合到一起,或者将这些比例很小的类别放到 “其他” 类别中。
  • 系统地绘制数据。绘制饼图的一种常见方法是从圆圈的顶部开始,然后沿着顺时针方向绘制每个分类级别,从最常见的到最不常见的排列。 如果有三个类别,并且想要对比其中两个,一种常见绘制方法是将这两个类别放在 12 点钟方向的两侧,第三个类别填充在底部剩余部分。

如果无法满足这些规则,则建议使用条形图。通常选择条形图更保险。长条高度比面积或角度更精确,并且条形图比饼图更紧凑。 对于值很多的变量来说,条形图更灵活。

参考:udacity的饼图

直方图

不会为每个单独的数值绘制一个长条,而是定义几个连续的分组(bin),为每个分组绘制长条以代表相应的数字。 x表示特征值,y表示数量统计(与柱状图相同),绘图时应尝试不同的组距。 plt.hist(data=df, x='age', bins=30)

lesson4: 双变量可视化探索(研究相关性)

  • 数值变量vs数值变量 用 scatterplots(散点图)
  • 数值变量vs分类变量 用 violin plots(小提琴图)
  • 分类变量vs分类变量 用 clustered bar charts(分组柱状图)

重叠、透明度和抖动

如果要绘制大量数据点,或者数值变量是离散型的,那么直接使用散点图可能无法呈现足够的信息。图形可能会出现重叠,由于大量数据重叠到一起, 导致很难看清变量之间的关系。在这种情形下,我们需要应用透明度和抖动,使散点图能呈现更多的信息。

除了设置透明度,我们还可以通过抖动使每个点稍微偏离真实值所对应的位置。这并不是 scatter 函数中的直接选项,但是 seaborn 的regplot 函数有这个内置选项。可以单独添加 x 轴和 y 轴抖动,不会影响到回归方程的拟合情况

sns.regplot(data = df, x = 'disc_var1', y = 'disc_var2', fit_reg = False,
           x_jitter = 0.2, y_jitter = 0.2, scatter_kws = {'alpha' : 1/3})

热图

violinplot

Seaborn 的 violinplot 函数可以创建将小提琴图和箱线图相结合的图表

sns.violinplot(data = df, x = 'cat_var', y = 'num_var')

分组条形图

lesson5: 多变量可视化探索

第三个变量使用非位置编码

形状颜色 适于编码分类变量, 大小 适于编码数值变量.

调色板

调色板类型主要有三种类型:分类的(qualitative 或 categorical),有序的(sequential)和发散的(diverging)。 它们在 seaborn 中分别对应于 sns.color_palette(n_colors=9) sns.color_palette('viridis', 9) sns.color_palette('vlag', 9)

多变量可视化

pd.plotting.scatter_matrix(df_clean) 可以绘制两两特征的散点图。数值变量的相关系数: df.corr()

特征工程(探索数据的一种方式)

特征工程并不是为图表添加变量的相关技术,它是一个有助于探索和了解数据的有用工具。在探索数据的时候,你有时候会发现两个变量在某种程度上存在一定的关联, 对这两个变量进行相加、相减、相乘或者相除得到的新特征能够更好地回答你的研究问题。

另一种特征工程的方式是使用 cut 函数将数值变量分为有序的组。作为第三个变量,将数值变量转变成有序数组,然后就可以通过分面画出包含第三个变量的图表了。 此外,这种离散化处理消除了数据噪音,所以可能会对讲述数据故事有帮助,因为可以使受众更专注于数据中的主要趋势

lesson6: 解释性数据可视化

回顾数据分析的过程

让我们简要回顾一下数据分析过程,看一下解释性可视化和探索性可视化在数据分析的各个过程中的适用性。 数据分析的五个主要步骤为 :

  • 提炼 - 从电子表格、SQL、网络等途径获得数据
  • 清洗 - 在这一步,可能会用到探索性可视化
  • 探索 - 这一步使用探索性可视化
  • 分析 - 在这一步中,探索性和解释性可视化都有可能用到
  • 分享 - 这里就是解释性可视化的用武之地

前面三章的内容主要在讲探索性数据分析。在探索过程中创建的图表主要是給数据分析师自己看的,所以不会被特别地修饰或者美化, 能够从数据中获得见解即可 。

而本章课程主要讲如何根据你的数据洞察和见解,继而创作解释性数据分析可视化。此类可视化侧重于讲述你想要传达的特定故事。 很多时候,在这个过程中创建的可视化是由探索过程创建的图表演化而来,我们 对这些探索性可视化进行额外的修饰,以突出想要展示的特定关键信息。你的图表不光要包含丰富的信息,而且要具有吸引力和可解释性,所以先让我们来回顾之前课上提到的可视化设计的概念。

用数据讲故事

包括以下步骤:

  • 先抛出问题
  • 重复是个好事情
  • 突出问题的答案
  • 呼吁读者采取行动

修饰图表

到目前为止,你学到的代码都只是能让你创建图表,够用就行,没有考虑美观因素。但为了使你的发现准确和有效地传达给受众,你需要学会修饰图表。 在修饰图表的时候,有很多需要考虑的问题。

  • 选择合适的图表类型 图表类型的选择取决于你的变量数量以及它们的类型,比如它们是有序分类,还是无序分类,是连续数值,还是离散数值。图表类型的选择还取决于你想要传达的变量之间的关系。比如,选择小提琴图,箱线图还是调整过的条形图,取决于你有多少数据以及数据分布是不是你关心的重点。如果你有很多数据而且它们的分布是有意义的,你很可能会选择小提琴图;但如果如果你的数据量不多而且数据的分布并没有那么重要,那你会更倾向于使用箱线图或条形图。
  • 选择合适的编码 变量不光会影响你选择的图表类型,而且也影响你选择的编码类型。比如说,如果你有三个数值变量,不能随机将变量用在 x 轴、y 轴或用颜色编码。一般情况下,放在坐标轴上的变量应该相对重要,如果有一个变量是因变量或者结果变量,那么你应该把它放在 y 轴上。在其他情况下,因变量也可以用颜色来编码,就像从上俯视由其他两个自变量组成的平面一样。
  • 注意整体考量与诚实设计原则 在设置图表参数的时候,请务必记住之前课上提到的可视化设计原则。
  • 你应该尽可能地确保图表中没有很多图表垃圾并且拥有比较高的数据墨水比。应该在必须的情况下,即你想传达额外信息的情况下,再决定加入非位置编码。比如,在单独的频率条形图上使用颜色可能没必要,但如果在其他图表中也使用相同的颜色表示相应的变量,那么使用颜色也是合理的。同理,你应当避免对不同的变量使用相同的颜色,减少读者的困惑。
  • 最后,还要遵守诚实设计原则,避免对数据做出扭曲或者不真实的可视化呈现。如果你使用条形图或直方图,那 y 轴最好从 0 开始。如果你使用了任何坐标轴变换,最好在你的标题,坐标轴标签以及刻度标记上进行说明。

轴标签以及选择合适的轴刻度 坐标轴一定要包含相应的标签。在探索性分析的时候,这可能没那么地重要,因为图表主要是給你自己看的,而且代码也都是你自己写的。但是当你要将图表包含的信息传达给别人的时候,这变得非常得关键。当你添加坐标轴标签的时候,也尽可能提供轴变量的单位。

至于轴刻度,你应该在每个轴上提供至少三个刻度标记 。这对于已经变换的数据尤为重要,为了清晰地展示数据的比例,你可能需要应用足够多的刻度标记。如果数字非常大或非常小,你应该考虑使用缩写(比如,用 ”250k” 取代 “250000”)。

为非位置编码的变量提供图例 一定要为那些非坐标轴变量提供图例。对于颜色编码,你可以在图表旁边加上颜色栏。需要特别注意的是,就像你会添加坐标轴标签,也请为你的图例提供一些解释性的标签。

为图表提供标题和描述性文本 最后,记住要为你的图表提供具有描述性的标题。如果这是个包含了重要信息的关键图表,尽可能把重要的信息放在标题里以吸引观众的注意力,而不是简单地把图表中的变量当作标题。

虽然图表是我们传达信息的主要工具之一,但是我们也可以有一些其他辅助工具,比如在图表下方或者周围加入一些描述性文本注释,强调重点,这样能使你的观众更容易地获得重要的信息或者增强记忆。

  • 用 Matplotlib 来修饰图表 在之前单变量可视化的课程中,你了解了 Matplotlib 和 Seaborn 是如何绘图的:每个图表都是一个单独的 Figure 对象,这个对象包含了坐标轴,坐标轴又包含了用来表达数据的点,线或长条等。理解并利用这种结构会让你的图表修饰工作变得容易。下面的每个函数都包含其文档页面的链接, 以及与之关联的对象类型。

figure (Figure): 用来创建新的图表。 可以用它来初始化图表,最常用的是 “figsize” 参数设置图表大小。 xlabel 和 ylabel (Axes): 用来设置轴标签。 xticks 和 yticks (Axes): 用来设置轴刻度。 legend (Axes): 用来创建和自定义图例。一个关键参数是 “title”,可以为你的图例提供描述文字,标记特征名称。”loc” 和 “ncol” 参数可以改变图例的位置和形状,因为有些时候默认的图例位置可能并不理想。 colorbar (Axes): 用来添加调色板。用 “label” 这个参数給调色板添加标签。 title (Axes): 用来设置单个坐标系图表的标题。 suptitle (Figure): 用来设置整个图表容器的标题。suptitle 和 title 主要的不同是前者是为整个图表容器(Figure 对象) 设置标题,而后者只是为单个坐标系的图表(Axes 对象)设置标题。这对于分面图表或者创建包含很多子图的图表很有用,suptitle 可以为整个图表 矩阵设置总标题。 所有上面提到的函数以及在 Seaborn 里和这些函数相关的参数,在整个课程中用到的比较少。下面是用到这些函数的几个示例。

这个例子用到了 汽车燃油效率数据集。因为图表用到了颜色栏,所以用了 figsize 来将图表 变大一些。标题,坐标轴以及颜色栏也都包含了标签。注意每个标签里都将变量的单位标注在了括号里面。

# loading in the data, sampling to reduce points plotted
fuel_econ = pd.read_csv('./data/fuel_econ.csv')

np.random.seed(2018)
sample = np.random.choice(fuel_econ.shape[0], 200, replace = False)
fuel_econ_subset = fuel_econ.loc[sample]

# plotting the data
plt.figure(figsize = [7,4])
plt.scatter(data = fuel_econ_subset, x = 'displ', y = 'comb', c = 'co2',
            cmap = 'viridis_r')
plt.title('Fuel Efficiency and CO2 Output by Engine Size')
plt.xlabel('Displacement (l)')
plt.ylabel('Combined Fuel Eff. (mpg)')
plt.colorbar(label = 'CO2 (g/mi)');

project3: 探索性数据分析EDA

什么是EDA

EDA可以增加你对数据的了解,对提出假设和建立模型有帮助。进行EDA时要时刻对数据保持好奇与怀疑。 在EDA时应该让数据直接说话,并测试自己对数据集的直觉,培养新的直觉。

协调迁移

交互式可视化用d3.js

R基础

  • State “TODO” from [2020-04-09 Thu 13:24]

用数据来呈述你的结论

project4: 求职-模拟面试

机器学习基础

数学基础

lesson6: 神经网络中的微积分

监督学习

非监督学习

聚类

K-means

可视化:

import matplotlib.pyplot as plt
plt.scatter(Xy['x1'], Xy['x2'], c=Xy['y_pred'])

层次聚类(hierarchical clustering)

  1. 单连接层次聚类法(自下而上)

DENDROGRAM 系统树,sklearn中没有单连接层次聚类实现。

LINKAGE DENDROGRAM可以帮助分析高维聚类的类别数!

  1. sklearn中的凝聚聚类法(自下而上)

2.1 全连接聚类法:关注两个类中两点的最远距离,将其定义为两个类的距离,再按层次将所有的类别连接起来 (同单连接一样)。聚类结果比单连接更紧凑,更好。

sklearn.cluster.AgglomerativeClustering(n_clusters=3, linkage='complete')

2.2 WARD’s methods

sklearn.cluster.AgglomerativeClustering(n_clusters=3, linkage='ward')

AB类的距离定义为:找一个AB类的中心点C,计算ΔAB, ΔAB = ∑i Ci2 - ∑i Ai2 - ∑i Bi2 其中Ai(Bi)为A(B)类的中心到A(B)类各点的距离,Ci为C中心点到AB两类中各点的距离。 然后哪两个类最近,再将它们按层次连接起来。

2.3 平均连接法

sklearn.cluster.AgglomerativeClustering(n_clusters=3, linkage='average')
  1. 可视化系统树构建用 scipy
from scipy.cluster.hierarchy import dendrogram, ward, single
linkage_matrix = ward(X) # 聚类
dendrogram(linkage_matrix) # 绘制系统树
  1. 优缺点

优点:结果信息量丰富(在生物进化学领域应用) 缺点:对噪声和异常值敏感,计算量大 O(N2)。

密度聚类(DBSCAN, 具有噪声的基于密度的聚类)

参数:epsilon每个点的领域半径,识别为非噪声的最小点个数(半径内)。噪声点,核心点,边界点。

  • 优点:不用输入类别个数,不限定类别的图形状,可以用来检测异常值和噪声。
  • 缺点:边界点有时会被归为其他类,不太擅长区分密度相关很大的类别(可用HDBSCAN)。

异常值检测方法

from sklearn.cluster import DBSCAN
plt.scatter(dataset[0], dataset[1]) # 数据可视化
dbscan = DBSCAN(eps=1.3, min_samples=50) # 这是两个主要参数

高斯混合模型聚类(GMM)(最超前的聚类方法)

认为每个数据点都属于每个类,只是有权重。每个类别都服从特定的统计分布。

一维高斯分布性质:[μ-σ, μ+σ] 之间有68%的数据点, [μ-2σ, μ+2σ] 之间有95%的数据点, [μ-3σ, μ+3σ] 之间有99%的数据点。 预测时用多个高斯分布去拟合数据点,并选择更有可能的高斯分布作为同一个类。

高维高斯分布与多个高斯分布混合的区别: 多个混合可能有多个聚类中心,高维高斯分布只有一个中心。

GMM的工作原理:1.为数据初始化n个类别的高斯分布,如果不收敛,则2.为每个点计算属于所有分布的隶属度(软聚类), 3.用隶属度和原数据计算μnew,用隶属度、原数据和μnew计算σ2new。4.期望最大化

from sklearn.mixture import GaussianMixture
gmm = GaussianMixture(n_components=3)
y = gmm.fit_predict(X)

第一步,初始值的设置会影响结果!优点:在机器视觉方面很有用。

聚类分析流程:

  • 数据
  • 特征选择(挑选一些重要特征)、特征提取(对数据转换以生成更有用的新特征如PCA)
  • 选择聚类算法、调优(‘NoFreeLanch定理’,邻近度量(计算两点距离的方法))
  • 对聚类算法进行评估(可视化和评分)
  • 解释结果(转化为知识)

聚类模型的评估

外部评估指标(原数据集带有标签):Adjusted Rand Index(调整兰德系数) [-1, 1] 内部评估指标(原数据集没有标签):silhouette coeffient(轮廓系数), [-1, 1], 别用在DBSCAN算法上,用DBCV

特征缩放

xnew = (xold - xmin)/(xmax - xmin) 以上公式会将最小值变成0,最大值变成1,sklearn的实现:

from sklearn.preprocessing import MinMaxScaler
min_max = MinMaxScaler()
X_scaled = min_max.fit_transform(X) # 输入X应该是浮点数,不能是整数

缩放算法的影响

受影响的算法:

  • SVM with rbf kernal
  • K-means

不受影响的算法:

  • linear regression
  • decision tree

主成分分析PCA

  • 在数据方差最大的方向设为x轴
  • 与其正交的方向设为y轴

作用:

  • 找到潜在的特征间关系(发现隐藏模式)
  • 降维:对成份(新的合成特征)的重要性排序并筛选,用于降维
  • 可视化高维数据(只画主要成份)
  • 去噪声(去掉不重要的成份)
  • 让其他算法工作更好(如SVM),即减少拟合的方差(不是偏差)
from sklearn.decomposition import PCA
from sklearn.decomposition import RandomizedPCA
pca = PCA(n_components=2).fit(X)
pca.components_[0]
pca.components_[1]
pca.explained_variance_ratio_

最大主成分数量是训练点数量和特征数量这两者中的最小值。

随机投影

比PCA更高效,适于处理十分高维的数据

from sklearn.random_projection import SparseRandomProjection
rp = SparseRandomProjection()
new_X = rp.fit(X)

independent component analysis 独立成份分析ICA

假设特征之间独立,没有依赖关系,可以用于分离各部分,比如鸡尾酒会问题

from sklearn.decomposition import FastICA
ica = FastICA(n_components=2)
components = ica.fit_transform(X)

project6: 深度学习

神经网络简介

感知器算法

感知器: step_function(wixi + b) > or < 0 ? 感知器算法:

  • 先随机初始化权重wi和偏置b,以给定决策边界的超平面
  • 对于每个错误分类的实例X=[xi]更新权重,α 是learning_rate:
    • if prediction=0: change wi to wi + α xi change b to b + α
    • if prediction=1: change wi to wi - α xi change b to b - α

离散型和连续型激活函数

step_function和sigmoid_function. sigmoid函数通常用于将离散的结果 转变成概率,它的输出在0到1之间,而且是连续的。它就是量子统计物理中的费米 分布函数,1/(1+ex), x为电子的能量

多分类时怎么办呢?要找一个归一函数,能将正负值都安全地转换成0到1之间的概率, 那就是softmax函数, Si = (ei)/(∑jej),它又和物理中 的费曼图求和形式相同。

处理多分类时,One-Hot编码是经常的做法。

最大似然概率

用Numpy的矩阵乘法实现梯度下降

深度学习工具Pytorch

PyTorch 于 2017 年初推出,给深度学习社区带来了深远的影响。它是由 Facebook AI 研发团队开发的,已经被各行各业和各个学术领域采用。

张量,它是 PyTorch 的主要数据结构。我将演示如何创建张量、如何完成简单的运算,以及张量如何与 Numpy 交互。

然后,你将学习模块 Autograd,PyTorch 会使用该模块计算在训练神经网络过程中用到的梯度。 Autograd 非常强大。你可以用它完成整个反向传播工作:计算网络中每个运算的梯度, 然后使用这些梯度更新网络权重。

接着,你将使用 PyTorch 构建网络并使数据前向经过网络。然后,你将定义损失和优化方法, 并用手写数字数据集训练神经网络。你还将学习通过验证步骤测试网络的泛化能力。

然而,一个潜在问题是网络在处理复杂图像方面的效果不太好。 所以我们会接着学习如何使用预训练的网络改善分类器的效果,这种技巧称为迁移学习。

import torch
torch.manual_seed(7)
x = torch.randn((1, 5))
w = torch.randn_like(x)
b = torch.randn(1,1)
#b = 3
print('x: ', x)
print('x: ', x.view(5,1))
print('w: ', w)
print('torch.exp(x): ', torch.exp(-x))
print('torch.mm(w, x.view(5, 1)): ', torch.mm(w, x.view(5, 1)) + b)

用Pytorch搭建神经网络

import torch
import numpy as np
a = torch.randn(1, 3, 1, 1, 3)
print(a.shape)
# 压缩掉长度为1的维度,axis指定维度,从0开始。非1的维度,不产生任何效果
b = np.squeeze(a, axis = 0)
print(b.shape)
c = np.squeeze(a, axis = 3)
print(c.shape)

注意 torch.nn.ReLUtorch.nn.funcional.relu 的区别:

  • 前者是模块Module,可以放在 torch.nn.Sequential()
  • 后者是函数,不能放入Sequential, 必须有参数传入

小结:

  • 可以用 np.dot(features, weights) + b1 来构建网络
  • 可以用pytorch的class,定义forward函数
  • 可以用pytorch.nn.Sequential
  • dim=0将每列求和,dim=1将每行求和
  • 卷积操作时,图像维度变化 (W-F+2P)/S + 1
  • transforms.RandomHorizontalFlip() 要放在totenosr之前!

输出层激励函数、loss、autograd、优化器

  • nn.CrossEntropyLoss,以此为Loss时,不要将输出进行Softmax操作
  • nn.NLLLoss,以此为Loss时,输出层激励函数用LogSoftmax(dim=1)
import torch.nn as nn
from torch import optim
# 定义损失函数
criterion = nn.NLLLoss()
# 前馈计算目标值
y = model(images)
# 计算损失函数值
loss = criterion(y, labels)
# 定义优化器
optimizer = optim.SGD(model.parameters(), lr=0.01)
optimizer.zero_grad()
output = model(images)
loss = criterion(output, labels)
loss.backward()
optimizer.step()

循环训练整个训练集

model = nn.Sequential(# ...
                     )
criterion = 
optimizer = optim.SGD(model.parameters(), lr=0.003)
for e in range(epochs):
    for images, labels in trainloader:
        output = model(images)
        loss = criterion(output, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        ps = torch.exp(output)

在测试集上预测

得到在训练集上的预测概率、预测类别、精度:

ps = torch.exp(output)
top_p, top_class = ps.topk(1, dim=1)
equals = top_class == labels.view(*top_class.shape)
accuracy = torch.mean(equals.type(torch.FloatTensor))

在测试集上预测时,只向前传播进行预测,不反向传播,所以应该关掉梯度跟踪:

with torch.no_grad():
    log_out = model(images)
    ps = torch.exp(log_out)
    # ...
    accuracy = # ...

对比训练精度与测试精度可以看出过拟合了!

dropout正则化

在训练时dropout:

nn.Dropout(p=0.2) # 写入nn.Sequential
self.dropout = nn.Dropout(p=0.2) # 写入class init()
x = self.dropout(F.relu(self.fc1(x))) # 写入class方法forward()
for images, labels in trainloader:
    # 写法和之前相同,dropout默认进行(在model中定义)
    pass

预测时不能dropout!

else:
    with torch.no_grad():
        model.eval() # 关闭dropout
        for images,  labels in testloader:
            pass # 开始预测以验证
model.train() # 验证完成后回到训练,开始dropout

BatchNorm

  • 在批归一化的层不要使用bias项
  • 批归一化在激活之前
  • BatchNorm1d, BatchNorm2d

保存训练得到的模型

迁移学习

练习记录

  • fully-connected neural network
  • CNN on MNIST(多分类问题)
  • ResNet18 on MNIST(多分类问题)
  • transfer learning
  • LSTM for movie reivews sentiment analysis(二分类问题)
  • AE(自动编码器) on MNIST(无监督学习,生成模型)
  • GAN on MNIST(无监督学习,无外部标签,属于生成模型)
  • Cycle GAN on Yosemite National Park image dataset(NOT finished!), 图到图的翻译。
  • DCGAN on SVHN(与gan相似,只是将全连接换成了卷积网络,GAN的一种)
  • PixelRNN, PixelCNN(生成模型)

deep learning历史介绍

deeplearning视频

你应该知道的深度学习算法

A Tour of Machine Learning Algorithms

  • FNN架构

    即前馈神经网络。

  • CNN架构

    CNN被广泛用于有监督的图像识别,文本分析(NLP),图数据分析(graph CNN)。包括了从LeNet到ResNet, DenseNet。

    • LeNet CNN 1990s, ICPCPFO, 存在问题:容易过拟合,图像分析数度低
    • AlexNet CNN, 2012, ICPCPCCCPFFO。第一深度神经网络,利益于硬件的发展,使用了大的卷积核
    • VGG CNN, 2014, ICCPCCPCCCPCCCPCCCPFFFO, 使用小卷积核,计算量和参数更少
    • GoogleNet, 2015, ICPCCPIIPIIIIIPIIPFO, 中间的I表示新引入的联结:Inception层
    • ResNet, 与VGG同样使用相同大小的图像进行卷积操作。全连接层(通常在同等规模内包含最多参数) 对良好的网络性能并不必要。移除全连接层导致 CNN 参数数量大幅下降。此外,池化操作也越来越不常用, 有可能会被卷积操作取代。这为ResNet基本构建块,残差模块提供了基础部分。 尝试拟合输入的一个微小改善而不是输入,因此称之为残差,是里程碑式的工作。 ResNet 在一些常见的训练集中都达到了业内最佳的结果(如 CIFAR、MNIST 等)。
  • RNN架构

    同时向空间和时间方向延伸。包括最初的RNN到目前最热的LSTM。通过学习前序数据来预测后序事件, 如(声音,时间序列,书面语言等)。一般使用随机梯度下降和向后传播算法。用于情绪分析, 语言识别,NLP,机器翻译,搜索预测,视频分类,图像标注等。激活函数常用tanh(x), 因为它 的输出是-1到1,而不是0,到1. RNN的典型优化器是Adam.

    • LSTM(长短期记忆) 可以用于:图形和视频标注,语言翻译,情绪分析,股票预测
  • AE自动编码器

    可以用来给图片降噪,要记得始终加非线性激活,否则会得到全部像8的数字输出(MNIST)。关键在于 计算损失函数 loss = nn.MSEloss(outputs, images). 用回归的损失函数,并将sigmoid 之后的输出与归化的输入相比。要注意维度匹配!先relu后pool效果更好?decoder一般为encoder 的逆操作!

    降噪时可以先在无噪音的图片上引入高斯噪声,将有噪声的图片作为AE的输入,将无噪声的图片作为 输出,并以回归损失函数来训练网络。

    • Encoder: fully-connected layers OR convolutional layers
    • Deconder: fully-connected layers OR transpose convolutional layers, no pooling layers, use ~ nn.ConvTranspose2d()~ 在解码时引入的人为因素可以用upsampling, 或stride=kernel_size来避免。用 F.upsample(x, scale_factor=2, mode='nearest')
# upsample
    def forward(self, x):
        # add layer, with relu activation function
        # and maxpooling after
        x = F.relu(self.conv1(x))
        x = self.pool(x)
        # add hidden layer, with relu activation function
        x = F.relu(self.conv2(x))
        x = self.pool(x)  # compcompressed representation
        
        ## decoder 
        # upsample, followed by a conv layer, with relu activation function  
        # this function is called `interpolate` in some PyTorch versions
        x = F.upsample(x, scale_factor=2, mode='nearest')
        x = F.relu(self.conv4(x))
        # upsample again, output should have a sigmoid applied
        x = F.upsample(x, scale_factor=2, mode='nearest')
        x = F.sigmoid(self.conv5(x))
        
        return x
# 在图片中加入高斯噪声
    for images, labels in train_loader:
        ## add random noise to the input images
        noisy_imgs = images + noise_factor * torch.randn(*images.shape)
        # Clip the images to be between 0 and 1
        noisy_imgs = np.clip(noisy_imgs, 0., 1.)
  • GAN生成对抗网络(2014)

    范例:Pix2Pix , cycle GAN and Pix2Pix in Pytorch, 生成模型列表. 两个相对抗的网络:生成网络和判别网络。缺点对超参敏感,难以训练, 参考c231n!GANs对超参数十分敏感,参见:https://arxiv.org/pdf/1511.06434.pdf

    判别网络是个典型的线性分类器,应该 至少有一个隐层,并每个隐层后都要有一个LeakyRelu激活,输出为图片是真是假的二分类, 用BCEWithLogitsLoss()来将sigmoid函数与二元交叉熵结合成一个函数(所以不再加sigmoid)。 定义隐层时,不要复用隐层的nn.Linear,它们应该有不同的参数,而不是共享!定义隐层的 线性变换时最好有维度变化?先骤升后缓降?

    生成网络与判别网络的结构一定要相反吗?还是两个可以不一样?

    生成网络与判别网络类似,区别在于:判别网络的输出要用 tanh() 函数来激活。

  • CycleGAN 用非监督学习的方式将将图片从一个空间映射X到另一个空间Y, 它分别有两个判别网络和两个生成 网络。判别网络结构如下: images/discriminator_layers.png

    两个判别网络结构相同,由五个卷积层构成,前四个有ReLu激活,最后一个没有激活,也不加sigmoid, 因为要用平方差损失来训练。

    生成网络由一个编码器和一个解码器构成,结构如下: images/cyclegan_generator_ex.png

    经过三个卷积层,六个或更多的残差层,再接三个解卷积层。最后一个解卷积层后用Tanh激活。

  • DCGAN深度卷积生成对抗网络(2016) 参见https://arxiv.org/pdf/1511.06434.pdf
    • 判别网络是个没有maxpooling的卷积分类器:

    images/conv_discriminator.png

    • 卷积层建议以32个filter开始,以2倍增。原始文献中用步长为2的卷积代替了下采样。 卷积层建议使用4×4大小的核,stride=2。
    • 生成网络用解卷积层来生成图像,使用Tanh()作为输出: images/conv_generator.png
    • 先用全连接,将噪声变成深度很深的窄长形状,再通过解卷积来使深度减半,图像宽高增倍, 直到和原图大小相同,以方便交给判别网络判别。
    • 除了最后一个解卷积层外,所有解卷积层都要接BatchNorm2d()和leaky_relu(x,0.2)。 原数据要用Tanh()归一到判别网络的输出范围[-1, 1].
    • 同样,解卷积层建议使用4×4大小的核,stride=2。
    • 数据的结构越复杂,提取图像模式需要的网络深度越深
    • 以下是构造稳定的DCGAN结构的建议:(参考Stanford cs231n,https://arxiv.org/pdf/1511.06434.pdf
      • 使用带步长(分数步长)的卷积层代替生成网络(判别网络)中的池化层
      • 在生成网络和判别网络中都使用批归一化
      • 如果深度较深则去掉所有的全连接层
      • 生成网络除了输出用Tanh来激活外,其余所有层用ReLU来激活
      • 判别网络的所有层用LeakyReLU来激活
  • 受限Boltzmann机

wisdom实时可视化

软件工程

数据工程

数据工程师:为各种职业和场景准备数据

ETL管道

ETL: extract, transform, load. ETL是数据管道的一种。

project7: 推荐系统与试验设计

project8: Spark与大数据

github个人资料实战