(第 2 部分)如果您是 Python 的新手(尤其是自学 Python 的话),请将此加入书签
提示和技巧的第二部分在这里。现在就学习这些来平滑你的编码吧!
首先,感谢大家支持我之前关于 Python 技巧和提示的文章。我不敢相信我的文章能吸引超过 12 万的浏览量。我希望你们都能从这篇文章中受益。如果你还没有读过第一本书,最好现在就读。
[## 如果你是 Python 的新手(尤其是自学 Python 的话),请将此加入书签
Python 中简单但有用的技巧和提示列表
towardsdatascience.com](/bookmark-this-if-you-are-new-to-python-especially-if-you-self-learn-python-54c6e7b5dad8)
在 Unsplash 上由 Hitesh Choudhary 拍摄的照片
为了奖励大家,这里是 Python 技巧和提示的第 2 部分。除了展示技巧和提示,我还会包括解释和链接,这样你就可以了解更多。
让我们继续我们的 Python 之旅。
目录
同时更新多个变量
代替
>>> a = 5
>>> b = 8
>>> temp = a
>>> a = b
>>> b = temp + a
>>> a
8
>>> b
13
您可以在一行中同时计算这两个变量。在这种情况下,您不需要创建临时变量。
>>> a = 5
>>> b = 8
>>> a,b = b, a+b
>>> a
8
>>> b
13
(PS:这是什么?斐波那契数列!)
更多信息:评估订单
从列表中返回一个长字符串
>>> str_list = ['This', 'is', 'WYFok']
>>> ' '.join(str_list)
'This is WYFok'
您可以使用 join 函数将所有元素(需要是字符串格式)组合成一个字符串。您需要决定每个元素之间的分隔符是什么
进一步应用
>>> ans_list = [3,6,9]
>>> 'The answer is '+','.join(map(str,ans_list))
'The answer is 3,6,9'
使用 map 函数,你可以把整数类型的元素转换成字符串,结合 join 函数,你可以得到一个新的字符串变量。
字符串格式
>>> pi = 3.14159
# Before Python3.6>>> print('The value of pi is {:.2f}'.format(pi))
The value of pi is 3.14# Python 3.6 and after
>>> print(f'The value of pi is {pi:.2f}')
The value of pi is 3.14>>> pi
3.14159
字符串格式的一个优点是,您可以打印带有舍入的数值,而不会影响原始值的准确性。
更多信息: PyFormat
强调
通常,如果想重复一个步骤,可以使用如下的 for 循环:
>>> for i in range(3):
... print('Hello')
...
Hello
Hello
Hello
但是,您可以看到变量“I”没有任何用法。在这种情况下,您可以使用下划线“_”来替换“I”。
>>> for _ in range(3):
... print('Hello')
...
Hello
Hello
Hello
在这里,“_”是一个一次性变量。Python 不会在这个 for 循环中创建新变量。读者知道索引在 for 循环中是不必要的。
关键字,关键字值,关键字项
>>> teacher_subject = {'Ben':'English','Maria':'Math','Steve':'Science'}
>>> teacher_subject.keys()
dict_keys(['Ben', 'Maria', 'Steve'])
>>> teacher_subject.values()
dict_values(['English', 'Math', 'Science'])
>>> teacher_subject.items()
dict_items([('Ben', 'English'), ('Maria', 'Math'), ('Steve', 'Science')])
对于字典,可以使用键和值函数分别进行检索。对于 items 函数,可以同时检索键和值。当您需要切换键和值时,这很有用。
>>> subject_teacher = {y:x for x,y in teacher_subject.items()}
>>> subject_teacher
{'English': 'Ben', 'Math': 'Maria', 'Science': 'Steve'}
特别要注意的一点是,在切换过程中要小心重复的值。这将导致切换后元素丢失。
(额外:使用 zip,您可以从两个列表组成一个字典)
>>> subject = ['English','Math','Scienc']
>>> teacher = ['Ben','Maria','Steve']
>>> subject_teacher = {f:v for f,v in zip(subject,teacher)}
>>> subject_teacher
{'English': 'Ben', 'Math': 'Maria', 'Scienc': 'Steve'}
更多信息:映射类型—字典
两组的比较
>>> a = {1,2,3}
>>> b = {1,2,3,4,5}# Is a a subset of b?
>>> a<=b
True# Is a a superset of b?
>>> a>=b
False# Union of a and b
>>> a.union(b)
{1, 2, 3, 4, 5}# Intersection of a and b
>>> a.intersection(b)
{1, 2, 3}# Difference # Return elements in a but not in b
>>> a.difference(b)
set()# Return elements in b but not in a
>>> b.difference(a)
{4, 5}
进一步信息:设置
收藏。计数器
当你想计算一个列表中所有元素的数量时,这很有用。您将收到一个类对象,显示列表中所有独特的元素及其各自的编号。
>>> import collections>>> arr_list = [1,1,1,1,2,2,2,3,3,5,5,5,7]
>>> c = collections.Counter(arr_list)
>>> c
Counter({1: 4, 2: 3, 5: 3, 3: 2, 7: 1})
>>> type(c)
<class 'collections.Counter'>
>>> c[1]
4
>>> c[6]
0# Convert back to a dictionary
>>> dict(c)
{1: 4, 2: 3, 3: 2, 5: 3, 7: 1}
更多信息:收藏。计数器
我希望在阅读完这篇文章后,你能进一步了解 Python 的简单性。享受学习,享受编码。下次见。
我的其他文章
Web Scrape Twitter by Python Selenium(第 1 部分)
Web Scrape Twitter by Python Selenium(第二部分)
通过标准化和规范化将机器学习性能提高 30%
如果您不扩展您的数据,就等于放弃了性能
预处理是机器学习管道中最被低估的方面。
特征缩放,将特征值控制在相似的数字尺度上,是其中的关键组成部分。
当数据没有缩放时,计算距离或相似性的模型表现不佳。这包括 KNN 和 SVM。
我将演示 KNN 的缩放数据如何将准确度从 72%提高到 96%。
如果您不扩展输入数据,您就放弃了轻松的性能提升。
我们将用 3 种方法解决一个简单的 ML 问题,比较结果,然后解释为什么缩放有效:
1)无缩放
2)缩放:标准化
3)缩放:标准化
4)为什么缩放可以提高性能
基本情况
在这里,我们将解决一个没有任何缩放的分类问题。
从 Kaggle 下载葡萄酒数据集。这是一个简单的数据集,我们在其中预测葡萄酒的品种(例如:cab sauv,merlot,riesling)。
import pandas as pdimport numpy as np
import pandas as pddf = pd.read_csv('Wine.csv', names=[
'Class', 'Alcohol', 'Malic acid',
'Ash', 'Alcalinity of ash', 'Magnesium',
'Total phenols', 'Flavanoids',
'Nonflavanoid phenols', 'Proanthocyanins',
'Color intensity', 'Hue',
'OD280/OD315 of diluted wines', 'Proline'])df.iloc[np.r_[0:2, -2:0]]
快速检查数据的形状。
df.describe()
df.hist(figsize=(25, 15))
观察特征在完全不同的比例上。酒精从11.03
到14.83
不等,而非黄酮类酚类从0.13
到0.66
不等。
这应该会给你数据科学中的代码味道。不同的比例会混淆模型。
但是让我们用逻辑回归来分析一下。
# helper functionsimport numpy as np
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.neighbors import KNeighborsClassifierdef dataframe_to_X_and_y(df):
X = np.asarray(
df[['Alcohol','Malic acid','Ash',
'Alcalinity of ash','Magnesium',
'Total phenols','Flavanoids',
'Nonflavanoid phenols',
'Proanthocyanins','Color intensity',
'Hue','OD280/OD315 of diluted wines',
'Proline']])
y = np.asarray(df[['Class']])
return X, ydef split_data(X, y):
splitter = StratifiedShuffleSplit(n_splits=1, test_size=0.3, random_state=0)for train_index, test_index in splitter.split(X, y):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]return X_train, X_test, y_train, y_testdef fit_and_predict(X_train, y_train, X_test):
classifier = KNeighborsClassifier()
classifier.fit(X_train, y_train)
y_pred = classifier.predict(X_test)
return y_pred
对数据进行分类和评估。
X, y = dataframe_to_X_and_y(df)
X_train, X_test, y_train, y_test = split_data(X, y)
y_pred = fit_and_predict(X_train, y_train, X_test)from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
这导致了 72%的准确率。不可怕,但我打赌我们可以通过扩展做得更好。
正常化
什么是正常化
归一化也叫做“最小-最大缩放”,但我认为“挤压”这个术语更直观。
它强制数据在 0 和 1 之间的范围内,最低特征值为 0,最高特征值为 1。
归一化后,所有要素的值都将在此范围内。例如,比较标准化前后的Total phenols
数据。
attribute = 'Total phenols'
df_copy = df.copy()
df_copy = df_copy[[attribute]]
df_copy.hist()
以前
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df_copy[[attribute]] = scaler.fit_transform(df_copy[[attribute]])
df_copy.hist()
在…之后
请注意,在后者中,没有值低于 0 或高于 1。
这种缩放算法的一个缺点是,一个巨大的正异常值将变为 1,并将所有其他值挤到接近于 0。
例如,[1,2,10]
会变成[0.00, 0.11 ,1.00]
。
分类问题
回到我们上面解决的那个分类问题。这一次,我们将在进行预测之前对数据进行归一化处理。
df_copy = df.copy()
X, y = dataframe_to_X_and_y(df_copy)
X_train, X_test, y_train, y_test = split_data(X, y)from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)y_pred = fit_and_predict(X_train, y_train, X_test)from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
96%.这是一个巨大的进步!这是规范化数据帮助模型解决问题的一个很好的例子。
标准化
什么是标准化?
标准化减去平均值,然后除以样本方差,因此平均值为零,分布具有单位方差。
z = (x — u) / s
其中
u
是训练样本的均值,如果with_mean=False
为 0,s
是训练样本的标准差,如果with_std=False
为 1。
请注意下面应用标准化前后的比例差异。
attribute = 'Hue'
df_copy = df.copy()
df_copy = df_copy[[attribute]]
df_copy.hist()
以前
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df_copy[[attribute]] = scaler.fit_transform(df_copy[[attribute]])
df_copy.hist()
在…之后
分类问题
让我们解决同样的分类问题,但这一次我们将在进行预测之前对值进行标准化。
df_copy = df.copy()
X, y = dataframe_to_X_and_y(df_copy)
X_train, X_test, y_train, y_test = split_data(X, y)from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)y_pred = fit_and_predict(X_train, y_train, X_test)from sklearn.metrics import classification_report
print(classification_report(y_test, y_pred))
这也做到了!
为什么扩展可以提高性能?
缩放不会改进所有模型的预测。但是对于那些利用距离/相似性计算的人来说,这可能会有很大的不同。
假设我们正在根据购买价格(1000 美元)和行驶距离(公里)来比较二手车。
pd.DataFrame(
{'purchase_price': [20, 25, 80],
'distance_driven': [10000,15000,11000]}
)
虚构数据
你可以看到一些距离的计算(虽然不是全部)会被distance_driven
严重扭曲,因为它更大,即使purchase_price
可能是相似性的更强指标。
结论
我们介绍了一个例子,其中缩放将 KNN 分类器的性能提高了 30%以上。虽然我们可以尝试其他模型,但扩展应该是标准做法。
即使缩放不能提高性能(例如:逻辑回归),它也能使系数更容易解释。
增强熊猫数据框架
优化数据框架的使用
作者图片
作为21 世纪的数据分析师或数据科学家,最基本的、被所有人广泛使用的框架是——熊猫!借助内存处理能力和数据帧的使用,Pandas 让生活变得更加轻松。与将整个数据集转储到 SQL 数据库中并使用 SQL 查询来查询数据库以查看输出相反,现在我们只读取 pandas df 中的数据集文件。所有这些繁琐的过程现在都被熊猫 数据框所取代。
除了 pandas,还有更好的选择,可以通过优化 Pandas 的工作流程来进一步提高您的计算能力。这里有一些功能强大的替代品,易于安装,并允许您提高您的工作流程!
系好安全带,这将是一次颠簸的旅程
来源:吉菲
摩丁
厌倦了在处理大型数据帧时的漫长等待时间?— 摩丁来救援了!
摩丁使用 Ray 或 Dask 来提供一种毫不费力的方式来加速你的熊猫笔记本、脚本和库。与其他分布式数据框架库不同,Modin 提供了与现有 pandas 代码的无缝集成和兼容性。即使使用 DataFrame 构造函数也是一样的。
摩丁用一行代码的改变加速你的熊猫工作流程
安装
Modin 是加州大学伯克利分校 RISELab 的完全开源项目。这是该项目的 GitHub 链接
要使用 Modin,替换熊猫导入:Modin 可以从 PyPI 安装:如果你没有安装 Ray 或 Dask,你…
github.com](https://github.com/modin-project/modin)
可以通过 PyPI 快速安装 Modin:
pip install modin
用法
使用 Modin 就像使用 Pandas dataframe 一样简单。把熊猫当 pd 换成 modin.pandas 当 pd 就行了。
# import pandas as pd
import modin.pandas as pd
你都准备好了!使用具有增强计算能力和更快速度的数据帧优化您的 pandas 工作流程:)
达斯克
需要比摩丁更快的处理能力?—向达斯克问好!
Dask.distributed 是一个用于 Python 分布式计算的轻量级库。Dask.distributed 是一个集中管理的分布式动态任务调度程序。中央dask-scheduler
进程协调分布在多台机器上的几个dask-worker
进程的动作以及几个客户机的并发请求。
安装
Dask 也是一个开源框架,由他们的开发者积极维护。这是他们 GitHub 链接上的源代码:
带有任务调度的并行计算。在 GitHub 上创建一个帐户,为 dask/dask 开发做贡献。
github.com](https://github.com/dask/dask)
Dask 可以使用 pip 轻松安装:
python -m pip install dask distributed --upgrade
光线
想要释放分布式计算的力量吗?—欢迎雷!
Ray 与 TensorFlow、PyTorch、MXNet 等深度学习框架完全兼容,在很多应用中很自然地会与 Ray 一起使用一个或多个深度学习框架(比如我们的强化学习库大量使用 TensorFlow 和 PyTorch)。
摩丁使用射线来提供一种毫不费力的方式来加速熊猫的笔记本、脚本和库。Ray 是一个高性能分布式执行框架,目标是大规模机器学习和强化学习应用。
安装
Ray 也是一个开源项目。这是 Ray 的 GitHub 链接:
Ray 是一个快速而简单的框架,用于构建和运行分布式应用程序。雷被包装成…
github.com](https://github.com/ray-project/ray/)
可以通过以下命令使用 pip 快速安装 Ray:
pip install ray
PySpark
想要利用内存中的处理能力吗?— PySpark 正是正确的选择!
PySpark 是一种很好的语言,可以进行大规模的探索性数据分析,构建机器学习管道,为数据平台创建 ETL。PySpark 使用内存计算能力,使数据帧比以往更快。Spark 数据帧是数据科学家和数据工程师的首选,因为它们通过用内存资源取代计算能力来提高速度,并且提供了连接外部框架的巨大灵活性
安装
Spark 由 Apache 维护,是一个开源框架,拥有活跃的开发人员社区。下面是 GitHub 上 Spark 的源代码:
Spark 是用于大规模数据处理的统一分析引擎。它提供了 Scala、Java……
github.com](https://github.com/apache/spark)
使用以下命令可以很容易地安装 Spark:
确保您的机器上安装了 Java :
brew cask install java
由于 spark 是用 Scala 编写的,我们需要包含 Scala 依赖关系:
brew install scala
最后,在安装完所有依赖项后,使用以下命令安装 PySpark :
brew install apache-spark
用法
产生火花就像下面这样简单。就像摩丁一样,spark 和熊猫也有语法上的差异
df = spark.read.json("examples/src/main/resources/people.json")
迷茫?
来源:吉菲
对很多选项感到困惑?别担心。只需分析您正在处理的数据集并选择合适的框架。假设您正在处理一个只有几个字节的数据集——选择 Modin 将是一个不错的选择,因为您可以最大限度地发挥笔记本电脑的潜力。但是,让我们假设您正在处理一个 ETL 管道,其中摄取的数据非常巨大。在这种情况下, PySpark 会完成这项工作,但是您可能会想到一个替代框架,比如 Ray ,在这个框架中,您可以将负载分布到一个机器集群上,并充分利用并行计算!
请随意评论更好的选择和您的建议,使熊猫数据帧更快!
参考
[1]https://www.kdnuggets.com/2019/11/speed-up-pandas-4x.html
https://github.com/modin-project/modin
[3]https://github.com/ray-project/ray
https://modin.readthedocs.io/en/latest/
https://github.com/apache/spark
用这 6 个小窍门提高你的效率
并控制您的阵列
动机
有时,当我向我的朋友展示我使用的一些数字方法时,他们会发现它们很有帮助。所以我决定分享这些数字方法(或技巧),希望你也会发现它们很有帮助。
从导入 Numpy 开始
import numpy as np
面具
假设我们有一个数组,我们想在这个数组中选择一个特定的元素:0,2,并删除其他元素。有没有一种快速的方法可以选择这两个元素?口罩就可以了。
>>> A = np.array([0, 1, 2, 3, 4, 5])>>> mask = np.array([True, False, True, False, False, False])>>> A[mask]array([0, 2])
我们可以看到,标记为False
的元素被删除,而标记为True
的元素被保留。
随意
创建快速随机数组是测试代码的一种有用且快速的方法。但是有不同的np.random
方法,你可能想要选择一种而不是另一种来用于特定的用途。
用 0 到 1 范围内的给定形状创建随机值
>>> np.random.rand(10,2)array([[0.38850622, 0.31431385],
[0.00815046, 0.13334727],
[0.47482606, 0.92837947],
[0.89809998, 0.38608183],
[0.25831955, 0.56582022],
[0.36625782, 0.52753452],
[0.88125428, 0.71624809],
[0.83642275, 0.79315897],
[0.27361664, 0.8250761 ],
[0.89894784, 0.95994016]])
或者创建特定范围内具有特定大小的随机整数数组
>>> np.random.randint(0,10,(3,3))array([[0, 9, 6],
[1, 7, 3],
[6, 4, 7]])
类形状阵列
你有没有发现自己创建了第二个数组,它的尺寸与第一个数组的尺寸相同,但元素不同?通常的做法是使用shape
来捕捉第一个数组的维度
>>> A = np.random.randint(0,10,(3,3))>>> A.shape(3, 3)>>> B = np.zeros(A.shape)array([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])
这种方法没有错。但是有一个更快的方法来创建一个类似的数组,用 0 或 1 作为元素,用zeros_like
或ones_like
>>> A = np.random.randint(0,10,(3,3))>>> B = np.zeros_like(A)>>> Barray([[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]])>>> B = np.ones_like(A)>>> Barray([[1, 1, 1],
[1, 1, 1],
[1, 1, 1]])
正如我们所见,数组 B 与数组 A 的维数相同,但元素不同。
使再成形
如果我们想改变一个数组的维数,reshape
将是我们要使用的方法
>>> A = np.arange(9)>>> Aarray([0, 1, 2, 3, 4, 5, 6, 7, 8])#Reshape to 3x3 matrix>>> A.reshape((3,3))>>> Aarray([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
或者展平
>>> A.reshape(-1)array([0, 1, 2, 3, 4, 5, 6, 7, 8])>>> A.flatten()array([0, 1, 2, 3, 4, 5, 6, 7, 8])
reshape(-1)
或flatten()
将完成展平阵列的工作。
变换超出范围数组
假设我们有一个范围从-3 到 6 的矩阵 B
>>> B = np.arange(-3,9).reshape((3,4))>>> Barray([[-3, -2, -1, 0],
[ 1, 2, 3, 4],
[ 5, 6, 7, 8]])
但是我们只想保持元素的范围从 0 到 5,并将超出范围的元素转换为范围内的元素。我们如何做到这一点?这时我们需要np.clip
>>> np.clip(B,0, 5)array([[0, 0, 0, 0],
[1, 2, 3, 4],
[5, 5, 5, 5]])
从变换后的矩阵可以看出,0 以下的元素变换为 0,5 以上的元素变换为 5,而范围内的元素保持不变。
洗牌
有时,我们希望使用随机数组,但我们的数组可能不是随机的。想想一副牌,当我们怀疑牌可能以特殊方式排序时,我们会怎么做?我们洗牌!
>>> A = np.arange(9).reshape((3,3))>>> Aarray([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])>>> np.random.shuffle(A)>>> Aarray([[3, 4, 5],
[0, 1, 2],
[6, 7, 8]])
正如我们所看到的,数组 A 中的元素与原始元素的位置不同。
结论
我希望这篇文章有助于为您的数据科学和编程实践添加一些新的 Numpy 技巧。拥有几个有用的方法来操作数组将极大地提高您的工作流程,并为您提供转换数组以满足特定需求的灵活性。
在 this Github repo 中,您可以随意使用本文的代码。
我喜欢写一些基本的数据科学概念,并尝试不同的算法和数据科学工具。你可以通过 LinkedIn 和 Twitter 与我联系。
如果你想查看我写的所有文章的代码,请点击这里。在 Medium 上关注我,了解我的最新数据科学文章,例如:
使用字典创建一个更清晰的 If-Else 函数代码
towardsdatascience.com](/dictionary-as-an-alternative-to-if-else-76fe57a1e4af) [## 如何用 Faker 创建假数据
您可以收集数据或创建自己的数据
towardsdatascience.com](/how-to-create-fake-data-with-faker-a835e5b7a9d9) [## 跟踪数据的 Python 技巧
如何用列表、字典计数器和命名元组来跟踪信息
towardsdatascience.com](/python-tricks-for-keeping-track-of-your-data-aef3dc817a4e) [## 高效 Python 代码的计时
如何比较列表、集合和其他方法的性能
towardsdatascience.com](/timing-the-performance-to-choose-the-right-python-object-for-your-data-science-project-670db6f11b8e) [## cy thon——Python 函数的加速工具
当调整你的算法得到小的改进时,你可能想用 Cython 获得额外的速度,一个…
towardsdatascience.com](/cython-a-speed-up-tool-for-your-python-function-9bab64364bfd)
增强你对助推的把握🚀
揭秘著名的竞赛获奖算法。
比尔·杰伦在 Unsplash 上的照片
boosting 的普及是应用机器学习的重大突破。得益于多个软件包,boosting 天生易于实现,同时在许多任务上实现高性能,已经成为许多人的默认首选方法。在工业中,它被用来制造有价值的产品,被围棋大师用来赢得比赛。在本文中,我们将详细讨论升压。
请继续阅读,了解:
- 虽然最初令人生畏,但助推实际上很容易理解。
- 只需几行代码就可以实现不同的增强风格。
- 是什么让一个好的弱学习者得到提升,为什么树是一个普遍的选择。
- 自适应增强和梯度增强的区别。
- 你可以调整哪些旋钮来优化升压算法。
什么是助推?
Boosting 是一种集成技术,它将多个被称为“弱学习者”的顺序拟合的简单模型聚合成一个“强学习者”模型。本质上,增强预测只是弱学习者预测的加权平均,例如:
- 较好的弱学习者获得较大的权重,
- 当拟合时,每个弱学习者优先考虑被前一个错误预测的观察,从而专注于最困难的情况。
就这么简单。
特定的提升算法,比如我们马上要谈到的自适应或梯度提升,主要区别在于如何计算弱学习者的权重,以及如何对最困难的观察进行优先排序。
自适应增压
从实际的角度来看,从历史的角度来看,让我们看看第一个 boosting 算法。自适应增强,也称为 AdaBoost,早在 1997 年就被提出。它最初是为分类任务设计的,后来才扩展到回归设置。为了更加集中,我们将分析分类案例。
AdaBoost 的想法是使用样本权重来拟合弱学习者。我们从每个具有相同权重的观察开始,随着连续弱学习者的建立,观察权重得到更新,以将更多的重点放在困难的情况上。下面的模式概述了在单个自适应增强迭代中会发生什么。希望它能把这一点讲清楚。
自适应增压程序。
一旦合适了所需数量的弱学习器,就可以通过简单地对它们的预测进行平均来获得最终的预测,这些预测由各自的模型权重进行加权。
我们自己编码吧!我们的弱学习器将是简单的决策树,我们将对垃圾邮件数据集应用 AdaBoost,其中的任务是根据一组描述电子邮件中使用的词频的特征将电子邮件分类为垃圾邮件或非垃圾邮件。数据以及加载和处理数据的代码都可以在这里获得。现在,你只需要知道我们有一个二进制目标,对于垃圾邮件编码为 1,对于非垃圾邮件编码为-1,还有一组功能,25%的数据已经作为测试集放在一边。
下面的代码遵循上面的模式。为了编程方便,我们将在每次迭代中添加加权弱学习者的预测,将累积和存储在加权 _ 测试 _ 预测 _ 和变量中。此外,每次迭代我们将评估当前的性能,以便我们可以看到它如何随着提升迭代的数量(即弱学习者的数量)的增加而提高。
Final accuracy 0.945
让我们画出测试精度在提升迭代中的图。
AdaBoost:测试 boosting 迭代的准确性
我们拟合的第一棵树(具有相等的观察权重)获得了大约 79%的准确度。然后,随着提升迭代次数的增加,精确度也在增加,尽管速度在下降。经过 500 次迭代,我们达到了几乎 95%的准确率!但是你有没有想过为什么我们使用决策树作为我们的弱学习器?
哪些是最好的弱学习者,为什么?
要回答这个问题,我们首先需要讨论一种叫做偏差-方差权衡的现象。简而言之:如果预测模型是错误的,这可能是由于以下三个因素之一:
- 当模型不够复杂,无法捕捉数据中的关系时,就会出现偏差(或拟合不足);
- 当模型过于复杂、熟记训练数据并且在看不见的数据上表现不佳时,会出现方差(或过度拟合);
- 我们无能为力的无法解释的错误。
在大多数机器学习模型中,倾向于在偏差和方差之间进行权衡。也就是说,具有高方差的模型通常具有低偏差,反之亦然。 Boosting 通过拟合专注于解决难题的连续模型,旨在减少偏差。因此,可以从提升中受益最多的弱学习者候选是那些具有低方差(期望的)和高偏差(将在提升过程中减少)的学习者候选。
好吧,那么什么样的模型符合这些标准呢?线性回归,一个人能想到的最基本的模型呢?根据定义(和一些假设),线性回归的普通最小二乘估计量是无偏的,例如:偏差可以显示为恰好为零。因此,它不是一个很好的候选人。
决策树呢?你可能已经注意到我们是如何在上面的 AdaBoost 代码中适应弱学习者的:
model = DecisionTreeClassifier(max_depth=1)
通过限制树的深度,我们不允许它变得太复杂以至于超出数据的范围;不仅如此:它不可能变得足够复杂以适应数据。这样,我们就有了一个低方差(没有能力过度拟合)和潜在高偏差(过于简单,无法捕捉数据中的信息)的学习者。这是升压的理想情况,我们已经看到它提高了多少精度。
为了验证以上所说的,让我们试着不要限制树。让我们对以下弱学习者运行相同的 AdaBoost 代码:
model = DecisionTreeClassifier()
我们期望什么?我们的弱学习器现在将是一个过拟合模型,即高方差、低偏差。因此,我们预计提振不会带来多少改善。这是测试精确度在提升迭代中的曲线图。
AdaBoost:使用过拟合弱学习器测试 boosting 迭代的准确性
正如预期的那样,AdaBoost 将过度拟合的弱学习器的准确率提高了约 1.5 个百分点,达到 92%。这发生在最初的几次迭代中,随后没有进一步的改进。与之前弱学习者的更好选择相比。在那里,准确率提高了大约 15 个百分点,几乎达到 95%。
总而言之,我们已经说过,好的弱学习者是那些对数据拟合不足的人。受限树是好的,复杂树和线性回归就不那么好了。其他低方差、高偏差模型呢?你也可以提升它们,但是树是最受欢迎的。其原因如下:
- 即使数据量增加,树也能快速适应和扩展。这一点很重要,因为在推进过程中,每个弱学习者都需要前一个学习者的输入来改进它。因此,模型必须按顺序拟合,不能并行计算。如果一个模型需要很长时间才能适应,那么提升许多模型将需要很长时间。
- 树拥有许多属性,使它们适用于杂乱的数据,而不需要太多的数据预处理。例如,他们对各自预测因子的尺度和应用于它们的单调变换漠不关心。它们还可以自动处理不同的变量类型,并通过构造对异常值和无用预测值具有鲁棒性。
现在让我们来看看另一种提升树木的方法!
梯度推进
梯度推进是另一种推进方式。与自适应增强类似,它也输出弱学习者预测的加权平均值。主要区别在于,AdaBoost 在迭代过程中更新观测值权重,而梯度提升则更新观测值本身。
程序如下。我们需要从训练数据的一些预测开始。因为在拟合任何模型之前,我们没有模型,我们简单地用目标的样本均值初始化它们。然后,我们重复下面的多次。我们计算相对于当前预测的损失函数的负梯度。下面的代码使用了均方误差损失的梯度,这对于二进制分类来说不是最佳的,但是我们使用它来保持简单。然后,我们将回归树拟合到这些负梯度,并将该树的拟合值(可能乘以某个学习率)添加到我们在开始时初始化的累积训练集预测中。一旦运行了期望数量的提升迭代,我们就可以提取最终的预测。因为我们的目标被编码为-1 或 1,我们简单地取累积预测的符号。
下面的模式概述了在使用树作为弱学习器的单个梯度提升迭代中发生的情况。希望它能把这一点讲清楚。
梯度推进程序
我们来编码吧!与前面的 AdaBoost 代码片段一样,这里我们也在 boosting 迭代中计算测试数据的预测,并在之后绘制。
Final accuracy 0.933
梯度增强:测试增强迭代的准确性
我们已经获得了与 AdaBoost 相似的精度。据推测,使用比 MSE 更合适的损失函数会改善结果。
参数化升压算法
您可能已经注意到,在梯度推进代码中,我们使用了一个名为学习率的超参数,我们将其设置为 1。因为它作为乘法因子进入等式,所以值 1 会影响结果。如果我们将其设置为 0.1,那么最终的精度将会提高 1 个百分点。自己随便玩吧!
在任何升压算法中,还有更多可以参数化的东西。然后可以调整这些参数来优化性能。在不涉及太多细节的情况下,让我列举其中的一些。这绝不是一个详尽的集合。
- 学习率:我们可以用一个介于 0 和 1 之间的因子来衡量每棵树对整体的贡献,以避免过度拟合。这在精神上有点类似于在岭回归中加入收缩。对于较小的学习率,我们可能需要增加提升迭代的次数。
- 提升迭代的次数:太大可能导致过度拟合,太小可能阻止提升算法达到最佳性能。
- 子采样行:在梯度推进模型中,可以让弱学习者适应数据的引导样本,而不是实际数据。bootstrap 样本是从原始数据行中替换抽取的样本。这往往会使模型更好地概括。
- 子采样列:在每次迭代中使用随机选择的特征列来拟合弱学习者。
- 所有弱学习者的参数。在树的情况下:最大树深度,在树的叶节点上进一步划分所需的最小损失减少,等等。
简单地
- Boosting 是一种集成技术,它将多个被称为“弱学习者”的顺序拟合的简单模型聚合成一个“强学习者”模型。这个组合基本上是弱学习者预测的加权平均。
- 升压有利于减少偏差。因此,要提升的理想弱学习者是那些具有高偏差和低方差的学习者,即简单的欠拟合模型。一个流行的选择是约束树模型。
- 增强的两种主要方式是自适应增强和梯度增强。
- 自适应增强使用样本权重使弱学习者适应数据。在整个过程中,权重会更新,以便将更多的注意力放在最难正确预测的观察结果上。
- 梯度提升使弱学习器不适合原始数据,而是适合损失函数相对于当前预测的负梯度。后者随着迭代而更新。
- 为了优化 boosting 算法的性能,可以调整多个超参数,这些超参数定义了弱学习者如何学习以及它们具体适合哪些数据。
感谢阅读!我希望你已经学到了一些有用的东西,将推动你的项目🚀
如果你喜欢这篇文章,试试我的其他文章。不能选择?从这些中选择一个:
详细介绍 7 种流行的收缩和选择方法。
towardsdatascience.com](/a-comparison-of-shrinkage-and-selection-methods-for-linear-regression-ee4dd3a71f16) [## 线性分类器:综述
本文讨论了四个流行的线性函数的数学性质和 Python 的实际应用
towardsdatascience.com](/linear-classifiers-an-overview-e121135bd3bb) [## 插补的不确定性
你在预测中考虑到它了吗?
towardsdatascience.com](/uncertainty-from-imputation-8dbb34a19612)
来源
- Hastie,Tibshirani,r .,,j . h . Friedman(2009 年)。统计学习的要素:数据挖掘、推理和预测。第二版。纽约:斯普林格。
使用这些神奇的库来提高模型的性能
将 XGBoost 和 CatBoost 应用到您的机器学习模型中!
质量取决于准确性和完整性。
公司使用机器学习模型来做出实际的商业决策,更准确的模型结果会带来更好的决策。错误的代价可能是巨大的,但是优化模型精度可以降低这种代价。机器学习模型准确性是一种衡量标准,用于根据输入或训练数据确定哪个模型最擅长识别数据集中变量之间的关系和模式。一个模型越能概括“看不见的”数据,它就能产生越好的预测和洞察力,从而带来更多的商业价值。
谷歌图片
癌症预测数据集
我选择的数据集是乳腺癌预测数据集。我们需要预测癌症是恶性的还是良性的。每一行对应一个患者,对于这些患者中的每一个,我们有几个特征,从凝块厚度,细胞大小的均匀性等。所有这些特征都是肿瘤的特征。如果我们得到 2 级,结果是良性的,如果我们得到 4 级,结果是恶性的。所以类别变量成为我们的因变量,告诉我们它是良性的还是恶性的。我已经建立了决策树模型,并实现了 95.3%的准确率,这是与其他分类模型相比最高的。
在这之后,我建立了 XGBoost 模型,我在同一个数据集上对它进行了训练,我想看看准确性是否跨越了决策树分类模型。我不仅在测试集上训练了它,而且还使用了 K-fold 交叉验证,我们将在 10 个测试集上测试它,以便我们可以获得相关的准确性度量。
现在让我们开始实施吧!
**Importing the libraries**import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
首先,我们导入实现所需的库。
**Importing the dataset**dataset = pd.read_csv('/content/Data.csv')
X = dataset.iloc[:,:-1].values
y = dataset.iloc[:,-1].values
x 包含患者的所有特征,并由所有独立变量组成。y 包括因变量,即类别变量。
**Splitting the dataset into Training set and Test set**from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, random_state = 0)
接下来,我们将数据集分为训练集和测试集,前者用于训练模型,后者用于评估结果。
在此之后,我们建立了三个不同的模型,并比较了所有模型的准确性。
决策树分类
谷歌图片
**Feature Scaling**from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
X_train = sc.fit_transform(X_train)
X_test = sc.transform(X_test)
由于变量值的范围变化很大,我们需要应用特征缩放,以便所有变量都缩小到一个可比较的范围。我们只需要对决策树分类应用特征缩放,而不需要对 XGBoost 和 CatBoost 应用特征缩放。
**Training the Decision Tree Classification model on the Training set**from sklearn.tree import DecisionTreeClassifier
dtc = DecisionTreeClassifier(criterion = 'entropy', random_state = 0)
dtc.fit(X_train, y_train)
导入 DecisionTreeClassifier 类,然后创建该类的一个实例。然后应用拟合函数在训练集上训练模型。
**Making the Confusion Matrix for Decision Tree**from sklearn.metrics import confusion_matrix, accuracy_score
y_pred = dtc.predict(X_test)
cm = confusion_matrix(y_test, y_pred)
print(cm)
accuracy_score(y_test, y_pred)[[103 4]
[ 3 61]]0.9590643274853801
从度量模块导入混淆矩阵和准确度分数函数。
混淆矩阵显示出来,accuracy_score 给出了我们模型的准确度。这个模型的准确率我已经达到了 95.9%。
当我们在不同的测试集上测试我们的模型的性能时,我们获得了不同的精度。这就是为什么我们找到 10 个精度,然后取所有这些精度的平均值,找到我们模型的最佳精度。所以这种方法被称为 K 重交叉验证法。
**Applying the K-Fold Cross Validation for Decision Tree**from sklearn.model_selection import cross_val_score
accuracies = cross_val_score(estimator = dtc, X = X_train, y = y_train, cv = 10)
print("Accuracy:{:.2f} %".format(accuracies.mean()*100))
print("Standard Deviation:{:.2f} %".format(accuracies.std()*100))Accuracy:94.53 %
Standard Deviation:1.91 %
应用此方法后,精度变量包含获得的所有精度的列表。然后我们打印出模型的总体精度和标准偏差。因此,在各种测试集上评估该模型,并且评估每个测试集的准确性。在所有测试集上验证后达到的准确度为 94.53%,标准偏差为 1.91%,这是相当低且相当好的。
XGBOOST
谷歌图片
XGBoost 是一个优化的分布式梯度增强库,旨在高效、灵活、可移植。所以它是一个基于决策树的集成机器学习算法,使用了梯度提升框架。
要安装 XGBoost,您可以参考本文档
**Training XGBoost to the training set**from xgboost import XGBClassifier
xgboost=XGBClassifier()
xgboost.fit(X_train,y_train)
现在我已经用一个惊人的库 XGBoost 库训练了这个模型。
**Making the Confusion Matrix for XGBoost**from sklearn.metrics import confusion_matrix, accuracy_score
y_pred = xgboost.predict(X_test)
cm = confusion_matrix(y_test, y_pred)
print(cm)
accuracy_score(y_test, y_pred)[[84 3]
[ 0 50]]0.9781021897810219
最初,用决策树建立的模型准确率为 95.9%。但是在 XGBoost 之后,准确率达到了 97.8%,令人印象深刻。
类似地,我们对 XGBoost 模型执行 K-Fold 交叉验证。
**Applying the K-Fold Cross Validation for XGBoost**from sklearn.model_selection import cross_val_score
accuracies = cross_val_score(estimator = xgboost, X = X_train, y = y_train, cv = 10)
print("Accuracy:{:.2f} %".format(accuracies.mean()*100))
print("Standard Deviation:{:.2f} %".format(accuracies.std()*100))Accuracy:96.53 %
Standard Deviation:2.07 %
我们的模型的整体准确率为 96.53%,这是非常酷的。
这是我们能达到的最高精度吗?让我们试着用其他库来测试它,看看我们是否能击败这个精度。
CATBOOST
谷歌图片
CatBoost 是一个高性能的开源库,用于决策树上的梯度提升。CatBoost 是一种基于梯度下降的算法,它有一个非常特殊的功能,称为自调整。它不需要调整,并将自我训练以找到最佳参数和最佳得分,例如,用于回归的最佳 R 平方,用于分类的最佳准确度。这是 CatBoost 的关键特性。
要安装 CatBoost,您可以参考此文档
**Training CatBoost to the training set**from catboost import CatBoostClassifier
catboost = CatBoostClassifier()
catboost.fit(X_train, y_train)
现在我已经用一个很棒的库训练了这个模型,这个库就是 CatBoost 库。CatBoost 经过几次迭代,将自己调整到最佳参数,以找到最高的精度(它将为特定问题找到最佳超参数)
**Making the Confusion Matrix for CatBoost**from sklearn.metrics import confusion_matrix, accuracy_score
y_pred = catboost.predict(X_test)
cm = confusion_matrix(y_test, y_pred)
print(cm)
accuracy_score(y_test, y_pred)[[84 3]
[ 0 50]]0.9781021897810219
有趣的是,XGBoost 和 CatBoost 的精度是一样的。现在,让我们对 CatBoost 模型进行 K 倍交叉验证,并比较结果。
**Applying the K-Fold Cross Validation for CatBoost**from sklearn.model_selection import cross_val_score
accuracies = cross_val_score(estimator = xgboost, X = X_train, y = y_train, cv = 10)
print("Accuracy:{:.2f} %".format(accuracies.mean()*100))
print("Standard Deviation:{:.2f} %".format(accuracies.std()*100))Accuracy:97.26 %
Standard Deviation:2.03 %
太好了!!我们在 K-fold 交叉验证上取得了 97.26%的准确率,这太不可思议了!因此,XGBoost 的准确率从 94.53%提高到 96.53%,但对于 CatBoost,准确率要高得多,因为我们在 CatBoost 的 K 倍交叉验证集上获得的准确率为 97.26%,这绝对令人惊叹。CatBoost 以将近 1%的优势击败 XGBoost。
这两个库非常强大,因为它们极大地提高了机器学习模型的准确性,并且背后涉及到大量的数学知识。理解数学以及它如何提高模型的性能也很重要。因此,使用这两个库非常好,因为它们可以提供更好的预测,还可以提高机器学习模型的性能。还有其他强大的库,比如 Light GBM ,它们在很大程度上提高了我们的准确性。
在这篇文章中,我试图详细讨论一切。但是你可以随时参考我的 Github 库 获取完整代码。
在 LinkedIn 上与我联系
“快固然好,但准确才是最重要的。”-怀亚特·厄普
我希望你觉得这篇文章很有见地。我很乐意听到反馈,以便即兴创作,并带来更好的内容。
非常感谢您的阅读!
没有技术术语的助推算法
没有术语的机器学习
不可能的任务?任务完成…
图片由 Wasserstrom 通过谷歌图片提供
介绍
在我之前的帖子中(见下文),我用人们投票的类比来展示加权随机森林和 boosting 算法之间的区别。概括地说,加权随机森林的规则是,投票给结果 A 的每个人都将被计算更多。提升算法的规则是,谁更有资格,谁就能投更多的票。如果结果 A 赢得了更多的选票,那么它就是。
不平衡数据集完整工具包
towardsdatascience.com](/from-imbalanced-dataset-to-boosting-algorithms-1-2-798cd6384ecc)
这篇文章将介绍每个提升算法如何决定每棵树拥有的票数。通过理解算法是如何工作的,我们将理解我上一篇文章中所展示的性能差异。并且更好地知道何时使用哪个工具。
boosting 一家三口。它们是自适应增强、梯度增强和 XG 增强。它将被依次讨论。
adaboost 算法
Adaboost 只使用一个因素来决定一棵树的发言权——它的准确性。然而,有一个偷偷摸摸的转折。每棵树都被一组略有不同的样本训练。为什么
想象一下,你正在准备你的 SAT 考试,有四个部分:阅读,写作,数学 1(有计算器),数学 2(没有计算器)。为简单起见,我们假设每个部分有 15 个问题要回答,总共 60 个问题。你做了一次模拟考试,你意识到你在数学 1 中得分最低。所以下一次,你要多练习数学 1 题,少练习其他部分的题。因此,你仍然每次练习 60 个问题,但组合略有不同。
Adaboost 也是一样。Adaboost 的一个特别之处在于,它建立了一个带有“stump”的森林,一个一级深度的树。稍后我将对此进行更多的讨论。现在,把它当作一种约束。让我们先解决它是如何决定一棵树/树桩的话语权的。
假设我们想要建立一个模型来预测客户是否会购买我们的新产品。我们有 6 个样本客户。我们有来自 Amy、Tom、John、Tim、Lucy 和 Mike 的数据(见下图 1)。以下是建立目录林的步骤:
- 像建一棵普通的树一样建一个树桩。所以选择能正确分类大多数样本的变量。这就是我们的树桩 1。如果你不熟悉一棵树是如何建造的,你可以通过阅读这篇文章了解更多。
使用业务语言并在业务环境中理解随机森林
medium.com](https://medium.com/swlh/programming-journal-2-what-is-and-why-random-forest-without-technical-jargon-c5a9a69d8739)
2.树桩 1 有 83%的准确率,而蒂姆被错误地分类了。因此,我将把样本 Tim 的权重提高到 0.3,把其他样本的权重降低到 0.14,这样它们加起来就是 1。
等等…但是“提高样品的重量”是什么意思?很好的问题,但超出了我的帖子范围。你可以看看这个视频看看它是怎么做的。简而言之,有两种方法。您可以根据权重创建新的样品组,也可以使用加权 GINI 指数。但是,直觉和我上面给的 SAT 类比是一样的。
GIF via GIPHY
3.我使用新的加权样本构建 stump 2,准确率为 87%。约翰被错误地归类了。因为正确分类每个样本的权重现在略有不同,stump 2 有 87%的准确性(注意:这不是精确的计算)。
图片 1
4.下一次,我会提高约翰的重量,降低其他样品的重量。如果我们没有设置我们想要的最大树数,那么这个过程将会重复,直到我们达到 100%的准确率。
图片 2
假设我将限制设置为 3 个树桩。就像我之前提到的,每个树桩的投票数完全取决于他们模型的准确性。它用下面的公式来决定它的最终发言权。
图 3
括号内的一切反映了模型给出正确预测的可能性。例如,对于 stump 1,给出正确预测的可能性是错误预测的 5 倍。
神奇的是日志部分。因为对数的性质,如果我们的模型有 0 个误差(分母趋向于 0),我们给出无穷的正幂。如果我们有许多错误,我们将通过记录它给出一个大的负数(尝试将 99%作为错误率)。
5.在我们知道每个候选人有多少发言权后,我们简单地把他们的投票加起来。得票多的班级获胜。
图 4
好吧,但是我们为什么要用树桩呢?为什么不用树呢?
让我们退一步,看看整个画面。这里的关键思想是突出难以预测的样本,以便我们可以建立一个针对这些样本的模型。
当我们构建一个多于 1 层的树时,预测也取决于我们如何构建树。通过使用不同顺序的预测器,我们可以得到不同的预测。这削弱了我们的目标。你可以从这里了解更多关于如何构建一棵树的信息:
使用业务语言并在业务环境中理解随机森林
medium.com](https://medium.com/swlh/programming-journal-2-what-is-and-why-random-forest-without-technical-jargon-c5a9a69d8739)
这也是为什么对于不平衡数据集,boosting 算法比随机森林和决策树提供了更健壮的分析。Boosting 算法结合了更好地预测少数类的模型。
Ada boost 的问题是,每次构建一个 stump,都需要重新构建整个样本集!想象一下,你有成千上万的样本,甚至计算机也不想做这项工作。所以才推出了 Gradientboost!
梯度推进:
Gradientboost 通过不使用样本构建树解决了这个问题。它使用预测和实际结果之间的差异,也就是残差来构建树。图 6 向你展示了什么是剩余树,如果你像我一样困惑的话。
GIF via GIPHY
图 5 简单地展示了这个过程。基于样本集,我们将首先给出一个对数(赔率)预测,也就是说,我们的模型预测一个类别优于另一个类别的可能性有多大。然后,我们将对数(赔率)转换成概率,并计算残差。从这里,我们将开始建立一个森林,使每棵树的残差最小化。然后我们把所有的东西和初始预测一起加起来。终于,我们有了新的概率!
图 5
如果你不知道什么是对数(赔率)以及我们为什么使用它,先学习逻辑回归。你可以通过阅读下面的文章来了解更多关于逻辑回归的知识。
如果你喜欢披萨,你就会明白逻辑回归和随机森林的区别!
towardsdatascience.com](/programming-journal-3-logistic-regression-cbf68f01bf7d)
这里有一个例子来形象化这个过程,以便我们能更好地理解它。我们有一个分类问题,因此,我们的预测可以是 0 或 1。在这个例子中,我们有四个 1 和两个 0。因此,我们的对数(赔率)是 0.69。在我们把它转换成概率之后,它将是 0.67。Amy 的残差为 1–0.67,Tom 的残差为 0–0.67。在右边,我比较了一棵规则树和一棵剩余树。
图 6
在一棵普通的树上,树叶给我们一个最终的类别预测,例如,红色或绿色。在残差树中,树叶给了我们残差。比如从左到右,第一片叶子(-0.7)是-0.7(咄…)。第二片叶子(0.3,-0.7)是-0.4,最后一片叶子是 0.9。
这里的直觉是:如果叶子加起来是一个大的负数或大的正数,它把正确的样本组合在一起。另一方面,如果它们不是同一个东西,值会互相抵消,因此接近于 0。
一棵树的价值是它所有叶子的总和。在我们建立了所有的树之后,我们将所有的树值相加,并将它们添加到初始的对数预测中。因此,如果一棵树具有更大的值(更善于分裂组),它将对初始预测应该如何改变具有更大的影响。
图 7
每棵树的价值将乘以 0.1。这个值被称为学习率,你可以任意选择任何值,但 0.1 是转换。它很小,所以它确保每棵树只是稍微改变初始值。
关于 Gradientboost 我想说的最后一点是,它实际上使用了一棵树,而不是树桩。但是通常我们将 max_depth 限制在 6 到 8 之间,以避免过度拟合。Gradientboost 不使用树桩,因为它不使用树来检测困难的样本。它正在构建树以最小化残差。
更多的技术见解(随意跳过):一棵树如何影响另一棵树。
当我们计算一片叶子的值时,我们实际上使用下面的公式,而不是简单地将残差相加。我想分享一些关于我们如何理解这个公式的直觉。这个公式的实际数学是超级讨厌的。它涉及二阶导数。所以我们不要去那里。
图 8
在上面的公式中,分母中的 P 是我们最后一棵树基于其总对数(odds)给出的概率。我在下面列出了四种情况,这样我们就能明白这个公式的含义了。
图 9
从分母来看,如果前一棵树对自己的预测非常有信心,那么下一棵树就有更大的值(更大的发言权)。从分子上看,如果当前树的残差很大,那么也会导致更大的值。这就像我们已经讨论过的一样。这也是最后一棵树的准确性如何影响下一棵树在森林中的发言权。
为什么我们还需要 XGboost?
GIF via GIPHY
XGboost 是专门为大型数据集设计的,因为它非常快。它使用了许多优化和正则化技术,这超出了我想谈论的范围。
我想强调 XGboost 和 Gradientboost 之间的一个关键区别。在 Gradientboost 中,在我们计算每个样本的残差后,我们选择一个节点进行分割,并继续使用传统方法构建树。面对大型数据集时,这一过程可能会非常昂贵。
因此,XGboost 更进了一步。它没有使用谓词作为树节点。它构建树来将残差分组在一起。就像我之前提到的,相似的样本会有相似的残值。所以树节点是可以分隔残差的值。所以 XGboost 中的叶子是残差,XGboost 中的树节点是可以对残差进行分组的值!
XGboost 的速度使得它对于大型数据集来说确实可行。然而,当我们有合理数量的样本时,比如几千个样本,Gradientboost 实际上更健壮。
我希望这能说明为什么 Gradientboost 是我在做流失分析时最健壮的算法。只有 3333 个样本。您可以点击此处的文章查看完整的分析:
不平衡数据集完整工具包
towardsdatascience.com](/from-imbalanced-dataset-to-boosting-algorithms-1-2-798cd6384ecc)
GIF via GIPHY
我说完了:)
我在帖子中链接的视频和文章:
其他重要资源:
用可解释的人工智能推进机器学习模型(XAI)
关于 Airbnb 房源的见解
对于典型的机器学习模型,传统的特征重要性分析的相关性通常具有有限的价值。在数据科学家的工具包中,是否有可靠的、系统的、模型不可知的方法来测量对预测的特性影响?答案是肯定的。
这里我们用一个建立在 Airbnb 数据上的模型来说明:
- 可解释的人工智能(XAI)技术
- XAI 能为全球和地方解释做些什么
- XAI 能为模型增强做些什么
XAI——概述
随着人工智能在更多应用中获得牵引力,可解释人工智能(XAI)越来越成为清晰解释和自信部署的关键组件。对于机器学习和深度学习来说,XAI 技术正变得越来越成熟。这里有几个算法中立的方法,现在很实用:
SHAP
SHAP 是由华盛顿大学的斯科特·伦德伯格提出的。SHAP 根据博弈论计算沙普利值,假设实例的每个特征值都是游戏中的“玩家”,预测就是支出。那么可以通过计算每个特征对预测的贡献来解释预测。注:SHAP 具有以下可取的特性:
1.局部精度:特征属性的总和等于我们试图解释的模型的输出
2.缺失:已经缺失的功能没有影响
3.一致性:改变一个模型,使一个特性对模型有更大的影响,这永远不会减少分配给那个特性的属性。
SHAP 支持树集成、深度学习和其他模型。它既可以用于全局解释,也可以用于局部解释。请参考斯科特·伦德伯格的 SHAP 论文。
石灰
局部可解释模型不可知解释(LIME)是基于代理模型的概念。当解释黑盒模型时,LIME 用数据的变化测试预测发生了什么,并用加权特征训练局部代理模型。最后,对“黑箱”模型的个别预测可以用局部的、可解释的替代模型来解释。
请参考石灰纸:《我为什么要相信你》
Airbnb 预订率模型
这里使用的模型预测 Airbnb 的预订率。它使用从 insideairbnb.com 获得的洛杉矶地区列表数据进行训练。为了简单起见,我使用一个特征子集来训练 XGBoost 模型。
关于模型设计的更多信息,请参考https://towards data science . com/predicting-market-rank-for-Airbnb-listings-59009 a886d 6
具有全局解释的洞察力
SHAP 摘要显示了主要功能贡献。它还显示数据点分布,并提供特征值如何影响预测的可视化指标。这里红色表示较高的特征值,蓝色表示较低的特征值。在 x 轴上,右边较高的 SHAP 值对应于较高的预测值(列表更可能被预订),左边较低的 SHAP 值对应于较低的预测值(列表不太可能被预订)。
以下是通过全局要素分析获得的一些见解:
谁是最成功的主持人?
使用依赖图,我们可以检查特征值和预测结果之间的关系。在第一张图中,随着主机列表数量的增加,我们看到 SHAP 值呈下降趋势。在第二个图表中,x 轴显示主机列表计数,颜色显示“整个家庭”的列表计数。
我们大概可以得出这些类型的宿主:
- 拥有一个或几个列表的主机-这些是个人和家庭,他们的列表通常是有吸引力的,可能是由于关注和个人护理
- 拥有 15-60 个房源的房东——这些房东拥有最不吸引人的房源,他们可能是出租房间的小旅馆或汽车旅馆?
- 拥有超过 150 个列表的主机—在第二张图中,我们可以看到,随着主机列表的数量增加到 50 个以上,预计预订率将大幅增加(与之前的趋势相反)。进一步说,那些房源几乎都是“整栋住宅”。在最高端,那些拥有超过 100 个“全屋”房源的主机实现了 75%以上的预订率,远远高于其他任何人。那些是专业管理的 Airbnb 物业公司吗?
更高的清洁费还是更高的价格?
如果有选择的话,主人应该收取更多的每夜费用还是清洁费?相关性图显示了价格和清洁费之间的特征相互作用。红色表示较高的清洁费。沿着 x 轴,随着价格的上涨,预计预订率下降,这是意料之中的。此外,我们发现清洁费较高的列表(红点)往往位于清洁费较低的列表(蓝点)之上。
因此,清洁费较高的房源在预测预订率时实际上是有利的。主人将更多的成本转移到清洁费上,可能会通过鼓励客人逗留更长时间,并使首页的标价看起来更便宜而获胜。
评论多还是评论评分高?
在图中,我们看到点评率(x 轴)的上升导致预订率的上升。然而,评论数量的增加并不意味着预订率的提高(红点垂直分布)。一个主持人得到一些好评比有很多平庸的评论要好得多。
本地解释的洞察力
SHAP 力图可以用来解释个人的预测。
例如,我们可以看到基值(偏差项)为 0.01249,红色要素将该值向右推,蓝色要素将该值向左推,组合输出为 0.58。因此,top 特征的影响在具有局部精度的预测上被量化。特定的列表有许多强大的功能价值(超级主机,低价,整个家庭,最近的日历更新),这使得它有利于预订。
下面的列表有一些特色价值(390 美元的高价,最少 30 天的长时间停留,长时间日历没有更新),这使得它不太可能被预订。
LIME 方法也可以用来解释单个预测,它定量地显示了顶部特征的影响(橙色为正,蓝色为负)。
第一个例子显示了一个主要是正面特征值的列表(它是一个超级主机提供的一整个家,有很多评论)。
第二个示例显示了一个具有负特征值的列表(它要求最少入住 30 晚,并收取 150 美元的清洁费)。
模型改进的洞察力
通过检查特性的全局和局部影响,我们通常可以揭示出人意料的数据模式,并获得新的见解。通过进一步分析,我们可能会发现以下原因之一:
- 商业分析的不足
- 数据收集出错
- 数据处理改进(估算和标度)
- 或者说,不寻常的模式是新知识学习的真实反映
下图显示了主要有两种类型的列表具有较高的“日历更新”值(红点)。x 轴最左侧的一组,在过去 12 个月中没有评论,基本上是具有负 SHAP 值的陈旧列表,因此预测预订率低。其他红点分散在上部区域,这表明它们具有更高的 SHAP 值,更有可能被预订。这些列表是持续可用的,并且不需要主机进行多少日历更新。这为特征工程提供了线索,其目标是区分稳定列表和训练数据。
此处显示的另一个示例是溜冰者部分相关性图,它显示了纬度和经度特征的相互作用,纵轴表示它们对预测的影响。视觉上,这个 3D 图可以叠加在洛杉矶地区的地图上,该地图清楚地显示中部和北部地区更受欢迎,南部最不可能被预订。这种洞察力不能通过分析单个特征获得。
进行修正、调整和获取新知识是迭代模型生命周期的一部分,这将导致增量改进。XAI 可以发现隐藏的线索,并为此提供关键证据。
开源代码库
简化版的模型和 XAI 代码可以在这里找到:https://github.com/seanxwang/XAI-airbnb-booking
下一步是什么
Airbnb 房源具有丰富的信息功能,如图像和文本。将这些整合到模型中可以大大提高预测性能。拥有深度学习和远见的 XAI 应该既有挑战性又有回报。
使用 XGBoost 提升性能
在这篇博客中,我们将借助一个例子来看看 XGBoost 是如何工作的,以及 XGBoost 的一些重要特性。
来源:正面消息
所以,我们很多人都听说过树模型和助推技术。让我们将这些概念放在一起,讨论 XGBoost,这是目前最强大的机器学习算法。
XGboost 呼吁极端梯度助推树木。
【XGBoost 这个名字实际上是指提升树算法的计算资源极限的工程目标。这也是很多人使用 XGBoost 的原因。
自 2014 年推出以来,XGBoost 具有很高的预测能力,比其他梯度增强技术快近 10 倍。它还包括各种正则化,减少过度拟合,提高整体性能。因此也被称为“正则化增强技术。XGBoost 在性能和速度方面证明了自己的实力。
好吧!!!别急,我们来说说助推
什么是助推树?
我们遇到过许多基于树的算法,如决策树,在这些算法中,我们用来在特定数据集上训练我们的单一模型,可能需要一些参数调整。同样在集合模型中,我们习惯于单独训练所有的模型。
Boosting 也是一种集成技术,它将许多模型结合起来给出最终的模型,但不是单独评估所有模型,而是依次训练模型。这意味着,每一个新模型都被训练来纠正前一个模型的错误,当没有进一步的改进时,该序列被停止。这就是为什么它更准确。
安装 XGBoost
在 XGBoost 文档网站上有全面的安装指南。
它涵盖了 Linux、Mac OS X 和 Windows 的安装。
它还涵盖了在 R 和 Python 等平台上的安装。
设置我们的数据
所以,第一件事就是为我们的模型准备数据。我们将使用来自 Scikit Learn 的 iris flower 数据集。
这里,我们用 python 从 Sklearn 加载了数据集,还导入了 XGBoost 库
from sklearn import datasets
import xgboost as xgbiris = datasets.load_iris()
X = iris.data
y = iris.target
接下来,我们必须将数据集分成两部分:训练和测试数据。这是检验我们的模型表现如何的重要一步。因此,我们将把数据分成 80%-20%的部分。
from sklearn.model_selection import train_test_splitX_train, X_test, Y_train, Y_test = train_test_split(X, y, test_size=0.2)
与其他算法不同,XGBoost 需要将我们的数据转换成特定的格式,即 DMatrix。
DMatrix 是由 XGBoost 使用的内部数据结构,针对内存效率和训练速度进行了优化。
D_train = xgb.DMatrix(X_train, label=Y_train)
D_test = xgb.DMatrix(X_test, label=Y_test)
现在,我们将 NumPy 数组数据转换成 DMatix 格式,以提供给我们的模型。但在此之前,我们需要定义我们的模型。
定义 XGBoost 模型
我们要做的第一件事是定义梯度下降系综的参数。我们有 N 个参数可用于我们的模型,但现在,我们将把重点放在一些重要的。可能参数的完整列表可在官方 XGBoost 网站上获得。
param = {
'eta': 0.2,
'max_depth': 4,
'objective': 'multi:softprob',
'num_class': 4
}epochs = 20
这是我们的参数:
- max_depth :被训练决策树的最大深度
- 目标:使用损失函数
- num_class :数据集中类的数量
- eta :学习率
正如我们已经知道的,这种模型是按顺序工作的,这使得它更加复杂。这种技术很容易过度拟合。
eta 参数/学习率帮助我们的算法防止过度拟合,这不仅是通过将新树的预测添加到具有全权重的集合中,而且 eta 将乘以正在添加的残差以减少它们的权重。
注:建议在 0.1 到 0.3 的范围内使用较小的 eta 值
我们现在已经定义了模型,让我们来训练它
培训和测试
model = xgb.train(param, D_train, steps)
这是一个与 Scikit Learn 非常相似的过程,运行评估也非常熟悉。
import numpy as np
from sklearn.metrics import precision_score, recall_score, accuracy_scorepreds = model.predict(D_test)
best_preds = np.asarray([np.argmax(line) for line in preds])print("Precision = {}".format(precision_score(Y_test, best_preds, average='macro')))
print("Recall = {}".format(recall_score(Y_test, best_preds, average='macro')))
print("Accuracy = {}".format(accuracy_score(Y_test, best_preds)))
输出:
太棒了,我们达到了 90%以上的准确率
如上所述,我们有很多参数,选择错误的参数,可能会影响你的模型性能很多。
所以这里的问题是:如何选择合适的参数?
嗯,用不同的值来比较模型性能太容易了。让我们看看
寻找最佳参数
设置任何 ML 模型的最佳超参数都是一项挑战。那么为什么不让 Scikit Learn 帮你做呢?我们可以很容易地将 Scikit Learn 的网格搜索与 XGBoost 分类器结合起来:
from sklearn.model_selection import GridSearchCVclf = xgb.XGBClassifier()
parameters = {
"eta" : [0.05, 0.10, 0.15, 0.20, 0.25, 0.30 ] ,
"max_depth" : [ 3, 4, 5, 6, 8, 10, 12, 15],
"min_child_weight" : [ 1, 3, 5, 7 ],
"gamma" : [ 0.0, 0.1, 0.2 , 0.3, 0.4 ],
"colsample_bytree" : [ 0.3, 0.4, 0.5 , 0.7 ]
}grid = GridSearchCV(clf,
parameters, n_jobs=4,
scoring="neg_log_loss",
cv=3)grid.fit(X_train, Y_train)
输出:
如果你有时间的话,只在大数据集上这样做——进行网格搜索本质上是多次训练决策树的集合!
一旦您的 XGBoost 模型经过训练,您就可以将它的可读描述转储到一个文本文件中:
model.dump_model('dump.raw.txt')
这就是我们如何创建 XGBoost 模型,并为其选择理想的超参数。
保持曲调,快乐学习
最初发布于:https://blog . knol dus . com/machinex-boosting-performance-with-xgboost/
在 LinkedIn 和 Twitter 上关注我,了解更多信息:
用 Cython 提升 Python 脚本(应用于 Raspberry Pi)
使用 Cython 将 Python 代码加速数千倍
比尔·杰伦:【https://unsplash.com/photos/NVWyN8GamCk】T2
Python 可能是当今最流行的编程语言之一,但它肯定不是最高效的。特别是在机器学习领域,从业者为了 Python 提供的易用性牺牲了效率。
这并不意味着你不能用其他方法加快速度。Cython 是一种显著减少 Python 脚本计算时间的简单方法,而不会牺牲使用 Python 轻松实现的功能。
本教程将向您介绍如何使用 Cython 来加速 Python 脚本。我们将看到一个简单但计算量很大的任务:为循环创建一个*,该循环遍历一个包含 10 亿个数字的 Python 列表,并对它们求和。由于在资源有限的设备上运行代码时,时间尤其重要,我们将通过考虑如何在 Raspberry Pi (RPi)上的 Cython 中实现 Python 代码来考虑这个问题。Cython 显著提高了计算速度。把它想象成树懒和猎豹的比较。*
今日印度的树懒图片| pix abay 的猎豹图片
本文原载于 Paperspace 博客 。你可以在渐变 上免费运行我的教程的代码 。
本教程涵盖的部分如下:
- Python、CPython 和 Cython
- 简化 Python 代码
- 为回路鸣音一个
- 将 C 数据类型赋给变量
- Cython 在树莓派中的应用
让我们开始吧。
Python 和 CPython
许多人没有意识到这样一个事实,即像 Python 这样的语言实际上是用其他语言实现的。比如 Python 的 C 实现叫做 CPython 。注意不是 Cython 。关于 Python 不同实现的更多信息,你可以阅读这篇文章。
Python 的默认和最流行的实现是 CPython。使用它有一个重要的优点。c 是一种编译语言,它的代码被转换成机器代码,由中央处理器(CPU)直接执行。现在你可能会想,如果 C 是一种编译语言,那是不是意味着 Python 也是?
C (CPython)中的 Python 实现不是 100%编译的,也不是 100%解释的。在运行 Python 脚本的过程中,既有编译也有解释。为了说明这一点,让我们来看看运行 Python 脚本的步骤:
- 使用 CPython 编译源代码以生成字节码
- 在 CPython 解释器中解释字节码
- 在 CPython 虚拟机中运行 CPython 解释器的输出
当 CPython 编译源代码(.py 文件)来生成 CPython 字节码(.pyc 文件)。CPython 字节码(。pyc 文件)然后使用 CPython 解释器进行解释,输出在 CPython 虚拟机上运行。根据上面的步骤,运行 Python 脚本的过程包括编译和解释。
CPython 编译器只生成一次字节码,但是每次代码运行时都会调用解释器。通常字节码的解释要花很多时间。如果使用解释器会降低执行速度,为什么还要使用它呢?最大的原因是它有助于 Python 跨平台。因为字节码运行在 CPU 之上的 CPython 虚拟机中,所以它独立于运行它的机器。因此,字节码可以在不同的机器上运行而不发生变化。
如果没有使用解释器,那么 CPython 编译器将生成直接在 CPU 中运行的机器码。因为不同的平台有不同的指令,所以代码不会跨平台。
总之,使用编译器加快了这个过程,但是解释器使代码跨平台。所以,Python 比 C 慢的一个原因是使用了解释器。记住编译器只运行一次,但是每次代码执行时解释器都会运行。
Python 比 C 慢得多,但许多程序员仍然喜欢它,因为它更容易使用。Python 对程序员隐藏了许多细节,这有助于防止令人沮丧的调试。例如,因为 Python 是一种动态类型语言,所以您不必在代码中显式指定每个变量的类型——Python 会自动推导出它的类型。相反,对于静态类型的语言(如 C、C++或 Java ),您必须指定变量的类型,如下所示。
*int x = 10
string s = "Hello"*
将它与下面的 Python 实现进行比较。动态类型化使编码更容易,但是增加了机器寻找合适的数据类型的负担。这使得该过程更慢。
*x = 10
s = "Hello"*
一般来说,像 Python 这样的“高级”语言对开发者来说更容易使用。然而,当代码运行时,它需要被转换成低级指令。这种转换需要更多的时间,这是为了易于使用而牺牲的。
如果时间是一个重要的因素,那么你需要使用低级指令。因此,您可以使用 CPython 编写代码,而不是使用 Python(这是一种接口)来键入代码,CPython 是用 C 实现的 Python 的后端。但是,如果您这样做,您会觉得您是在用 C 而不是 Python 编程。
CPython 要复杂得多。在 CPython 中,一切都是用 C 实现的。在编码中没有办法逃避 C 的复杂性。这就是为什么许多开发者选择 Cython 而不是 T1 的原因。但是 Cython 和 CPython 有什么不同呢?
Cython 与众不同
根据 Cython 文档,Cython 是 C 数据类型的 Python。来自 Cython tutorial 2009 论文的另一个定义阐明:
Cython 是一种基于 Python 的编程语言,具有额外的语法来提供静态类型声明。这充分利用了 Python 的优势,同时允许用户达到 c 语言的速度
根据上面的定义,Cython 是一种让你拥有两个世界的最好的语言——速度和易用性。您仍然可以用 Python 编写常规代码,但是为了在运行时加快速度,Cython 允许您用 c 语言替换 Python 代码的某些部分。因此,您最终会将两种语言混合在一个文件中。请注意,您可以想象 Python 中的一切在 Cython 中都是有效的,但有一些限制。有关限制的更多信息,您可以访问本页。
常规 Python 文件的扩展名为. py,但 Cython 文件的扩展名为。改为 pyx 扩展名。相同的 Python 代码可以编写在。pyx 文件,但是这些文件也允许您使用 Cython 代码。请注意,与直接运行 Python 代码相比,仅将 Python 代码放入. pyx 文件中可能会加快速度,但不如声明变量类型时快。因此,本教程的重点不仅仅是在。pyx 文件,但也进行编辑,这将使它运行得更快。通过这样做,我们给编程增加了一点难度,但是这样做节省了很多时间。如果你有 C 语言编程的经验,那么对你来说会更容易。
简化 Python 代码
要将 Python 转换成 Cython,首先需要用创建一个文件。pyx 分机而不是*。py** 分机。在这个文件中,你可以从编写常规的 Python 代码开始(注意,Cython 接受的 Python 代码有一些限制,在 Cython 文档中已经阐明)。*
在继续之前,请确保安装了 Cython。您可以使用以下命令来完成此操作。
*pip install cython*
来生成。pyd/。所以我们需要首先构建 Cython 文件。的。pyd/。所以 file 表示稍后要导入的模块。为了构建 Cython 文件,将使用 setup.py 文件。创建这个文件,并将下面的代码放入其中。我们将使用 distutils.core.setup()函数来调用 Cython。Build.cythonize()函数,该函数将。pyx 文件。该函数接受您想要 cythonize 的文件的路径。这里我假设 setup.py 文件与 test_cython.pyx 文件放在同一个位置。
*import distutils.core
import Cython.Build distutils.core.setup(ext_modules = Cython.Build.cythonize("test_cython.pyx"))*
为了构建 Cython 文件,在命令提示符下发出下面的命令。命令提示符的当前目录应该与 setup.py 文件的目录相同。
*python setup.py build_ext --inplace*
该命令完成后,两个文件将被放在。pyx 文件。第一个有。c 扩展名,而另一个文件将具有该扩展名。pyd(或类似的,基于使用的操作系统)。为了使用生成的文件,只需导入 test_cython 模块,就会直接出现“Hello Cython”消息,如下所示。
我们现在已经成功地将 Python 代码细胞化了。下一节将讨论如何创建一个. pyx 文件,并在其中创建循环。
将“for”循环变成 Cythonizing
现在让我们优化我们前面提到的任务:一个 for 循环,它遍历 100 万个数字并将它们相加。让我们从查看循环迭代的效率开始。导入时间模块是为了估计执行需要多长时间。
*import timecdef unsigned long long int maxval
cdef unsigned long long int total
cdef int k
cdef double t1, t2, tmaxval = 1000000000
t1=time.time()for k in range(maxval):
total = total + k
print "Total =", totalt2=time.time()
t = t2-t1
print("%.10f" % t)*
在. pyx 文件中,3 次运行的平均时间是 0.0281 秒。代码运行在配备酷睿 i7–6500 u CPU @ 2.5 GHz 和 16 GB DDR3 RAM 的机器上。
将它与运行一个普通 Python 文件所需的时间进行比较,后者的平均值为 0.0411 秒。这意味着仅在迭代方面,Cython 就比 Python 快 1.46 倍,尽管我们不需要修改循环的来让它以 C 速度执行。**
现在让我们添加求和任务。为此,我们将使用 range()函数。
*import time
t1 = time.time()total = 0
for k in range(1000000):
total = total + k
print "Total =", totalt2 = time.time()
t = t2-t1
print("%.100f" % t)*
请注意,这两个脚本返回相同的值,即 499999500000。在 Python 中,平均运行时间为 0.1183 秒(三次试验之间)。在 Cython 中,它的速度快了 1.35 倍,平均为 0.0875 秒。
让我们看另一个例子,循环从 0 开始遍历 10 亿个数字。
*import time
t1 = time.time()total = 0
for k in range(1000000000):
total = total + k
print "Total =", totalt2 = time.time()
t = t2-t1
print("%.20f" % t)*
Cython 脚本完成了将近 85 秒(1.4 分钟),而 Python 脚本完成了将近 115 秒(1.9 分钟)。在这两种情况下,时间都太长了。如果在如此琐碎的任务上持续超过一分钟,那么使用 Cython 的好处是什么?注意这是我们的错,不是 Cython 的。
如前所述,在 Cython 中编写 Python 代码。pyx 脚本是一个改进,但是它并没有大幅减少执行时间。我们必须在 Cython 脚本中编辑 Python 代码。首先要关注的是明确定义所用变量的数据类型。
将 C 数据类型赋给变量
根据前面的代码,使用了 5 个变量: total,k,t1,t2 ,T5t。所有这些变量的数据类型都是由代码隐式推导出来的,因此需要更多的时间。为了节省推断它们的数据类型的时间,让我们从 C 语言中指定它们的数据类型。**
total 变量的类型是无符号 long long int* 。它是一个整数,因为所有数字的总和是一个整数,它是无符号的,因为总和将是正数。但是为什么是长长呢?因为所有数字的和非常大,所以添加 long long 以将变量大小增加到最大可能大小。*
为变量 k 定义的类型为 int ,为剩余的三个变量 t1 、 t2 和 t 分配了 double 类型。
*import timecdef unsigned long long int total
cdef int k
cdef double t1, t2, tt1 = time.time()for k in range(1000000000):
total = total + k
print "Total =", totalt2 = time.time()
t = t2-t1
print("%.20f" % t)*
Python 需要超过 1.9 分钟,而 Cython 只需要 0.00009346 秒。
既然我们已经看到了如何通过使用 Cython 来提高 Python 脚本的性能,那么让我们将其应用到 Raspberry Pi (RPi)中。
从 PC 访问 Raspberry Pi
如果这是你第一次使用你的 Raspberry Pi,那么你的 PC 和 RPi 都需要通过网络连接。为此,您可以将它们连接到一台交换机,在该交换机中,DHCP(动态主机配置协议)处于活动状态,以便自动为它们分配 IP 地址。成功创建网络后,您可以根据分配给它的 IPv4 地址访问 RPi。您如何知道分配给您的 RPi 的 IPv4 地址是什么?别担心,你可以简单地使用一个 IP 扫描工具。在本教程中,我将使用一个名为高级 IP 扫描器的免费应用程序。
应用程序的界面如下所示。它接受要搜索的 IPv4 地址范围,并返回活动设备的信息。
您需要输入本地网络中的 IPv4 地址范围。如果您不知道范围,只需在 Windows 中发出 ipconfig 命令(或在 Linux 中发出 ifconfig)即可知道您的 PC IPv4 地址(如下图所示)。在我的例子中,分配给我的 PC 的 Wi-Fi 适配器的 IPv4 地址是 192.168.43.177,子网掩码是 255.255.255.0。这意味着网络中的 IPv4 地址范围是从 192.168.43.1 到 192.168.43.255。如图所示,IPv4 地址 192.168.43.1 被分配给网关。请注意,范围内的最后一个 IPv4 地址 192.168.43.255 是为广播消息保留的。因此,搜索范围应该从 192.168.43.2 开始,到 192.168.43.254 结束。
根据下图所示的扫描结果,分配给 RPi 的 IPv4 地址是 192.168.43.63。此 IPv4 地址可用于创建安全外壳(SSH)会话。
为了建立 SSH 会话,我将使用一个名为的免费软件。应用程序的界面如下。
为了创建一个 SSH 会话,只需点击左上角的会话按钮。将出现一个新窗口,如下所示。
在该窗口中,单击左上角的 SSH 按钮,打开如下所示的窗口。只需输入 RPi 的 IPv4 地址和用户名(默认为 Pi),然后单击 OK 启动会话。
单击 OK 按钮后,会出现一个新窗口,要求输入密码。默认密码是 raspberrypi。登录后,将出现下一个窗口。左侧的窗格有助于轻松导航 RPi 的目录。还有一个用于输入命令的命令行。
将 Cython 与树莓 Pi 一起使用
创建一个新文件,并将其扩展名设置为。pyx 来编写最后一个例子的代码。左侧窗格的栏中有用于创建新文件和目录的选项。您可以使用“新建文件”图标使事情变得更加简单,如下图所示。我在 RPi 的根目录下创建了一个名为 test_cython.pyx 的文件。
只需双击文件打开它,粘贴代码,并保存它。之后,我们可以创建 setup.py 文件,这与我们之前讨论的完全相同。接下来,我们必须发出以下命令来构建 Cython 脚本。
*python3 setup.py build_ext --inplace*
该命令成功完成后,您可以根据下图找到左侧窗格中列出的输出文件。注意,要导入的模块的扩展现在是。因此,由于我们不再使用 Windows。
现在让我们激活 Python 并导入模块,如下所示并运行 Cython 代码。
本文原载于 Paperspace 博客 。你可以在渐变 上免费运行我的教程的代码 。
结论
本教程讨论了如何使用 Cython 来减少执行 Python 脚本的计算时间。我们看了使用一个 for 循环对一个包含 10 亿个数字的 Python 列表中的所有元素求和的例子,并比较了声明变量类型和不声明变量类型的执行时间。虽然这在纯 Python 中运行需要将近两分钟,但使用 Cython 声明的静态变量运行基本上不需要时间。
在下一篇教程中,我们将用 NumPy 数组替换这个 Python 列表,并看看如何使用 Cython 优化 NumPy 数组处理。然后,我们将看看如何将更高级的 Python 脚本(如遗传算法)进行 cythonize。这是轻松提高机器学习项目效率的好方法。
通过客户细分分析促进销售:更好地了解市场
应用客户细分来洞察营销活动
作者图片
客户细分是一个基于某些特征(年龄、性别、收入等)将公司的客户分成不同群体的过程。),而有效的分析可以帮助一个公司做出更好的营销决策。在这篇文章中,我将分享一个基于 Arvato 公司提供的数据的客户细分分析。Arvato 是一家供应链解决方案公司,我用于分析的数据集包含一家客户公司的客户人口统计数据。我还建立了一个模型来预测邮寄广告的回复率。
下面,我将向您详细介绍我使用无监督和有监督学习方法进行的分析。我们分析了两个数据集,即来自 Arvato 客户公司的客户数据和来自德国的一般人口统计数据,以回答以下问题:
1.谁是客户公司的忠实客户,随着营销策略的改变以扩大客户群体,谁是潜在的目标客户?
2.当客户公司发出邮件报价时,我们能预测回复率吗?
第一部分.客户细分
谁是客户公司的忠实客户,随着营销策略的改变以扩大客户群体,谁是目标潜在客户?
聚类分割有助于将客户公司现有客户的人口统计数据映射到德国的一般人群。在这里,我应用无监督学习来识别普通人群中的哪个部分代表客户公司的忠实客户,哪个部分代表他们可能瞄准的潜在新客户群。
数据探索
数据科学家花 80%的时间清理数据。
在这个项目过程中,我 90%的时间都花在了数据探索和预处理上。我在客户细分中使用的以下数据集包含大量原始数据:
- Azdias —德国普通人口的人口统计数据(891211 x 366)。
- 客户 —客户公司的人口统计数据(191652 x 369)。
在总体数据中,有 273 列包含缺失值。我决定删除缺失值率超过 30%的列(用红色表示),因为大量的缺失值对于分析统计数据和构建模型是有害的(例如 ALTER_KIND1 和 EXTSEL992)。对于剩余的列(蓝色),我会用最频繁的值来估算缺失的数据。
有 890919 行包含缺失值。通过检查缺失率的分布,大多数行的缺失值少于 10%,因此,我将删除阈值设为 50%。
数据预处理
数据预处理包括以下六个步骤:
- 重新编码缺失值:我手工创建了特征描述文件 feature_summary.csv,包含属性名、特征类型、缺失值或未知值。根据功能描述文件,许多功能中的缺失值由–1 和 0 值表示(例如,在功能“AGER_TYP”中)。在这里,我根据特性描述文件将每个属性中所有缺失的值重新编码到 NaN 中(见下文)。
- **丢弃缺失值:**注意缺失值重新编码后,各列缺失率的分布向百分比较高的区域偏移。丢失值超过 30%的所有列和丢失值超过 50%的所有行都从两个数据库中删除。
- **丢弃高度相关的特征:**计算每个特征的皮尔逊相关系数。相关性可以是正的,也可以是负的,因此,我存储了相关性的绝对值。特征被阈值> 0.95 去除,比如 KBA13_BAUMAX,KBA13_FAB_SONSTIGE,LP_FAMILIE_GROB。
# Calculate Pearson's correlation matrix
corr_df = azdias_drop_missing.corr().abs()# Create and apply mask
mask = np.triu(np.ones_like(corr_df,dtype=bool))
tri_df = corr_df.mask(mask)# Find the features that meet threshold
to_drop = [c for c in tri_df.columns if any(tri_df[c] > 0.95)]
- **一次性编码分类特征:**根据特征描述文件识别多级分类特征,每个分类特征都被一次性编码为虚拟变量。
- 平移变换混合型变量: 一些特征包含多个属性,被拆分成新的独立特征。例如,“CAMEO_INTL_2015”被拆分为“财富”和“人生阶段”属性。
- **估算和缩放数据:**用模式方法估算剩余缺失值,用 StandardScaler 缩放数据。
imputer = SimpleImputer(strategy='most_frequent')
scaler = StandardScaler()
经过数据预处理后, Azdias 数据库的矩阵为 791244 x 395,客户数据库的矩阵为 140866 x 395。
主成分分析
具有多个特征会使数据分析的过程变得复杂,并且有必要在聚类分割之前降低数据的维度。在这个项目中,我进行了主成分分析(PCA ),将原始数据分解成几个不相关的主成分,仅保留 395 个成分中的 200 个,这解释了原始数据集约 88%的累积可变性。
n_components=200
pca = PCA(n_components=n_components,random_state=42)
azdias_pca = pca.fit_transform(azdias_scaled)
聚类和特征分解
我应用了 k -means 算法来将数据集分组到各个集群中,并使用了肘方法来找到正确数量的集群。肘方法的思想是运行k——意思是在数据集上对范围 k 进行聚类,并对 k 的每个值计算误差平方和(即k——意思是得分)。在 k 值和k-均值得分的图中,曲线上的“肘”是数据集的最佳聚类数。基于下面的肘方法结果,我使用 k 均值算法将数据集分成八个聚类。
# Number of different cluster counts
n_clusters = np.arange(2,21)# Run k-means clustering on the data and compute the average within-cluster distances.
scores = [MiniBatchKMeans(i).fit(azdias_pca).score(azdias_pca) for i in n_clusters]
将客户数据映射到人口统计聚类后,现在我们能够比较普通人群和客户公司的客户群之间的聚类分布。结果表明,集群 7 是该公司的主要客户群,因为它在其他客户中拥有最高的客户比例。这个集群可以被认为是“忠诚的客户”相比之下,聚类 2 显示出最低的客户百分比,并展示出一般人群和客户比例之间的最高负差。这表明,考虑到当前的营销策略,集群 2 中的一小部分人可能会成为客户公司的客户。对于客户公司来说,这里的机会是,针对集群 2 的人口定制营销策略将有可能吸引新的客户群。
聚类信息的分解揭示了什么类型的个体构成聚类 2 和聚类 7。首先确定哪些主成分对聚类更有意义,然后评估哪些特征可以解释特定主成分中的更多方差,同时通过逆 PCA 变换和数据缩放收集原始特征值。总之,我能够找出哪些类型的个人属于第 2 类和第 7 类。
忠诚客户:集群 7(中产阶级)
下面,我列出了十个最正相关的特征(红色),以及十个最负相关的特征(蓝色)。
客户公司的忠实客户大多年龄在 46-60 岁之间,属于中产阶级,有小规模的家庭。这些客户生活稳定,对金融投资兴趣不大,热衷于网上购物。
聚类 7 正相关特征
聚类 7 负相关特征
潜在客户:集群 2(富裕的上层阶级)
“车,车,车!”当我们看集群 2 的主要特征时,我们看到的都是豪华车。第二组中的人是昂贵的德国汽车的爱好者,除此之外,他们中的大多数人的祖先追溯到旧时代的西德。
聚类 2 正相关特征
聚类 2 负相关特征
外卖:家庭小、网购习惯活泼的中产个人,是客户公司的核心客户。如果客户公司想要扩大他们的客户群体,对德国豪华车感兴趣的来自西德的上流社会人士是潜在的营销目标。
第二部分。监督学习
当客户公司发出邮件报价时,我们能预测回复率吗?
这是一个典型的分类问题,建立一个有监督的机器学习模型是一个很好的解决方法。这部分的主要焦点是使用训练数据集来训练模型,并使用训练的模型来预测“响应”属性,即,确定测试数据集中的个体是否会响应邮寄要约。
数据探索
Arvato 提供的培训数据和测试数据包括以下内容:
- Mailout_train —作为营销活动目标的个人的人口统计数据(42 982 x 367)。
- Mailout_test —作为营销活动目标的个人的人口统计数据(42 833 x 366)。
如下图响应分布图所示,目标属性“response”在 Mailout_train 数据集中高度不平衡,有 42430 个否定响应,只有 532 个肯定响应,响应率仅为 1.2%。这种高度的不平衡会影响分类模型的训练,也会使常用的度量标准变得具有误导性(如准确性)。
数据预处理
第一部分的数据预处理过程已经实现为 clean 函数,可以在我的 GitHub 中找到。这里,我只是复制了相同的步骤来预处理 Mailout_train 和 Mailout_test 中的数据。
实施和细化
由于“回应”中的数据高度不平衡,这里我采用的方法是计算个人对要约做出回应的概率,并分析做出回应的个人的集体特征,并使用这些信息来建议具有高回应概率的个人。ROC 曲线下的计算面积(假阳性率对真阳性率)用于评估机器学习模型的性能。
我考虑了以下五种分类算法:
- AB: AdaBoostClassifier
- GB:GradientBoostingClassifier
- LR:物流回收
- RF:RandomForestClassifier
- XGB: XGBClassifier
为了评估这五种算法的性能,我创建了一个函数,当指定算法和参数时,它可以计算 ROC 得分。
def grid_search(estimator, param_grid, X=X, y=y):
"""
Grid search a classifier by ROC score, using cross- validation.
INPUT:
- estimator (classifier): name of classifier
- param_grid (dict): parameters used with GridSearchCV
- X (DataFrame): features from cleaned mailout_train dataframe
- y (DataFrame): 'RESPONSE' from cleaned mailout_train dataframe
OUTPUT:
- classifier: fitted classifier
- prints elapsed time and ROX AUC
"""
grid = GridSearchCV(estimator=estimator, param_grid=param_grid, scoring='roc_auc', cv=5)
grid.fit(X, y)
best_estimator = grid.best_estimator_
best_score = grid.best_score_
return best_estimator, best_score
由于高度不平衡的响应属性,我通过 5 重交叉验证将 Mailout_train 数据集分成训练集和验证集,然后用默认超参数将数据拟合到五个算法中。
# Choose five classifiers, LR, RF, AB, XGB, and GB
models = []
models.append(('LR', LogisticRegression()))
models.append(('RF', RandomForestClassifier()))
models.append(('AB', AdaBoostClassifier()))
models.append(('XGB', XGBClassifier()))
models.append(('GB', GradientBoostingClassifier()))# Evaluate ROC AUC score of five classifiers with default parameter
for i in range(len(models)):
score = grid_search(models[i][1], {})[1]
print('ROC AUC score for {}: {}'.format(models[i][0], score))
AdaBoostClassifier (AB)和 GradientBoostClassifier (GB)是表现最好的模型,ROC AUC 得分分别为 0.7172 和 0.7564。从这一点开始,我使用网格搜索来调整 AB 和 GB 模型的超参数,将它们的 ROC AUC 分数分别增加到 0.7531 和 0.7570(见下面的红色柱)。
# Tune the hyperparameters of AB model
param_AB = {
"learning_rate" : [0.1,0.2],
"n_estimators" : [100,200,500]}
AB_tuned = grid_search(AdaBoostClassifier(), param_AB)# Tune the hyperparameters of GB model
param_GB = {
"learning_rate" : [0.1,0.2],
"max_depth" : [3,4],
"n_estimators" : [100,200],
"min_samples_split" : [2,4]}
GB_tuned = grid_search(GradientBoostingClassifier(), param_GB)
然后,我研究了 AB 和 GB 模型的特征,看它们是否验证了我在第二部分的客户细分分析中得出的结论。不幸的是,两种型号中唯一突出的功能是“D19_SOZIALES”,该功能不包含描述,并且在第二部分中没有被确定为忠诚客户的相关功能。对“D19_SOZIALES”特征含义的大胆猜测是,它可能与交易历史有关,因此暗示着社会经济地位。
Kaggle 比赛
AB 和 GB 模型被用于预测 Mailout_test 数据集中的“响应”。AB 机型取得了 0.781 的成绩,GB 机型取得了 0.777 的成绩。这些结果被提交给了 Kaggle。
要点:建立机器学习模型是解决分类问题的最有效方法。我使用 AB 和 GB 算法构建了两个模型,两个模型都能够预测邮寄要约的回复率,得分约为 0.78。
结论
有人说 80–85%的数据科学项目在完成前失败,我感到幸运的是这个项目属于 15–20%。在这个项目中,我练习并应用了不同类型的数据科学技能来解决一个现实生活中的问题——找到忠诚和潜在新客户的特征,并预测个人是否会对邮件发送活动做出回应。
有改进的余地。主成分分析(PCA)受要素比例差异的影响很大,在这方面,使用 MinMaxScaler 等替代方法缩放数据可能会获得更好的性能。在监督学习部分,合成少数过采样技术(SMOTE)可能是解决不平衡分类问题的更好选择,因为这种方法允许人工合成数据以获得更平衡的数据集。
资信证明
本文使用的所有代码都可以在我的 GitHub 和 Tableau 上找到。
数据和资源由 Udacity 和 Bertelsmann&Arvato 提供。
助推对决:情感分类中的 Scikit-Learn vs XGBoost vs light GBM vs CatBoost
哪一个梯度增强库将在这场竞争中独占鳌头?
梯度推进是近年来最流行的机器学习技术之一,统治了许多具有异构表格数据的 Kaggle 竞赛。类似于随机森林(如果你不熟悉这种集成算法,我建议你仔细阅读),梯度提升通过集成许多决策树来执行回归或分类。但是,与随机森林不同,梯度增强按顺序生长树,根据前一棵树的残差迭代生长树。这样做可以让梯度推进专注于特别棘手的观察,并产生一个异常强大的树木集合。
这是一种过于简单化的做法,并没有提到现有的各种 boosting 实现,但这并不是本文的目的。如果你有兴趣阅读更多关于 boosting 如何工作的细节,我在文章底部附上了一些有用的资源。
随着 XGBoost、LightGBM 和 CatBoost 等竞争算法争夺用户,梯度提升空间近年来变得有些拥挤。刚刚提到的三个是 Kaggle 比赛中最常见的,因为它们的速度、功率和 GPU 兼容性。有几篇文章已经在异构数据上比较了这些增强变体,例如:
- CatBoost vs Light GBM vs XGBoost:
[## CatBoost 与轻型 GBM 和 XGBoost
谁将赢得这场预测战争,代价是什么?我们来探索一下。
towardsdatascience.com](/catboost-vs-light-gbm-vs-xgboost-5f93620723db)
- XGBOOST vs LightGBM:哪种算法赢得了比赛!!!
[## LightGBM vs XGBOOST:哪种算法赢得了比赛!!!
这篇文章是关于在人口普查收入数据集上对 LightGBM 和 XGBoost 进行基准测试。我注意到了…的执行时间
towardsdatascience.com](/lightgbm-vs-xgboost-which-algorithm-win-the-race-1ff7dd4917d)
然而,还没有任何分析比较这些竞争对手在其他设置,如文本分类。这有一个很好的理由,因为梯度推进并不被认为是最适合这类问题的算法,但看看这种比较如何进行仍然很有趣!
关于数据
我们将分析斯坦福大学提供的大型电影评论数据集(链接如下),其中包含 50,000 篇与“正面”或“负面”标签相关联的电影评论。这些数据已经被分成训练集和测试集,每一个都有 25,000 条评论。我们的标签也非常平衡,共有 25,000 个正面和 25,000 个负面评论。我们应该承认这是多么干净,因为在文本分类中,我们很少有这种级别的分类平衡!
准备我们的数据
由于我们在这里强调的是比较梯度增强方法,因此我们将对文本数据执行简单的预处理,只需将其强制转换到数据框中,执行 tfi df-矢量化,这是一种将可变长度文本转换为单词包表示的常用方法,该单词包表示表示所述文本中转换后的词频。如果你不熟悉这项技术,我再次在文章底部放了一个链接,因为这是 NLP 领域的必读内容。我们将限制预处理数据帧中的单词数量,以使用 TFIDF 频率方面的 2000 个顶级单词。
我们还将把我们的训练集分割成一个训练集和一个验证集,这样我们就可以对一些没有在内部执行这种分割的功能的 boosting 候选项执行早期停止,这是一种正则化技术。
# Importing packages and data
from time import time
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.experimental import enable_hist_gradient_boosting
from sklearn.ensemble import (RandomForestClassifier,
AdaBoostClassifier,
GradientBoostingClassifier,
HistGradientBoostingClassifier)
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
from catboost import CatBoostClassifier
import matplotlib.pyplot as pltdf_train = pd.read_csv('train.csv').sample(frac=1.0)
df_test = pd.read_csv('test.csv').sample(frac=1.0)# Preprocessing our data
tfidf = TfidfVectorizer(max_features=2000)
X_train = tfidf.fit_transform(df_train['text']).toarray()
X_test = tfidf.transform(df_test['text']).toarray()
y_train, y_test = df_train['negative'], df_test['negative']
X_train_sub, X_valid, y_train_sub, y_valid = train_test_split(X_train, y_train, test_size=0.1)# Setting up our results dataframe
df_results = pd.DataFrame(columns=['accuracy', 'run_time'])
设置我们的候选模型
我们将分析几个不同的基线模型以及我们的提升方法,每个方法都包含一个简短的总结,然后我们开始对我们的情感分类任务进行全面的比较。请注意,所有的准确性和运行时间将被记录在最终的视觉效果。在本节中,我们仅实例化我们的分类器。
决策图表
作为我们的第一个基线,我们将考虑最简单的情况:单个决策树分类器。我们将使用著名的 CART 算法的 Scikit-Learn 实现来逐级生成分类器,以对情感进行分类。请注意,这里我们可以做很多调整,例如正则化、树修剪和特征采样,但是对于我们的用例,我们将简单地指定速度的最大深度(否则,如果有 2,000 个特征和无限的深度,我们的树将会变得过深、过拟合,并且永远需要训练)。
dt = DecisionTreeClassifier(max_depth=12, random_state=1234)
随机森林
接下来,我们将考虑过去几十年中最有影响力的集成算法之一:随机森林。随机森林通过创建决策树的“森林”来工作,每个决策树都在训练数据的袋装(引导聚合)样本上进行训练。现在,我将继续从表面上概述 RF;如果你感兴趣,在页面底部有资源。随机森林在防止过度适应方面非常出色,并且往往开箱即用。我们将在我们的森林中使用 500 棵树,深度不限,作为比单一决策树更强的性能基准。
但是,请注意,从这一点开始,我们的所有增强算法(除 AdaBoost 之外)都将有一个类似于max_features
的参数,该参数表示如何在每个树或分裂处对特征进行子采样(根据实现方式而不同),我们将该参数设置为 0.06,这意味着我们将在每个间隔对 6%的特征进行子采样。这样做是为了提高速度,减少过度拟合,并确保我们的候选模型之间的公平比较。为了公平比较,我们还将分布式计算限制在 6 个内核上(即使这些算法中的一些可能会随着内核的增加而有所不同)。
rf = RandomForestClassifier(n_estimators=500,
max_features=0.06,
n_jobs=6,
random_state=1234)
adaboost 算法
AdaBoost(T2 的简称)是早在 1997 年推出的首批主要助推技术之一。Adaboost 是梯度提升的一个特例,它使用一系列任何所需的弱学习器(这里通常选择决策树桩)来最小化指数损失。尽管早些年取得了很大成功,但这种算法在竞争环境中并不常见,因为它往往被更现代的提升技术超越。
如果你有兴趣了解 Adaboost 和梯度增强之间的区别,我在本文底部贴了一个链接。
base_estim = DecisionTreeClassifier(max_depth=1, max_features=0.06) ab = AdaBoostClassifier(base_estimator=base_estim,
n_estimators=500,
learning_rate=0.5,
random_state=1234)
梯度增强决策树(Scikit-Learn)
现在我们将进入第一个真正的梯度增强方法:梯度增强树。梯度提升是前述 Adaboost 算法的推广,其中可以使用任何可微分的损失函数。Adaboost 试图使用观察权重来通知训练,而梯度增强试图遵循梯度。在 Scikit-Learn 中,这个类的功能更加丰富;我们可以为正则化指定训练数据的子集化,并选择类似于随机森林的特征子集化百分比。请注意,虽然n_estimators
被设置为 2000,但我们并不期望接近 2000,并且当我们的内部验证错误在 15 次迭代中没有改善时,早期停止将停止生长新的树。我们将遵循相同的早期停止过程,以便所有的增强方法都遵循这一过程。
请注意,大多数迭代算法都有可能提前停止,但我们没有将它与 AdaBoost 一起使用,因为它不包含在 Scikit-Learn 实现中。
gbm = GradientBoostingClassifier(n_estimators=2000,
subsample=0.67,
max_features=0.06,
validation_fraction=0.1,
n_iter_no_change=15,
verbose=0,
random_state=1234)
XGBoost
大多数严肃的 ML 从业者已经很熟悉,或者至少听说过 XGBoost(EXtremeGradientBoosting 的简称)。XGBoost 是一个梯度增强库,在 2014 年赢得 Kaggle Higgs 机器学习挑战赛后声名鹊起。这个库变得流行有几个原因:
- 它在底层树上实现了非常有效的正则化超参数。
- 它被构建为高度可伸缩的,利用分布式计算来处理极大的数据集。
- 它有许多不同的语言版本(如 Python、R、C、C++、Ruby、Julia 等。).
XGBoost 在现代比赛中仍然做得很好,XGBoost 社区在维护软件包和添加新功能方面做得很好。然而,它面临着来自其他 boosting 库(如 LightGBM 和 CatBoost)的竞争。XGBoost 库的一个缺点是,它不像竞争对手那样对分类特性进行任何特殊处理。这是不幸的,因为 boosting 库往往擅长表格数据,而表格数据通常包含离散的特性。然而,在我们的比较中,这无关紧要,因为我们的 TFIDF 表示只包含连续值特征。
还要注意,这里使用了与GradientBoostingClassifier,
相似的参数,但也指定了tree_method='hist’
。这将使用直方图宁滨对连续特征进行分类,减少需要分析的分割数量,这是 LightGBM 首先引入的技术。
xgb = XGBClassifier(n_estimators=2000,
tree_method='hist',
subsample=0.67,
colsample_level=0.06,
verbose=0,
n_jobs=6,
random_state=1234)
LightGBM
在我看来,截至 2020 年 3 月,LightGBM 是梯度推进库的王者。由微软在 2017 年推出的 LightGBM 是一个速度快得离谱的工具包,旨在为高维度的超大数据集建模,通常比 XGBoost 快很多倍(尽管当 XGBoost 添加了自己的宁滨功能后,这一差距缩小了)。LightGBM 通过以下方式实现这一速度:
- 与 XGBoost 类似,是高度分布式的。
- 种植树木时,使用叶子方向而不是水平方向的分裂。
- 使用连续特征的直方图宁滨(第一个这样做的增强算法)来减少分割的数量。
LightGBM 还通过使用一种特殊的最优分割算法,提供了对分类特性的特殊支持。
lgbm = LGBMClassifier(n_estimators=2000,
feature_fraction=0.06,
bagging_fraction=0.67,
bagging_freq=1,
verbose=0,
n_jobs=6,
random_state=1234)
CatBoost
最新的流行梯度增强库 CatBoost(CategoricalBoosting)是由俄罗斯科技公司 Yandex 在 2017 年年中开发的,紧随 LightGBM 之后。不幸的是,我还没有看到 CatBoost 持续优于其竞争对手(尽管它有许多分类功能,但它确实倾向于名列前茅),也没有比得上 LightGBM 的速度,但这肯定会随着未来的更新而改变。然而,CatBoost 适用于分类数据和文本数据,所以在决定为您的用例尝试哪些方法时,请对本文的结果持保留态度。
CatBoost 确实包括现成的文本功能(其他 boosting 库没有这种功能),但我们不会使用这种功能,因为它会改变 CatBoost 训练集的标记化方法,这又会扭曲我们的比较。因此,我们将坚持使用 CatBoost 的 tfi df-矢量化。(更新:本文底部有一个更新,展示了如何使用这个特性,以及它与我们的普通 TFIDF-vectorization 相比如何)
cb = CatBoostClassifier(n_estimators=2000,
colsample_bylevel=0.06,
max_leaves=31,
subsample=0.67,
verbose=0,
thread_count=6,
random_state=1234)
奖励:基于直方图的梯度增强机器(Scikit-Learn)
Scikit-Learn 最近发布了自己的直方图增强版本,名为HistGradientBoostingClassifier
,其操作与 LightGBM 非常相似,速度比精确梯度增强快很多倍。然而,一个很大的警告是,截至 2020 年 3 月,Scikit-Learn 的实现只是实验性的,并且只包括少数超参数和两个损失函数。相对于它的精确对应物,HistGradientBoostingClassifier
的一个改进是它包含了对缺失值的内置支持,以及一些关于如何将缺失观察值分配给叶节点的简单规则。
hgbm = HistGradientBoostingClassifier(max_iter=2000,
validation_fraction=0.1,
n_iter_no_change=15,
verbose=0,
random_state=1234)
比较我们的竞争对手
是时候进行我们的比较了!在开始我们的训练循环之前,我们需要创建几个对象,例如将我们的模型放入一个列表中,并提取类名以便稍后绘制:
models = [dt, rf, ab, gbm, hgbm, xgb, lgbm, cb]
model_names = [i.__class__.__name__ for i in models]
我们还想指定哪些模型需要在.fit()
方法中提前停止。就我个人而言,我更喜欢非 Scikit-Learn 包的约定,其中您将一个离散的验证集传递给 es 的 fit 方法,而不是在内部执行分割(这给了您更多的控制)。
es_models = ['XGBClassifier',
'LGBMClassifier',
'CatBoostClassifier']
最后,是时候训练我们每个候选模特了!我们将为需要在.fit()
方法中传递验证集的模型添加一点逻辑,以便提前停止。在每次运行结束时,我们将在测试集上附加我们的准确度,以及训练每个模型需要多长时间:
for m, n in zip(models, model_names):
start_time = time() if n in es_models:
m.fit(X_train_sub,
y_train_sub,
eval_set = [(X_valid, y_valid)],
early_stopping_rounds=15,
verbose=0)
else:
m.fit(X_train, y_train)
run_time = time() - start_time
accuracy = np.mean(m.predict(X_test) == y_test)
df_results.loc[n] = [accuracy, run_time]
del m
检查结果
现在,我们已经存储了所有的精度和运行时间,我们将把所有的数据打包到一个带有模型名称的数据框中,以便于以后使用。最后,我们将使用 matplotlib 可视化我们模型的测试精度和运行时间:
图 1:比较我们的候选模型之间的测试准确性
图 2:用绝对和相对时间比较我们的候选模型之间的运行时间(秒)
哇!正如我们从上面的图中看到的,LightGBM 似乎是这个用例中的明显赢家,比下一个 boosting 算法快三倍以上,同时在测试准确性方面也是最好的!LightGBM 的实现实际上非常快,它可以比我们单一的深度决策树更快地训练整个树集合!虽然每次运行之间可能会有一些差异,但这是如此之大的差异,以至于我们可以相当肯定地说它是赢家。
另一个问题是,CatBoost 在速度上表现不佳,与较老的库 XGBoost 的速度不太匹配。然而,随着 GPU 支持的启用和一些超参数调整,这种情况可能会改变。同样令人惊讶的是 Scikit-Learn 的HistGradientBoostingClassifier
的性能,它比 XGBoost 和 CatBoost 都快得多,但在测试准确性方面似乎表现得不太好。我预计这个 boosting 类只会继续变得更好(记住它现在是实验性的),因为它甚至没有利用特性子集和其他库中存在的一些其他特性。
不出所料,AdaBoost 和 random forest 在运行时间上都落后了不少,但我对GradientBoostingClassifier
的表现相当失望。这个类并不适合处理非常大的数据,但是如此大的性能差距是很有趣的。
看起来我们已经有了答案,LightGBM 是明显的赢家!
但是……
等等!其他算法呢?
我已经可以听到数据科学家和 ML 爱好者跃跃欲试地跳到评论区:“有更好的词汇袋模型!”,“你应该将这些与其他基线模型如神经网络或 SVM 进行比较!”,或者“在这里助推没有意义!”。
对于那些有这些想法的人,我完全同意你的观点。
我写这篇文章是为了看看 boosting 实现如何在非标准问题上进行比较,以及它们如何扩展到大范围的数据。不过,在我看来,boosting 算法对于这个用例来说并不理想,因为你可以用少得多的计算时间获得同样的性能。因为我们处理的是非常同质的数据,所以我们将我们的结果与一个简单得多的替代方法进行比较,这个替代方法通常用于单词袋的文本分类问题:SVM。特别是,我们将使用 Scikit-Learn 的LinearSVC
类。
我们将在与我们的 boosting 候选数据相同的数据上运行我们的新模型,记录我们的测试准确性和运行时间,并将它们添加到前面的图中:
# Testing LinearSVC
svc = LinearSVC()
start_time = time()
svc.fit(X_train, y_train)
run_time = time() - start_time
preds = svc.predict(X_test)
score = np.mean(preds == y_test)df_results.loc['LinearSVC'] = [score, run_time]
图 3:比较我们的 SVM 与其他模型的测试精度
图 4:比较 SVM 和我们其他车型的训练时间
上面的两个图准确地显示了为什么当处理一个有大量先前文献的问题时,你不应该总是跳到最令人兴奋和最新的算法。支持向量机是一种已经存在了几十年的算法,其性能几乎与我们最好的最先进的 boosting 模型**一样好,而训练速度却快了近十倍!**这正好表明,根据手头的任务定制您选择的车型可能是几小时和几分钟的火车时间之差!
结论
我们查看了各种 boosting 库,以及它们如何在极宽的同质表格数据上进行比较,最终发现 LightGBM 是我们测试的所有库中最快、最准确的。然而,我们也表明,更传统的算法,如 SVM,仍然可以胜过最先进的和前沿的方法!看看当前流行的 boosting 库如何发展会很有趣!
感谢您的阅读!如果你有任何问题或意见,请在下面留下!
更新# 1—2020 年 4 月 28 日
CatBoost 团队最近发布了一个新版本 0.23,它将内部文本矢量化功能扩展到了 CPU(以前您只能使用 GPU 指定文本功能)。我不会深入讨论它们如何向量化的细节(你可以看看官方文档)。让我们来看看这个内置的矢量化与我们之前的结果相比表现如何:(注意,这是单独运行的结果,因此我们的结果与上面略有不同,但总体结果是相同的)
# Testing the CatBoost text feature
model = CatBoostClassifier(n_estimators=2000,
text_features=[0],
colsample_bylevel=0.06,
max_leaves=31,
subsample=0.67,
verbose=0,
thread_count=6,
random_state=1234)
model.fit(X_train_text,
y_train_sub,
eval_set = [(X_valid_text, y_valid)],
early_stopping_rounds=15,
verbose=0)
图 5:比较 CatBoost 内置文本矢量化的测试精度
图 6:比较 CatBoost 内置文本矢量化的训练时间
正如我们从上面看到的,利用 CatBoost 的内部文本矢量化功能,我们的火车时间几乎减少了一半!此外,我们可以看到,新的模型比我们迄今为止测试的任何其他方法都更通用。虽然我们没有达到与 LightGBM 相同的火车速度,但我们确实发现具有这一新扩展功能的 CatBoost 可以实现令人印象深刻的准确性!
参考
- 大型电影评论数据集【https://ai.stanford.edu/~amaas/data/sentiment/ T3
- tfi df-矢量化
教程 https://towards data science . com/natural-language-processing-feature-engineering-using-TF-IDF-E8 b 9d 00 e 7e 76 - 随机森林简介
https://towards data science . com/an-implementation-and-explain-the-Random-Forest-in-python-77bf 308 a9b 76 - Adaboost vs GBM 的有益帖子:
https://stats . stack exchange . com/questions/164233/intuitive-explaining-of-differences-between-gradient-boosting-trees-GBM-ad - 梯度助推树上的幻灯片
https://homes . cs . Washington . edu/~ tqchen/data/pdf/Boosted tree . pdf - XGBoost 主页
https://xgboost.readthedocs.io/en/latest/ - LightGBM 主页
https://lightgbm.readthedocs.io/en/latest/ - CatBoost 主页
https://catboost.ai/
XGBoost 和不平衡类:预测酒店取消
Boosting 是机器学习中一种非常流行的技术,旨在通过将许多弱模型组合成一个强模型来提高预测精度。
为此,增强被称为集成方法。
在这个例子中,boosting 技术用于确定客户是否会取消他们的酒店预订。
数据概述和功能选择
训练数据从 AWS S3 时段导入,如下所示:
import boto3
import botocore
import pandas as pd
from sagemaker import get_execution_rolerole = get_execution_role()bucket = 'yourbucketname'
data_key_train = 'H1full.csv'
data_location_train = 's3://{}/{}'.format(bucket, data_key_train)train_df = pd.read_csv(data_location_train)
酒店取消表示响应(或相关)变量,其中 1 =取消,0 =继续预订。
用于分析的特征如下。
间隔
leadtime = train_df['LeadTime']
arrivaldateyear = train_df['ArrivalDateYear']
arrivaldateweekno = train_df['ArrivalDateWeekNumber']
arrivaldatedayofmonth = train_df['ArrivalDateDayOfMonth']
staysweekendnights = train_df['StaysInWeekendNights']
staysweeknights = train_df['StaysInWeekNights']
adults = train_df['Adults']
children = train_df['Children']
babies = train_df['Babies']
isrepeatedguest = train_df['IsRepeatedGuest']
previouscancellations = train_df['PreviousCancellations']
previousbookingsnotcanceled = train_df['PreviousBookingsNotCanceled']
bookingchanges = train_df['BookingChanges']
agent = train_df['Agent']
company = train_df['Company']
dayswaitinglist = train_df['DaysInWaitingList']
adr = train_df['ADR']
rcps = train_df['RequiredCarParkingSpaces']
totalsqr = train_df['TotalOfSpecialRequests']
绝对的
arrivaldatemonth = train_df.ArrivalDateMonth.astype("category").cat.codes
arrivaldatemonthcat=pd.Series(arrivaldatemonth)
mealcat=train_df.Meal.astype("category").cat.codes
mealcat=pd.Series(mealcat)
countrycat=train_df.Country.astype("category").cat.codes
countrycat=pd.Series(countrycat)
marketsegmentcat=train_df.MarketSegment.astype("category").cat.codes
marketsegmentcat=pd.Series(marketsegmentcat)
distributionchannelcat=train_df.DistributionChannel.astype("category").cat.codes
distributionchannelcat=pd.Series(distributionchannelcat)
reservedroomtypecat=train_df.ReservedRoomType.astype("category").cat.codes
reservedroomtypecat=pd.Series(reservedroomtypecat)
assignedroomtypecat=train_df.AssignedRoomType.astype("category").cat.codes
assignedroomtypecat=pd.Series(assignedroomtypecat)
deposittypecat=train_df.DepositType.astype("category").cat.codes
deposittypecat=pd.Series(deposittypecat)
customertypecat=train_df.CustomerType.astype("category").cat.codes
customertypecat=pd.Series(customertypecat)
reservationstatuscat=train_df.ReservationStatus.astype("category").cat.codes
reservationstatuscat=pd.Series(reservationstatuscat)
使用树外分类器和前向和后向特征选择方法进行分析时,确定的特征如下:
- 研制周期
- 原产国
- 细分市场
- 存款类型
- 客户类型
- 所需的停车位
- 到达日期:年
- 抵达日期:月
- 到达日期:周数
- 到达日期:当月的某一天
助推技术
XGBoost 是一种提升技术,因其执行速度和模型性能而闻名,并越来越多地被作为默认的提升方法,这种方法实现了梯度提升决策树算法,其工作方式类似于自适应提升,但实例权重不再像 AdaBoost 那样在每次迭代时调整。取而代之的是,尝试用新的预测器来拟合前一个预测器产生的残差。
精确度与召回率和 f1 分数
当比较准确度分数时,我们看到在每个混淆矩阵中都提供了大量的读数。
然而,在精度和召回之间存在一个特别重要的区别。
Precision = ((True Positive)/(True Positive + False Positive))Recall = ((True Positive)/(True Positive + False Negative))
这两个读数经常相互矛盾,也就是说,通常不可能在不降低召回率的情况下提高精确度,反之亦然。
对理想指标的评估很大程度上取决于所分析的具体数据。例如,癌症检测筛查出现假阴性(即表明患者没有患癌症,而事实上他们患有癌症)是一大禁忌。在这种情况下,召回是理想的衡量标准。
然而,对于电子邮件,人们可能更喜欢避免误报,例如,将一封重要的电子邮件发送到垃圾邮件文件夹,而实际上它是合法的。
f1 分数在设计一个更通用的分数时考虑了精确度和召回率。
哪个因素对预测酒店取消更重要?
从酒店的角度来看,他们可能希望更准确地识别出最终会取消预订的客户,这使得酒店能够更好地分配房间和资源。确定不打算取消预订的客户不一定会增加酒店分析的价值,因为酒店知道,无论如何,很大一部分客户最终都会坚持预订。
分析
该数据首先被分为 H1 数据集的训练和验证数据,H2 数据集被用作比较 XGBoost 预测与实际取消发生率的测试集。
以下是 XGBoost 算法的实现:
import xgboost as xgb
xgb_model = xgb.XGBClassifier(learning_rate=0.001,
max_depth = 1,
n_estimators = 100,
scale_pos_weight=5)
xgb_model.fit(x_train, y_train)
注意,本例中的 scale_pos_weight 参数设置为 5 。这样做的原因是对次要类别的错误施加更大的惩罚,在这种情况下,响应变量中的任何 1 事件,即酒店取消。权重越高,对次要类上的错误施加的惩罚就越大。这样做的原因是因为数据集中 0 比 1 多,也就是说,坚持预订的客户比取消预订的客户多。
因此,为了有一个无偏见的模型,次要类上的错误需要受到更严厉的惩罚。
验证集性能
以下是训练和验证集的准确性:
>>> print("Accuracy on training set: {:.3f}".format(xgb_model.score(x_train, y_train)))
>>> print("Accuracy on validation set: {:.3f}".format(xgb_model.score(x_val, y_val)))Accuracy on training set: 0.415
Accuracy on validation set: 0.414
预测是这样生成的:
>>> xgb_predict=xgb_model.predict(x_val)
>>> xgb_predictarray([1, 1, 1, ..., 1, 1, 1])
下面是一个混淆矩阵,比较了验证集上的预测取消和实际取消:
>>> from sklearn.metrics import classification_report,confusion_matrix
>>> print(confusion_matrix(y_val,xgb_predict))
>>> print(classification_report(y_val,xgb_predict))[[1393 5873]
[ 0 2749]]
precision recall f1-score support 0 1.00 0.19 0.32 7266
1 0.32 1.00 0.48 2749 accuracy 0.41 10015
macro avg 0.66 0.60 0.40 10015
weighted avg 0.81 0.41 0.37 10015
请注意,虽然 f1 分数(41%)的准确性很低,但类别 1(取消)的召回分数是 100%。这意味着该模型会产生许多误报,从而降低整体准确性,但这具有将召回率提高到 100%的效果,即该模型可以 100%成功识别所有将取消预订的客户,即使这会导致一些误报。
测试集上的性能
和前面一样,测试集也是从相关的 S3 存储桶导入的:
data_key_test = 'H2full.csv'
data_location_test = 's3://{}/{}'.format(bucket, data_key_test)h2data = pd.read_csv(data_location_test)
这是 XGBoost 模型在 H2 上的后续分类性能,这是本例中的测试集。
>>> from sklearn.metrics import classification_report,confusion_matrix
>>> print(confusion_matrix(b,prh2))
>>> print(classification_report(b,prh2))[[ 1926 44302]
[ 0 33102]]
precision recall f1-score support 0 1.00 0.04 0.08 46228
1 0.43 1.00 0.60 33102 accuracy 0.44 79330
macro avg 0.71 0.52 0.34 79330
weighted avg 0.76 0.44 0.30 79330
f1 分数所指示的准确度稍高,为 44%,但是类别 1 的回忆准确度再次为 100%。
校准:磅秤位置重量
在这种情况下,观察到使用 5 的 scale_pos_weight 导致 100%的召回,同时将 f1 分数准确度非常显著地降低到 44%。
然而,100%的召回也是不可靠的。例如,假设 scale_pos_weight 被设置得更高,这意味着几乎所有的预测都表示响应为 1,即所有的客户都被预测取消预订。
如果预测所有客户都将取消预订,则该模型没有内在价值,因为不再有任何方法来识别可能会取消预订的客户与不会取消预订的客户的独特属性。
在这方面,更平衡的解决方案是具有高召回率,同时还确保整体准确度不会降得过低。
以下是分别使用 2 、 3 、 4 和 5 的权重时的混淆矩阵结果。
秤重= 2
[[36926 9302]
[12484 20618]]
precision recall f1-score support 0 0.75 0.80 0.77 46228
1 0.69 0.62 0.65 33102 accuracy 0.73 79330
macro avg 0.72 0.71 0.71 79330
weighted avg 0.72 0.73 0.72 79330
秤重= 3
[[12650 33578]
[ 1972 31130]]
precision recall f1-score support 0 0.87 0.27 0.42 46228
1 0.48 0.94 0.64 33102 accuracy 0.55 79330
macro avg 0.67 0.61 0.53 79330
weighted avg 0.70 0.55 0.51 79330
秤重= 4
[[ 1926 44302]
[ 0 33102]]
precision recall f1-score support 0 1.00 0.04 0.08 46228
1 0.43 1.00 0.60 33102 accuracy 0.44 79330
macro avg 0.71 0.52 0.34 79330
weighted avg 0.76 0.44 0.30 79330
秤重= 5
[[ 1926 44302]
[ 0 33102]]
precision recall f1-score support 0 1.00 0.04 0.08 46228
1 0.43 1.00 0.60 33102 accuracy 0.44 79330
macro avg 0.71 0.52 0.34 79330
weighted avg 0.76 0.44 0.30 79330
当 scale_pos_weight 设置为 3 时,召回率为 94%,而准确率为 55%。当 scale_pos_weight 参数设置为 5 时,召回率为 100%,而 f1 得分准确率降至 44%。此外,请注意,将参数从 4 增加到 5 不会导致召回率或整体准确度的任何变化。
在这方面,使用 3 的权重允许高召回率,同时仍然允许总体分类准确度保持在 50%以上,并允许酒店有一个基线来区分取消预订的客户和没有取消预订的客户的属性。
结论
在本例中,您看到了使用各种提升方法来预测酒店取消预订。如上所述,在这种情况下,boosting 方法被设置为对 minor 类施加更大的惩罚,其结果是降低了由 f1 分数测量的整体准确性,因为存在更多的假阳性。然而,召回分数因此大幅增加——如果假设在这种情况下假阳性比假阴性更容易容忍——那么人们可以认为该模型在此基础上表现得相当好。作为参考,在相同数据集上运行的 SVM 模型展示了 63%的总体准确性,而在类别 1 上的召回率下降到 75%。
您可以在这里找到原始文章,它包括一个到 GitHub 资源库的链接,该资源库包含与上述示例相关的相关笔记本和数据集。
免责声明:本文是在“原样”的基础上编写的,没有任何担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。
有用的参考资料
- 安东尼奥、阿尔梅迪亚和努内斯(2019)。酒店预订需求数据集
- 分类:精度和召回率
- 通过 Scikit-Learn 和 TensorFlow 进行机器实践学习
- 机器学习掌握:应用机器学习 XGBoost 简介
- 什么是 LightGBM,如何实现?如何微调参数?