人口普查收入数据的逻辑回归分类器
在这篇博客中,我们将分析来自 UCI 机器学习知识库的人口普查数据集。
数据集包含三个文件:
我们将使用逻辑回归来构建分类器。如果你不知道逻辑回归,你可以看看我之前的博客。
我们将看到如何建立一个实用的机器学习项目。一般来说,任何机器学习项目都需要以下步骤:
- 定义问题陈述
- 探索性数据分析
- 训练模型
- 微调模型
- 保存模型
所以让我们开始吧。
定义问题陈述
数据包含匿名信息,如年龄、职业、教育、工人阶级等。*目标是训练一个二元分类器来预测收入,它有两个可能的值’> 50K ‘和’< 50K '。*数据集中有 48842 个实例和 14 个属性。数据很好地融合了分类值、数值值和缺失值。
首先,我们将导入所需的库
import numpy as np
import pandas as pd
import io
import requests
import seaborn as sns
from matplotlib import pyplot as plt
import pickle
import os
from pandas.api.types import CategoricalDtypefrom sklearn.base import BaseEstimator, TransformerMixin
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import FeatureUnion
from sklearn.model_selection import cross_val_score%matplotlib inline
下载数据
我们将编写一个小脚本来下载 URL 列表的内容,并将它们保存在一个文件夹中,而不是手动下载数据集。以后我们可以直接使用下载的数据,而不是每次都打网络。您也可以将此代码用于任何机器学习项目。
def load_dataset(path, urls):
if not os.path.exists(path):
os.mkdir(path)
for url in urls:
data = requests.get(url).content
filename = os.path.join(path, os.path.basename(url))
with open(filename, "wb") as file:
file.write(data)
我们将在当前工作目录中创建一个data
文件夹,并存储 URL 的内容。
urls = ["http://archive.ics.uci.edu/ml/machine-learning- databases/adult/adult.data",
"https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.names",
"https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test"]load_dataset('data', urls)
接下来,我们使用read_csv
函数将数据加载到一个pandas
数据帧中。
columns = ["age", "workClass", "fnlwgt", "education", "education-
num","marital-status", "occupation", "relationship",
"race", "sex", "capital-gain", "capital-loss", "hours-per-
week", "native-country", "income"]train_data = pd.read_csv('data/adult.data', names=columns,
sep=' *, *', na_values='?')
test_data = pd.read_csv('data/adult.test', names=columns,
sep=' *, *', skiprows=1, na_values='?')
数据值前后有一些空格。为了修剪所有的空白,我们使用分隔符‘ *, *’
。测试数据集有一个奇怪的第一行,因此我们使用skiprows=1
跳过这一行。数据集中缺失的值用?
表示
接下来,我们将探索数据。这是构建模型之前的重要一步。
探索性数据分析
让我们使用train_data.info()
获得更多关于训练数据的信息
RangeIndex: 32561 entries, 0 to 32560
Data columns (total 15 columns):
age 32561 non-null int64
workClass 30725 non-null object
fnlwgt 32561 non-null int64
education 32561 non-null object
education-num 32561 non-null int64
marital-status 32561 non-null object
occupation 30718 non-null object
relationship 32561 non-null object
race 32561 non-null object
sex 32561 non-null object
capital-gain 32561 non-null int64
capital-loss 32561 non-null int64
hours-per-week 32561 non-null int64
native-country 31978 non-null object
income 32561 non-null object
观察结果
- 训练数据集中有 32561 个样本
- 数据集中既有分类列也有数值列
- 列工作类别、职业、本国有缺失值
类似地,对于测试数据集
- 有 16281 个样品
- 没有没有丢失的值
让我们借助一些可视化工具来看看数字和分类数据。
处理数值列
我们使用select_dtypes
函数选择数字列。
num_attributes = train_data.select_dtypes(include=['int'])
print(num_attributes.columns)['age', 'fnlwgt', 'education-num', 'capital-gain', 'capital-loss', 'hours-per-week']
变量年龄、每周工作时间不言自明。
- fnlwgt :取样重量
- education-num :受教育的总年限
- 资本收益/资本损失:工资以外的投资收入
fnlwgt 与目标变量收入无关,在建立模型之前将被移除
数据可视化
num_attributes.hist(figsize=(10,10))
使用train_data.describe()
可以收集更多关于数据的信息
观察结果
- 数字属性都没有缺失值
- 这些值在不同的范围内。许多机器学习模型要求值在相同的范围内。我们将使用 sklearn 库中的 StandardScaler 来缩放特性。
处理分类列
cat_attributes = train_data.select_dtypes(include=['object'])
print(cat_attributes.columns)['workClass', 'education', 'marital-status', 'occupation', 'relationship', 'race', 'sex', 'native-country', 'income']
数据可视化
我们将使用 seaborn 包中的countplot
。
sns.countplot(y='workClass', hue='income', data = cat_attributes)
sns.countplot(y='occupation', hue='income', data = cat_attributes)
观察结果
- 列 education 只是列 education-num 的字符串表示。我们将删除教育栏目。
- 变量工作类别、职业、母国有缺失值。我们将用该列中出现频率最高的值替换每列中缺失的值。
我们需要不同地处理数字和分类属性。数字属性需要缩放,而对于分类列,我们需要填充缺失的值,然后将分类值编码成数字值。为了应用这些转换序列,我们将使用 sklearn 的管道类。我们还将构建可直接用于管道的定制变压器。
创建管道
sklearn 内置了很多变形金刚。然而,如果内置的转换器不能为您完成工作,您可以构建一个定制的转换器。你需要做的就是继承 BaseEstimator 和 TransformerMixin 类。您还需要实现 fit 和 transform 方法。
- fit: 应该返回 self 的一个实例
- **转换:**转换逻辑可在此添加
列选择器管道
sklearn 没有提供库来直接操作 pandas 数据帧。我们将编写自己的自定义转换器,它将选择相应的属性(数字或分类)
class ColumnsSelector(BaseEstimator, TransformerMixin):
def __init__(self, type):
self.type = type
def fit(self, X, y=None):
return self
def transform(self,X):
return X.select_dtypes(include=[self.type])
数字数据管道
我们使用上面定义的列选择器转换器选择数字属性,然后使用标准缩放器缩放数值。
num_pipeline = Pipeline(steps=[
("num_attr_selector", ColumnsSelector(type='int')),
("scaler", StandardScaler())
])
如果我们调用num_pipeline
的fit
和transform
方法,它会在内部调用管道中定义的所有转换器的fit
和transform
方法。在这种情况下,列选择器和标准缩放器转换器。
分类数据管道
我们需要替换分类列中缺失的值。我们将用每列中出现频率最高的值替换缺失的值。sklearn 带有估算器来处理缺失值。然而,输入器仅适用于数值。我们将编写一个定制的转换器,它将接受我们需要替换缺失值的列的列表,以及用于填充缺失值的策略
class CategoricalImputer(BaseEstimator, TransformerMixin):
def __init__(self, columns = None, strategy='most_frequent'):
self.columns = columns
self.strategy = strategy
def fit(self,X, y=None):
if self.columns is None:
self.columns = X.columns
if self.strategy is 'most_frequent':
self.fill = {column: X[column].value_counts().index[0] for
column in self.columns}
else:
self.fill ={column: '0' for column in self.columns}
return self
def transform(self,X):
X_copy = X.copy()
for column in self.columns:
X_copy[column] = X_copy[column].fillna(self.fill[column])
return X_copy
所有的机器学习模型都需要数值。我们将使用 pd.get_dummies 将分类值转换成数值。这类似于使用 OneHotEncoder ,只是 OneHotEncoder 需要数字列。
我们需要在使用 pd.get_dummies 之前合并训练和测试数据集,因为测试数据集中可能存在训练数据集中不存在的类。为此,在fit
方法中,我们将连接训练和测试数据集,并找出一列的所有可能值。在transform
方法中,我们将把每一列转换成分类类型,并指定该列可以接受的类别列表。get_dummies 将为该列的类别列表中不存在的类别创建一个全零的列。
转换器还接受一个参数dropFirst
,它指示我们是否应该在使用 pd.get_dummies 创建虚拟列之后删除第一列。我们应该删除第一列以避免多重共线性。默认情况下,该值设置为True
class CategoricalEncoder(BaseEstimator, TransformerMixin):
def __init__(self, dropFirst=True):
self.categories=dict()
self.dropFirst=dropFirst
def fit(self, X, y=None):
join_df = pd.concat([train_data, test_data])
join_df = join_df.select_dtypes(include=['object'])
for column in join_df.columns:
self.categories[column] =
join_df[column].value_counts().index.tolist()
return self
def transform(self, X):
X_copy = X.copy()
X_copy = X_copy.select_dtypes(include=['object'])
for column in X_copy.columns:
X_copy[column] = X_copy[column].astype({column:
CategoricalDtype(self.categories[column])})
return pd.get_dummies(X_copy, drop_first=self.dropFirst)
完整的分类管道
cat_pipeline = Pipeline(steps=[
("cat_attr_selector", ColumnsSelector(type='object')),
("cat_imputer", CategoricalImputer(columns=
['workClass','occupation', 'native-country'])),
("encoder", CategoricalEncoder(dropFirst=True))
])
完成管道
我们有两条变压器管道,即 num_pipeline 和 cat_pipeline 。我们可以使用功能联合来合并它们
full_pipeline = FeatureUnion([("num_pipe", num_pipeline),
("cat_pipeline", cat_pipeline)])
现在我们有了构建模型的所有管道,让我们为模型准备数据并构建它。
我们将删除不需要的列
train_data.drop(['fnlwgt', 'education'], axis=1, inplace=True)
test_data.drop(['fnlwgt', 'education'], axis=1, inplace=True)
训练模型
我们将创建训练数据集的副本,并分离特征向量和目标值。
train_copy = train_data.copy()
train_copy["income"] = train_copy["income"].apply(lambda x:0 if
x=='<=50K' else 1)X_train = train_copy.drop('income', axis =1)
Y_train = train_copy['income']
接下来,我们将X_train
传递给我们构建的full_pipeline
。
X_train_processed=full_pipeline.fit_transform(X_train)model = LogisticRegression(random_state=0)
model.fit(X_train_processed, Y_train)
测试模型
test_copy = test_data.copy()
test_copy["income"] = test_copy["income"].apply(lambda x:0 if
x=='<=50K.' else 1)X_test = test_copy.drop('income', axis =1)
Y_test = test_copy['income']
我们将应用于训练数据集的相同变换应用于测试数据集。
X_test_processed = full_pipeline.fit_transform(X_test)predicted_classes = model.predict(X_test_processed)
模型评估
我们将使用来自 sklearn 的 accuracy_score 来确定模型的准确性
accuracy_score(predicted_classes, Y_test.values)
准确率为 85.2%
让我们画出混淆矩阵。
cfm = confusion_matrix(predicted_classes, Y_test.values)
sns.heatmap(cfm, annot=True)
plt.xlabel('Predicted classes')
plt.ylabel('Actual classes')
X 轴代表预测类,Y 轴代表实际类。我们如何解读混淆矩阵?1.2e+04
当实际类别为 0 时,模型正确预测类别为 0 的次数。同样,对于其余的情况也可以得出结论。
交叉验证
我们将使用stratified fold将我们的数据集分成 k 个文件夹。在每次迭代中,k-1
个折叠被用作训练集,剩余的折叠被用作验证。我们使用 StratifiedKFold,因为它保留了每个类中样本的百分比。
如果我们使用 KFold ,我们可能会面临引入采样偏差的风险,即训练集可能包含大量收入大于 50K 的样本,而测试集包含更多收入小于 50K 的样本。在这种情况下,从训练数据构建的模型将不能很好地适用于测试数据集。而 StratifiedKFold 将确保在训练和测试数据集中每个类都有足够的样本。
我们将使用 cross_val_score 进行交叉验证。参数cv
决定交叉验证策略。如果整数值被传递给cv
,则使用 StatifiedKFold
cross_val_model = LogisticRegression(random_state=0)
scores = cross_val_score(cross_val_model, X_train_processed,
Y_train, cv=5)
print(np.mean(scores))
我们将每次迭代中获得的所有得分的平均值作为我们模型的最终得分。
交叉验证的准确率为 85.0%。
微调模型
我们可以通过调整参数来微调我们的模型。sklearn 附带了 GridSearchCV 来对估计器的指定参数值进行彻底搜索。
# penalty specifies the norm in the penalization
penalty = ['l1', 'l2']# C is the inverese of regularization parameter
C = np.logspace(0, 4, 10)random_state=[0]# creating a dictionary of hyperparameters
hyperparameters = dict(C=C, penalty=penalty,
random_state=random_state)
使用 GridSearchCV 寻找最佳参数
clf = GridSearchCV(estimator = model, param_grid = hyperparameters,
cv=5)
best_model = clf.fit(X_train_processed, Y_train)
print('Best Penalty:', best_model.best_estimator_.get_params() ['penalty'])
print('Best C:', best_model.best_estimator_.get_params()['C'])
最佳参数是
Best Penalty: l1
Best C: 1.0
使用最佳模型进行预测
best_predicted_values = best_model.predict(X_test_processed)
accuracy_score(best_predicted_values, Y_test.values)
最佳参数模型的准确率为 85.2%
保存模型
我们已经完成了创建和测试模型的所有艰苦工作。如果我们可以保存模型以备将来使用,而不是重新训练它,那就太好了。我们将把我们的模型保存在 pickle 中。
filename = 'final_model.sav'
pickle.dump(model, open(filename, 'wb'))
从 pickle 加载模型
saved_model = pickle.load(open(filename, 'rb'))
现在我们可以使用该模型进行预测。
这个博客到此为止。完整的 Jupyter 笔记本可以在这里找到。
结束语
我们已经学会了建立一个完整的机器学习项目。在这个过程中,我们构建了可以与 sklearn 的管道类一起使用的自定义转换器。我们还学会了微调我们的模型,并保存它以备将来使用。
如果有什么地方我可以做得更好,请告诉我。
感谢阅读!!
逻辑回归—详细概述
Figure 1: Logistic Regression Model (Source:http://dataaspirant.com/2017/03/02/how-logistic-regression-model-works/)
逻辑回归在二十世纪早期被用于生物科学。后来,它被用于许多社会科学应用中。当因变量(目标)是分类变量时,使用逻辑回归。
举个例子,
- 要预测电子邮件是垃圾邮件(1)还是(0)
- 肿瘤是恶性的(1)还是非恶性的(0)
考虑一个场景,我们需要对一封电子邮件是否是垃圾邮件进行分类。如果我们对这个问题使用线性回归,就需要设置一个阈值,根据这个阈值可以进行分类。比方说,如果实际类别是恶性的,预测连续值为 0.4,阈值为 0.5,则数据点将被分类为非恶性的,这会导致实时的严重后果。
从这个例子可以推断,线性回归不适合分类问题。线性回归是无限的,这就带来了逻辑回归。它们的值严格地在 0 到 1 之间。
简单逻辑回归
型号
输出= 0 或 1
假设=> Z = WX + B
hθ(x)= sigmoid(Z)
乙状结肠功能
Figure 2: Sigmoid Activation Function
如果‘Z’趋于无穷大,Y(预测)将变为 1,如果‘Z’趋于负无穷大,Y(预测)将变为 0。
分析假设
假设的输出是估计的概率。这用于推断给定输入 x 时,预测值与实际值的可信度。考虑以下示例,
X = [x0 x1] = [1 个 IP 地址]
基于 x1 值,假设我们获得的估计概率为 0.8。这表明一封电子邮件有 80%的可能是垃圾邮件。
从数学上讲,这可以写成:
Figure 3: Mathematical Representation
这证明了“逻辑回归”这个名称的合理性。将数据拟合到线性回归模型中,然后由预测目标分类因变量的逻辑函数对其进行操作。
逻辑回归的类型
1.二元逻辑回归
分类回答只有两种可能的结果。示例:垃圾邮件与否
2.多项式逻辑回归
三个或更多类别,无需排序。示例:预测哪种食物更受欢迎(素食、非素食、纯素食)
3.有序逻辑回归
三个或三个以上的分类与排序。示例:电影等级从 1 到 5
决定边界
为了预测数据属于哪一类,可以设置一个阈值。基于该阈值,将所获得的估计概率分类。
比如说,如果 predicted_value ≥ 0.5,那么将邮件归类为垃圾邮件,否则归类为非垃圾邮件。
决策边界可以是线性或非线性的。多项式阶可以增加,以获得复杂的决策边界。
成本函数
Figure 4: Cost Function of Logistic Regression
为什么用于线性的成本函数不能用于逻辑?
线性回归使用均方误差作为其成本函数。如果这用于逻辑回归,那么它将是参数(θ)的非凸函数。梯度下降只有在函数是凸的情况下才会收敛到全局极小值。
Figure 5: Convex and non-convex cost function
成本函数解释
Figure 6: Cost Function part 1
Figure 7: Cost Function part 2
简化成本函数
Figure 8: Simplified Cost Function
为什么这个成本函数?
Figure 9: Maximum Likelihood Explanation part-1
Figure 10: Maximum Likelihood Explanation part-2
这个负函数是因为我们在训练的时候,需要通过最小化损失函数来最大化概率。假设样本是从完全独立的分布中抽取的,降低成本将增加最大可能性。
推导梯度下降算法的公式
Figure 11: Gradient Descent Algorithm part 1
Figure 12: Gradient Descent part 2
Python 实现
def weightInitialization(n_features):
w = np.zeros((1,n_features))
b = 0
return w,bdef sigmoid_activation(result):
final_result = 1/(1+np.exp(-result))
return final_result def model_optimize(w, b, X, Y):
m = X.shape[0]
#Prediction
final_result = sigmoid_activation(np.dot(w,X.T)+b)
Y_T = Y.T
cost = (-1/m)*(np.sum((Y_T*np.log(final_result)) + ((1-Y_T)*(np.log(1-final_result)))))
#
#Gradient calculation
dw = (1/m)*(np.dot(X.T, (final_result-Y.T).T))
db = (1/m)*(np.sum(final_result-Y.T))
grads = {"dw": dw, "db": db}
return grads, costdef model_predict(w, b, X, Y, learning_rate, no_iterations):
costs = []
for i in range(no_iterations):
#
grads, cost = model_optimize(w,b,X,Y)
#
dw = grads["dw"]
db = grads["db"]
#weight update
w = w - (learning_rate * (dw.T))
b = b - (learning_rate * db)
#
if (i % 100 == 0):
costs.append(cost)
#print("Cost after %i iteration is %f" %(i, cost))
#final parameters
coeff = {"w": w, "b": b}
gradient = {"dw": dw, "db": db}
return coeff, gradient, costsdef predict(final_pred, m):
y_pred = np.zeros((1,m))
for i in range(final_pred.shape[1]):
if final_pred[0][i] > 0.5:
y_pred[0][i] = 1
return y_pred
成本与迭代次数
Figure 13: Cost Reduction
系统的训练和测试准确率为 100 %
该实现用于二元逻辑回归。对于超过 2 类的数据,必须使用 softmax 回归。
这是一个教育性的帖子,灵感来自吴恩达教授的深度学习课程。
用于面部识别的逻辑回归
使用 sklearn 的混淆矩阵和 ROC-AUC 曲线
注意 :此帖子不再是最新的,可能包含错误。它是为了透明而保留的。更新版本可以在这里找到。**
面部识别算法一直令我着迷,为了在一些数据上展示我新发现的逻辑回归技能,我基于一个名为“皮肤分割”的数据集创建了一个模型。
正如其描述中所指出的,皮肤分割中的数据是“通过从各种年龄组(青年、中年和老年)、种族组(白人、黑人和亚洲人)以及从 FERET 数据库和 PAL 数据库获得的性别的面部图像中随机采样 B、G、R 值来收集的。”数据集具有 245,057 行和 4 列(B、G、R 和指示图像被分类为包含皮肤还是不包含皮肤的二进制列)。后者,二元列使这个数据集适合逻辑回归。
(如果你想阅读使用该数据集的两篇(付费)学术文章,请参见此处的和此处的和。)
回归
我的专长是 Python,我特别想测试一下 scikit-learn 库,因为它是回归等科学任务的行业标准。我还选择使用 Juypter Notebook 作为我的 IDE,而不是 Atom 这样的文本编辑器,因为它的入门门槛较低;凭借其叙事结构,Jupyter 让大多数人都能感受到代码是如何工作的。
要自己运行这段代码,您需要在您的机器上/虚拟环境中安装/导入 Python 3、scikit-learn、Pandas、NumPy、matplotlib、Seaborn、Itertools 和 imb learn(requirements . txt 文件即将发布!).
你可以在这里找到这个项目的回购。在那里,你可以找到一个深入的 Jupyter 笔记本,概述了这篇文章中总结的所有步骤。
芒格
我必须对这个数据集进行的数据管理相当简单。在通过 URL 读入文本文件并保存到 Pandas dataframe 后,您可以看到它唯一真正的问题是缺少列标题。
Original dataframe
在将第一行下推到数据框中并重命名列标题后,我能够得到这样的结果:
Munged dataframe
在这个数据集中,1 表示没有皮肤的像素,2 表示有皮肤的像素。
正如您所预料的,1 和 2 确实很有帮助,但是我们真的希望 1 和 0 用于逻辑回归。所以,我为皮肤或无皮肤专栏制作了假人。(我还将数据类型强制为 int64,以便与数据帧中的其他列保持一致。)
Making dummies and coercing datatype.
正如你所看到的,我把这个皮肤或者无皮肤列变成了我的 y 变量(我的因变量)。其他列我变成了一个矩阵(X)。
X matrix
在我的 X 矩阵中,我还想让我的所有变量都在同一标度上,所以我让它们通过一个最小-最大归一化器,并让它们都在 0-1 标度上。
Normalizing X values
训练-测试-分割和建立模型
在使我的数据进入可工作状态后,我使用 sklearn 将它分成测试集和训练集。我还创建了我的模型,使其适合我的训练数据,然后在我的训练和测试数据上运行我的模型,以查看它的性能如何。
Train-test-split
Creating and fitting my model
Running the model on my training and test data
评估性能,第 1 部分:简单的读数
我查看了我的预测值(y_hat_train 和 y_hat_test)与我的原始 y_train 和 y_test 值之间的差异,以评估我的模型的准确性。
Evaluating initial performance
在读数中,与真实值相比,0 的数量是正确预测的数量,1 的数量是错误预测的数量。normalize = True 只是将读数的第一部分从预测数转换为百分比。
您可以看到,根据我们的训练数据,我们的模型在 90.7%的时间内是准确的,而根据我们的测试数据,它在 90.6%的时间内是准确的。相当不错!
评估性能,第 2 部分:混淆矩阵
我还想看看我的模型在混淆矩阵方面表现如何。(关于混淆矩阵的精彩阅读,见这里。)
Confusion matrix for initial model
正如你在评论中看到的,这里 0 是被分类为没有皮肤的像素,1 是被分类为有皮肤的像素。
为了让我的混淆矩阵的值更容易理解,我运行了一个分类报告,以获得一些常见的指标,如精确度、召回率和 f1 分数。
Classification Report from sklearn.metrics
您可以在这里看到,我们的模型的准确率为 96%,召回率为 92%,f1 值为 94%。我还想知道我的准确率,所以我简单地手动计算了一下,得到了 91%(与我们在上面的简单读数部分的测试数据中得到的数字相同)。
为了更好地展示每个分数的含义,请参见下图。
Recall and precision mapped onto a confusion matrix
评估绩效,第 3 部分:ROC-AUC 曲线
ROC-AUC 曲线是一个有用的指标,因为它们衡量的是真阳性率和假阳性率。
我为我的训练和测试数据生成了 ROC-AUC 曲线,但是它们看起来基本相同,所以我在这里只显示训练图像。(训练数据的 AUC 为 93.4%,而测试数据的 AUC 为 93.2%。)
Creating my ROC curve
ROC-AUC curve for testing data.
更多关于 ROC-AUC 曲线及其目的可以在这里和这里找到。
如你所见,我们的 ROC 曲线紧挨着图表的左上角,这正是我们想要的。
倒回一点:ROC-AUC 曲线和类别不平衡
ROC-AUC 曲线最有用的一点是,即使原始数据集中存在类别不平衡,它们也允许我们评估模型。
类别不平衡是指在您的数据中,一种类别明显多于另一种类别。这有能力真正搞乱你的分析。举个例子,一个罕见疾病的数据集是有偏差的(即存在类别不平衡问题)。我们假设 1000 个案例中只有 2 个是阳性的。即使你做了一个蹩脚的模型,把一切都归类为负面,你仍然会达到 99.8%的准确率(即 998 / 1000 的分类是正确的)。因此,当模型在不平衡的数据集上运行时,您需要更多的上下文来真正评估您的模型。
所以,让我们倒回去一点,看看我们的数据是否不平衡。也许我们可以让我们的模型变得更好。
Class balance for original data
我们可以看到,我们的数据有点奇怪——大约 79%被归类为 1(即包含皮肤的像素),只有大约 21%被归类为 0(即不包含皮肤的像素)。
所以,在我们今天结束之前,让我们运行一个叫做 SMOTE(合成少数过采样)的东西。SMOTE 创建合成数据来为我们的少数类填充更多的值(在我们的例子中,这意味着它将为我们提供更多的 0 数据点)。尽管创建合成数据看起来像是作弊,但这在数据科学世界中是非常常见的做法,因为数据集通常并不均衡。
对我们的原始数据运行 SMOTE 并重新生成我们的混淆矩阵和分类报告,我们得到以下结果。
SMOTE confusion matrix
Classification Report for SMOTE-ized data, showing both training and test readouts
我们可以看到这些数字与我们最初的数字有很大的不同。回想一下,第一次我们的准确率为 96%,召回率为 92%,f1 得分为 94%。通过 SMOTE 运行我们的数据后,我们的准确率为 85%,召回率为 92%,f1 得分为 89%。所以,我们的模型在试图补偿阶级不平衡后实际上变得更差。
作为数据科学家,何时对我们的数据运行 SMOTE 之类的操作,或者让我们的数据保持原样,这取决于我们。在这种情况下,我们可以看到,让我们的数据保持原样是正确的做法。
那么,这一切意味着什么呢?
除了是一个很好的学习机会,我们真的创造了一个很好的模式。我们知道,在这种情况下,对我们的数据做其他事情,例如试图补偿阶级不平衡,肯定不是我们应该做的。我们的原始模型是我们表现最好的,在 94%的时间里正确预测了有皮肤的图像(使用我们的 f1 分数)。
虽然这听起来可能是一个不错的分类率,但创建用于面部识别的算法会带来无数的伦理问题。如果我们的模型被用来在人群中识别被通缉的恐怖分子呢?这当然不同于在 Snapchat 中为滤镜识别人脸。
From Christoph Auer-Welsbach’s post “The Ethics of AI: Building technology that benefits people and society”
这是我们作为数据科学家在创建算法时需要尽可能多的信息的地方。如果我们的模型用于 Snapchat 过滤器,我们可能会希望优化以提高我们的回忆分数——表面上看,当事物不是人脸时,我们错误地将它们识别为人脸比有时只识别真实人脸要好。
另一方面,如果我们的模型用于在人群中发现通缉犯,我们可能仍然希望优化回忆,但结果将会大不相同。如果这意味着你几乎 100%的时间都能抓到被通缉的罪犯,那么把无辜的人带进来审问并潜在地侵犯他们的权利值得吗?或许不会。
当我们在人工智能的世界里玩耍时,我们需要仔细思考这些问题。正如凯茜·奥尼尔在数学毁灭武器中所写的,构建算法需要“道德想象力,而这只有人类才能提供。”
Python 中的逻辑回归在销售营销系统盈利能力评估中的应用
任何企业的销售和营销领域都负责寻找客户、进行销售和创造收入。销售代表通过多种沟通方式联系现有客户和潜在客户,但由于相关的时间和成本,无法联系到所有人。在本文中,逻辑回归作为一种机器学习技术将被用来识别具有较高转换概率的目标人群,并估计锁定所识别群体的盈利能力。
我的 GitHub 上的 Python 代码和数据:
在 GitHub 上创建一个帐户,为数据科学的发展做出贡献。
github.com](https://github.com/saivishnuk/Data-Science/tree/master/Logistic-Regression-to-evaluate-profitability-of-Sales-Marketing-System)
文章大纲:
- 从总体上理解销售-营销系统,并给出一个将在本文中使用的例子
- 理解逻辑回归作为一种技术,以及它在这种情况下如何有用
- 评估盈利能力的方法、代码和结果
从总体上理解销售-营销系统,并给出一个将在本文中使用的示例
大多数系统使用现场销售代理通过个人拜访或移动电话联系客户。产生潜在客户和将潜在客户转化为客户需要一定的成本,接触所有客户是一项既费时又费钱的任务。
例如,一家公司推出了一款新产品,希望接触到可能对该产品感兴趣的现有客户。公司现有客户数量为 41,188,公司估计接触客户的平均成本为 10 美元,如果客户购买了产品,则客户的平均收入为 50 美元。只看数字,成本收入比为 1: 5,这项工作将产生大量利润。意识到之前营销活动对类似产品的转换率(约 11.5%),经理明白瞄准每一个客户将是一个巨大的损失。因此,经理决定首先确定目标受众,然后决定预算。他希望团队中的数据科学家回答 3 个问题:
- 实现最高投资回报率的成本是多少?
- 实现最高利润的成本是多少?
- 利润-投资回报率均衡点的成本是多少?
理解逻辑回归作为一种技术,以及它在这种情况下如何有用
二项式逻辑回归,根据一个或多个连续或分类的独立变量,预测观察值落入两类二分因变量之一的概率。在销售-营销系统中,先前营销活动的结果是因变量,自变量是先前活动的度量,如“过去联系客户的次数”、“自上次购买以来的天数”,…和顾客的一些人口统计特征。在本文中,我们假设数据已按 70/30 的比例分为训练数据集和测试数据集,重点只放在衡量盈利能力的方法上。
评估盈利能力的方法、代码和结果
- 在培训和测试数据集中,结果变量(因变量)为“1”(购买了产品)的客户比例约为 11.2%
- 通过接触训练数据中的所有客户来计算“每个客户的平均利润”。
这表明,通过接触转换率约为 11.2%的所有客户,将导致 1,25710 美元的损失。这保证了目标受众的选择具有较高的转换几率。
3.对训练数据执行逻辑回归,并使用事件发生的预测概率来计算间隔为 0.01 的每个概率值的成本、收入、利润和投资回报(ROI)。
ROI= (Profit/Cost)*100
上述函数将“实际结果”、“事件发生的预测概率”、“每个人的成本”、“每个人的收入”、“要检查的概率范围”作为输入。下面的代码片段是对上述函数的调用,使用培训数据作为输入,并使用经理确定的每个人的估计成本和收入。
在这里,“事件发生的概率”被认为是区分顾客是否会购买产品的临界值。我们可以观察到,随着“事件发生的概率”增加,“目标人群百分比”减少,这意味着考虑更高的概率作为截止点会导致分离更少数量的客户作为目标人群。但有趣的事实是,随着“事件发生的概率”增加,“投资回报率”也增加,这意味着尽管我们针对的人口较少,但与针对更多人口相比,我们得到了良好的结果,这也可以在下图中看到。
不同事件发生预测概率的收入、成本和利润图表:
该图显示,随着“事件发生的概率”增加,成本、收入、利润等指标下降,而 ROI 增加。根据当时的需要,如“预算限制”、“高投资回报率”,可以选择特定的概率作为临界值,但也有必要确保使用测试数据可以复制相同的结果。
不同成本下的投资回报和利润图
从前面的结果可以看出,该图还显示成本类似于利润,投资回报率随着成本的增加而降低。这个图表可以用来回答经理提出的三个问题。
经理的三个问题
- **实现最高投资回报率的成本是多少?**花费更少会带来更高的投资回报率,但与花费更多相比,相关的利润会更少
- 实现最高利润的成本是多少?花费更多会带来更高的利润,但与花费更少相比,投资回报率会更低
- 利润-投资回报率均衡点涉及的成本是多少?花费 11,300 美元将产生 25,300 美元的利润,该支出的投资回报率为 224,即削减 0.42。
我们还需要确保将截止概率取为 0.42 不会导致任何过拟合或欠拟合,并且测试数据的结果大致接近训练数据。
在上面的代码中,model_eval 是一个用户定义的函数,结果显示训练和测试结果的模型评估指标几乎相同。因此,0.42 可以被认为是临界值,并且所有估计概率高于 0.42 的客户可以被认为是目标人群。
谢谢你的阅读。如果你喜欢这篇文章,给它一些掌声👏。希望你有一个伟大的一天!
使用 Python 进行逻辑回归(scikit-learn)
Visualizing the Images and Labels in the MNIST Dataset
Python 的 scikit-learn 库最令人惊讶的一点是,它有一个 4 步建模模式,使编写机器学习分类器变得很容易。虽然本教程使用了一个称为逻辑回归的分类器,但本教程中的编码过程也适用于 sklearn 中的其他分类器(决策树、K-最近邻等)。在本教程中,我们使用逻辑回归来预测基于图像的数字标签。上图显示了一组来自 MNIST 数据集的训练数字(观察值),其类别成员是已知的(标签 0-9)。使用逻辑回归训练模型后,它可用于预测给定图像的图像标签(标签 0-9)。
Logistic Regression using Python Video
这篇教程文章的第一部分介绍了一个玩具数据集(digits dataset ),快速展示了 scikit-learn 的 4 步建模模式,并展示了逻辑回归算法的行为。本教程的第二部分介绍了一个更真实的数据集(MNIST 数据集),以简要说明更改模型的默认参数如何影响性能(包括模型的计时和精度)。就这样,让我们开始吧。如果你迷路了,我建议在一个单独的标签中打开上面的视频。本教程中使用的代码如下
数字逻辑回归(教程代码的第一部分)
MNIST 逻辑回归(教程代码的第二部分)
入门(先决条件)
如果您已经安装了 anaconda,请跳到下一节。我建议安装 anaconda(Python 2 或 3 对本教程来说都很好),这样在导入库时就不会有任何问题。
您可以从官方网站下载 anaconda 并自行安装,也可以按照下面的 anaconda 安装教程在您的操作系统上安装 anaconda。
在 Windows 上安装 Anaconda:链接
在 Mac 上安装 Anaconda:链接
在 Ubuntu 上安装 Anaconda(Linux):链接
数字数据集上的逻辑回归
加载数据(数字数据集)
digits 数据集是 scikit-learn 附带的数据集之一,不需要从外部网站下载任何文件。下面的代码将加载数字数据集。
from sklearn.datasets import load_digits
digits = load_digits()
现在您已经加载了数据集,您可以使用下面的命令
# Print to show there are 1797 images (8 by 8 images for a dimensionality of 64)
print(“Image Data Shape” , digits.data.shape)# Print to show there are 1797 labels (integers from 0–9)
print("Label Data Shape", digits.target.shape)
要查看数据集中有 1797 个图像和 1797 个标签
显示图像和标签(数字数据集)
这一部分实际上只是展示图像和标签的样子。可视化数据通常有助于了解您正在处理的内容。
import numpy as np
import matplotlib.pyplot as pltplt.figure(figsize=(20,4))
for index, (image, label) in enumerate(zip(digits.data[0:5], digits.target[0:5])):
plt.subplot(1, 5, index + 1)
plt.imshow(np.reshape(image, (8,8)), cmap=plt.cm.gray)
plt.title('Training: %i\n' % label, fontsize = 20)
Visualizing the Images and Labels in our Dataset
将数据分为训练集和测试集(数字数据集)
下面的代码执行训练测试分割,将 75%的数据放入训练集,25%的数据放入测试集。这是为了确保我们的分类算法能够很好地推广到新数据。
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(digits.data, digits.target, test_size=0.25, random_state=0)
sci kit-学习 4 步建模模式(数字数据集)
第一步。导入您想要使用的模型
在 sklearn 中,所有的机器学习模型都是作为 Python 类实现的
from sklearn.linear_model import LogisticRegression
第二步。制作模型的一个实例
# all parameters not specified are set to their defaults
logisticRegr = LogisticRegression()
第三步。根据数据训练模型,存储从数据中学习到的信息
模型正在学习数字(x_train)和标签(y_train)之间的关系
logisticRegr.fit(x_train, y_train)
第四步。预测新数据(新图像)的标签
使用模型在模型训练过程中学习到的信息
# Returns a NumPy Array
# Predict for One Observation (image)
logisticRegr.predict(x_test[0].reshape(1,-1))
一次预测多个观察结果(图像)
logisticRegr.predict(x_test[0:10])
对整个测试数据进行预测
predictions = logisticRegr.predict(x_test)
衡量模型性能(数字数据集)
虽然有其他方法来衡量模型性能(精确度、召回率、F1 分数、 ROC 曲线等),但我们将保持简单,使用精确度作为我们的衡量标准。
要做到这一点,我们要看看模型在新数据(测试集)上的表现
精确度定义为:
(正确预测的分数):正确预测/数据点总数
# Use score method to get accuracy of model
score = logisticRegr.score(x_test, y_test)
print(score)
我们的准确率是 95.3%。
混淆矩阵(数字数据集)
混淆矩阵是一个表格,通常用于描述一个分类模型(或“分类器”)对一组真实值已知的测试数据的性能。在这一节中,我将展示两个 python 包(Seaborn 和 Matplotlib ),它们使混淆矩阵更容易理解,在视觉上更有吸引力。
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import metrics
下面的混淆矩阵在视觉上并不丰富,也不吸引人。
cm = metrics.confusion_matrix(y_test, predictions)
print(cm)
Not a visually appealing way to view a confusion matrix
方法 1(海上分娩)
正如你在下面看到的,这个方法使用 seaborn 产生了一个更容易理解和视觉可读的混淆矩阵。
plt.figure(figsize=(9,9))
sns.heatmap(cm, annot=True, fmt=".3f", linewidths=.5, square = True, cmap = 'Blues_r');
plt.ylabel('Actual label');
plt.xlabel('Predicted label');
all_sample_title = 'Accuracy Score: {0}'.format(score)
plt.title(all_sample_title, size = 15);
Confusion Matrix using Seaborn
方法 2 (Matplotlib)
这个方法显然多了很多代码。我只是想向人们展示如何在 matplotlib 中也这样做。
plt.figure(figsize=(9,9))
plt.imshow(cm, interpolation='nearest', cmap='Pastel1')
plt.title('Confusion matrix', size = 15)
plt.colorbar()
tick_marks = np.arange(10)
plt.xticks(tick_marks, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], rotation=45, size = 10)
plt.yticks(tick_marks, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], size = 10)
plt.tight_layout()
plt.ylabel('Actual label', size = 15)
plt.xlabel('Predicted label', size = 15)
width, height = cm.shapefor x in xrange(width):
for y in xrange(height):
plt.annotate(str(cm[x][y]), xy=(y, x),
horizontalalignment='center',
verticalalignment='center')
Confusion Matrix using Matplotlib
逻辑回归(MNIST)
需要强调的一点是,sklearn 中包含的数字数据集太小,不能代表真实世界的机器学习任务。
我们将使用 MNIST 数据集,因为它是为那些希望在真实世界数据上尝试学习技术和模式识别方法,同时在预处理和格式化方面花费最少精力的人准备的。我们将注意到的一件事是,参数调整可以大大加快机器学习算法的训练时间。
下载数据(MNIST)
MNIST 数据集并非来自 scikit-learn 内部
from sklearn.datasets import fetch_mldata
mnist = fetch_mldata('MNIST original')
现在您已经加载了数据集,您可以使用下面的命令
# These are the images
# There are 70,000 images (28 by 28 images for a dimensionality of 784)
print(mnist.data.shape)# These are the labels
print(mnist.target.shape)
要查看数据集中有 70000 张图像和 70000 个标签
将数据分成训练集和测试集(MNIST)
下面的代码执行了一次列车测试分割。test_size=1/7.0
使训练集大小为 60,000 幅图像,测试集大小为 10,000 幅图像。
from sklearn.model_selection import train_test_splittrain_img, test_img, train_lbl, test_lbl = train_test_split(
mnist.data, mnist.target, test_size=1/7.0, random_state=0)
显示图像和标签(MNIST)
import numpy as np
import matplotlib.pyplot as pltplt.figure(figsize=(20,4))
for index, (image, label) in enumerate(zip(train_img[0:5], train_lbl[0:5])):
plt.subplot(1, 5, index + 1)
plt.imshow(np.reshape(image, (28,28)), cmap=plt.cm.gray)
plt.title('Training: %i\n' % label, fontsize = 20)
Visualizing the Images and Labels in our Dataset
sci kit-学习 4 步建模模式(MNIST)
我想提到的一点是参数调整的重要性。虽然对于较小的数字数据集来说,这可能没什么关系,但对于较大和更复杂的数据集来说,这就有很大的不同了。虽然通常是为了精确而调整参数,但在下面的例子中,我们调整了参数求解器以加速模型的拟合。
第一步。导入您想要使用的模型
在 sklearn 中,所有的机器学习模型都是作为 Python 类实现的
from sklearn.linear_model import LogisticRegression
第二步。制作模型的一个实例
如果你想知道变化求解器是做什么的,请看这个教程。本质上,我们正在改变优化算法。
# all parameters not specified are set to their defaults
# default solver is incredibly slow thats why we change it
logisticRegr = LogisticRegression(solver = 'lbfgs')
第三步。根据数据训练模型,存储从数据中学习到的信息
模型正在学习 x(数字)和 y(标签)之间的关系
logisticRegr.fit(train_img, train_lbl)
第四步。预测新数据(新图像)的标签
使用模型在模型训练过程中学习到的信息
# Returns a NumPy Array
# Predict for One Observation (image)
logisticRegr.predict(test_img[0].reshape(1,-1))
一次预测多个观察结果(图像)
logisticRegr.predict(test_img[0:10])
对整个测试数据进行预测
predictions = logisticRegr.predict(test_img)
衡量模型性能(MNIST)
虽然有其他方法来衡量模型性能(精确度、召回率、F1 分数、 ROC 曲线等),但我们将保持简单,使用精确度作为我们的衡量标准。
为此,我们将观察模型在新数据(测试集)上的表现
精确度定义为:
(正确预测的分数):正确预测/数据点总数
score = logisticRegr.score(test_img, test_lbl)
print(score)
我想简单提一下的一件事是,默认的优化算法参数是solver = liblinear
,它花了 2893.1 秒运行,准确率为 91.45%。我设置solver = lbfgs
的时候,用了 52.86 秒运行,准确率 91.3%。改变求解器对精确度有一个小的影响,但至少它快了很多。
Depending on the problem, some optimization algorithms can take longer (image source)
显示带有预测标签的错误分类图像(MNIST)
虽然我可以展示另一个混淆矩阵,但我认为人们宁愿看到错误分类的图片,也不希望有人觉得有趣。
获取错误分类图像的索引
import numpy as np
import matplotlib.pyplot as pltindex = 0
misclassifiedIndexes = []
for label, predict in zip(test_lbl, predictions):
if label != predict:
misclassifiedIndexes.append(index)
index +=1
使用 matplotlib 显示错误分类的图像和图像标签
plt.figure(figsize=(20,4))
for plotIndex, badIndex in enumerate(misclassifiedIndexes[0:5]):
plt.subplot(1, 5, plotIndex + 1)
plt.imshow(np.reshape(test_img[badIndex], (28,28)), cmap=plt.cm.gray)
plt.title(‘Predicted: {}, Actual: {}’.format(predictions[badIndex], test_lbl[badIndex]), fontsize = 15)
Showing Misclassified Digits
结束语
这里需要注意的重要一点是,在 scikit-learn 中制作一个机器学习模型并不需要很多工作。我希望这篇文章对你正在做的事情有所帮助。我的下一个机器学习教程使用 Python 复习了 PCA。如果你对本教程有任何问题或想法,欢迎在下面的评论中,通过 YouTube 视频页面,或通过 Twitter 联系我们!如果想学习其他机器学习算法,请考虑上我的机器学习 with Scikit-Learn LinkedIn 学习课程。
逻辑回归的“Logit ”;了解基本原理
在我学习机器学习基础的旅程的最开始,我记得花了很多时间来清楚地理解逻辑回归的基础。希望这个冥想会给你留下更多的答案和正确的概念,而不是与逻辑回归相关的困惑。
在这篇文章中,我将尝试涵盖—
- 赔率和赔率比
- 理解逻辑回归,从线性回归开始。
- 逻辑函数作为分类器;用伯努利分布连接 Logit。
- 关于癌症数据集和设置概率阈值以对恶性和良性进行分类的示例。
优势和优势比
在我们深入研究逻辑回归之前,我们需要弄清楚一些概率的基础知识。为简单起见,我们将考虑一个数据集,它告诉我们,客户是否会购买产品取决于性别。我们导入并检查数据集
import pandas as pdgender_df = pd.read_csv('gender_purchase.csv')print gender_df.head(3)>>> Gender Purchase
0 Female Yes
1 Female Yes
2 Female No
我们将使用pandas
的crosstab
功能,根据性别创建一个“是”和“否”的频率表。这张表对理解以后的优势和优势比有很大的用处。
table = pd.crosstab(gender_df['Gender'], gender_df['Purchase'])
print table>>> Purchase No Yes
Gender
Female 106 159
Male 125 121
我们现在准备定义几率、 几率,它描述了成功与失败的比率。考虑到女性群体,我们看到女性购买(成功)产品的概率= 159/265(是/女性总数)。女性失败(不购买)的概率为 106/265。在这种情况下,赔率定义为(159/265)/(106/265) = 1.5。可能性越大,成功的机会就越大。赔率范围可以是【0,∞】*之间的任意数字。*如果我们对这些数字取自然对数,范围会发生什么变化?log(x)定义为 x≥0,但范围从[-∞,∞]变化。您可以使用一段代码进行检查
random=[]
xlist = []
for i in range(100):
x = uniform(0,10)# choose numbers between 0 and 10
xlist.append(x)
random.append(math.log(x))plt.scatter(xlist, random, c='purple',alpha=0.3,label=r'$log x$')
plt.ylabel(r'$log \, x$', fontsize=17)
plt.xlabel(r'$x$',fontsize=17)
plt.legend(fontsize=16)
plt.show()
Figure 1: log x vs x; for all +’ve’ values of x, log x can vary between -∞ to + ∞.
到目前为止,我们已经理解了概率。我们来描述一下赔率,顾名思义就是赔率的比值。考虑到上面的例子,比值比,代表哪一组(男性/女性)有更好的成功几率,它是通过计算每一组的比值比给出的。所以女性成功购买的几率=女性成功购买的几率/男性成功购买的几率= (159/106)/(121/125)。男性的优势比是上述数字的倒数。
我们可以清楚地认识到,虽然比值比可以在 0 到正无穷大之间变化,但 log(比值比)将在[-∞,∞]之间变化。特别是当比值比位于[0,1]之间时,log(比值比)为负。
线性到逻辑回归
由于“回归”一词在逻辑回归中容易引起混淆,我们可以花几秒钟来回顾一下回归。回归通常指连续性,即预测连续变量(药品价格、出租车费等。)取决于特性。然而,逻辑回归是关于预测二元变量,即当目标变量是分类变量时。 *逻辑回归可能是一个初露头角的数据科学家应该尝试掌握分类问题的第一件事。*我们将从线性回归模型开始,逐步理解实现 logistic 模型。
在线性回归中,特征变量可以取任何值,因此输出(标签)可以从负到正无穷大连续。
Range of label and feature in linear regression case
因为逻辑回归是关于分类的,即 Y 是分类变量。很明显,用线性回归模型(方程式)不可能获得这样的输出。1.1),因为两侧量程不匹配。我们的目标是以这样的方式变换 LHS,使得它匹配 RHS 的范围,RHS 的范围由特征变量的范围[-∞,∞]来控制。
我们将遵循一些直观的步骤来探索如何可能达到这样的结果。
- 对于线性回归, X 和 Y 的范围都是从负无穷大到正无穷大。逻辑中的 Y 是绝对的,或者对于上面的问题,它取两个不同值 0,1 中的一个。首先,我们尝试使用回归模型预测概率。现在 LHS 可以取从 0 到 1 的任何值,而不是两个不同的值,但是范围仍然不同于 RHS。
- 我上面讨论过,赔率和赔率比从[0,∞]不等。这比概率(限制在 0 和 1 之间)更好,并且更接近匹配 RHS 的范围。
- 你们中的许多人已经明白,如果我们现在考虑(等式)的 LHS 的自然对数。1.3)那么两侧的范围匹配。
这样,我们实现了一个回归模型,其中输出是概率的自然对数,也称为 logit 。对数的底数并不重要,但取赔率的对数才重要。
我们可以从 eq 中检索成功的概率。1.4 如下。
From odds to probability where probability distribution resembles a sigmoid function
如果我们知道自变量的系数 X s 和截距 a,我们就可以预测概率。我们将使用软件(sklearn
)进行优化。根据问题,我们可以从概率值中选择输出属于 A 类还是 b 类。当我们通过一个示例时,这将更加清楚。
逻辑函数
如果你看到等式 1.5 的 RHS。也称为逻辑函数,与 sigmoid 函数非常相似。我们可以用一小段 python 代码来检查这个函数的行为。
random1=[]
random2=[]random3=[]xlist = []
theta=[10, 1,0.1]
for i in range(100):
x = uniform(-5,5)
xlist.append(x)
logreg1 = 1/(1+math.exp(-(theta[0]*x)))
logreg2 = 1/(1+math.exp(-(theta[1]*x)))
logreg3 = 1/(1+math.exp(-(theta[2]*x)))
random1.append(logreg1)
random2.append(logreg2)
random3.append(logreg3)plt.scatter(xlist, random1, marker='*',s=40, c='orange',alpha=0.5,label=r'$\theta = %3.1f$'%(theta[0]))
plt.scatter(xlist, random2, c='magenta',alpha=0.3,label=r'$\theta = %3.1f$'%(theta[1]))
plt.scatter(xlist, random3, c='navy',marker='d', alpha=0.3,label=r'$\theta = %3.1f$'%(theta[2]))plt.axhline(y=0.5, label='P=0.5')
plt.ylabel(r'$P=\frac{1}{1+e^{-\theta \, x}}$', fontsize=19)
plt.xlabel(r'$x$',fontsize=18)
plt.legend(fontsize=16)
plt.show()
Figure 2: Probability vs independent variable x; resembles sigmoid function plot.
从上面的图中,注意自变量(这里是 X )的系数(橙色星星)值越高,它就能更好地表示两个不同的概率 0 和 1。对于较低的系数值,它基本上是一条直线,类似于一个简单的线性回归函数。对比等式(1.5),图 2 中固定项 a 取为 0。固定项对逻辑函数的影响也可以通过下图来理解
Figure 3: Sigmoid function for different values of intercept (a).
就像线性回归中的常数项表示 Y 轴上的截距(因此沿 Y 轴移动),这里对于逻辑函数,常数项沿 X 轴移动 s 曲线。上面的数字(图 2,3)应该让你相信,使用可以分类数据的逻辑回归来优化模型确实是可能的,例如预测 0 或 1。
伯努利和罗吉特
逻辑回归的目的是针对独立变量(特征)的任何给定线性组合,预测成功事件的某个未知概率 P 。那么如题所示,logit 和 Bernoulli 函数是如何联系的呢?回想一下二项式分布,它是在 N 次试验中有 n 次成功的概率分布,假设
Binomial distribution
每个试验以概率 P 为真,以概率 Q=1-P 为假。伯努利分布另一方面是一个离散分布,有两种可能的结果,标记为 n=0 和 n=1 ,其中 n=1 (成功事件)以概率 P 发生,而失败即 n=0 以概率发生
Bernoulli distribution as a special case of binomial distribution
可以理解的是,伯努利分布是单次试验的二项分布的特例(等式 1.6 中 N=1 )。**最重要的是,我们看到逻辑回归中的因变量遵循具有未知概率 p 的伯努利分布。因此,logit,即几率的对数,将自变量( Xs )与伯努利分布联系起来。**在 logit 情况下,P 是未知的,但是在伯努利分布(eq。1.6)我们知道。让我们画出 logit 函数。
Figure 4: Logit Function i.e. Natural logarithm of odds
我们看到函数的定义域位于 0 和 1 之间,函数的范围从负到正无穷大。我们需要逻辑回归的 y 轴上的概率 P ,这可以通过取 logit 函数的反函数来实现。如果你以前注意过 sigmoid 函数曲线(图 2 和图 3),你可能已经找到了联系。的确, sigmoid 函数是 logit 的逆(检查等式。1.5).
癌症数据集和概率阈值的例子
不再拖延,让我们看看逻辑回归在癌症数据集上的应用。这里我们将集中讨论如何设置概率阈值来对我们的模型进行分类。为了简单起见,我将使用数据集的所有特征,但你可以阅读关于使用RFE
方法选择最佳特征的详细信息,我已经在单独的帖子中描述了该方法。
from sklearn.datasets import load_breast_cancercancer = load_breast_cancer()
cancer_df=pd.DataFrame(cancer.data,columns=cancer.feature_names)X_trainc, X_testc, y_trainc, y_testc = train_test_split(cancer.data, cancer.target, test_size=0.3, stratify=cancer.target, random_state=30)cancerclf = LogisticRegression()
cancerclf.fit(X_trainc, y_trainc)#print "Logreg score on cancer data set", cancerclf.score(X_testc, y_testc) # you can check the score if you want, which is not the main purpose.
我们将使用predict_proba
方法进行逻辑回归,引用 scikit-learn 的话“返回按类别标签排序的所有类别的概率估计值”。我们在测试数据集上调用这个方法。
probac = cancerclf.predict_proba(X_testc)print probac[1:10] >>> [[5.86216203e-02 9.41378380e-01]
[7.25210884e-03 9.92747891e-01]
[9.99938102e-01 6.18983128e-05]
[4.75502091e-02 9.52449791e-01]
[9.66861480e-01 3.31385203e-02]
[3.09660805e-01 6.90339195e-01]
[9.99687981e-01 3.12018784e-04]
[6.80759215e-04 9.99319241e-01]
[9.99998223e-01 1.77682663e-06]]
由于我们的目标要么是 0,要么是 1,那么打印predict_proba
会给我们维数为(N,2)的概率矩阵,N 是实例的数量。第一个指标指的是数据属于类 0 的概率,第二个指标指的是数据属于类 1 的概率。默认情况下,如果该概率大于 0.5,则该预测被归类为正面结果。对于每一行,两列相加应该等于 1,因为成功的概率 § 和失败的概率 (1-P) 应该等于 1。
我们现在可以转向predict
方法,它预测类别标签,在默认情况下,对于二元分类,它将小于 0.5 的概率归类为 0,反之亦然。
predict = cancerclf.predict(X_testc)print predict >>> [1 1 1 0 1 0 1 0 1 0 1 1 1 1 .....]# didn't show the complete list
现在我们考虑probac=cancerclf.predict_proba(X_testc)
数组的第一列,它由 0 类概率组成(在癌症数据集中,这是恶性类)。我们用这个数组做了一个迷你数据框。
probability = probac[:,0]
prob_df = pd.DataFrame(probability)
print prob_df.head(10) # this should match the probac 1st column >>> 0
0 0.005366
1 0.058622
2 0.007252
3 0.999938
4 0.047550
5 0.966861
6 0.309661
7 0.999688
8 0.000681
9 0.999998
我们进一步修改这个数据帧,以理解改变阈值的影响。
prob_df['predict'] = np.where(prob_df[0]>=0.90, 1, 0)# create a new column
print prob_df.head(10)>>> 0 predict
0 0.005366 0
1 0.058622 0
2 0.007252 0
3 0.999938 1
4 0.047550 0
5 **0.966861 1**
6 0.309661 0
7 0.999688 1
8 0.000681 0
9 0.999998 1
我们设定≥ 90%作为恶性分类选择的阈值。在打印出的示例中,我们看到值为 0.96,因此将阈值更改为 97%会将该样本从恶性类别中排除。
prob_df['predict'] = np.where(prob_df[0]>=0.97, 1, 0)
print prob_df.head(10)>>> 0 predict
0 0.005366 0
1 0.058622 0
2 0.007252 0
3 0.999938 1
4 0.047550 0
5 **0.966861 0 # here is the change**
6 0.309661 0
7 0.999688 1
8 0.000681 0
9 0.999998 1
还可以检查对测试样本总数的影响
prob_df['predict'] = np.where(prob_df[0]>=0.50 1, 0)
print len(prob_df[prob_df['predict']==1])>>> 56prob_df['predict'] = np.where(prob_df[0]>=0.97 1, 0)
print len(prob_df[prob_df['predict']==1])>>> 45
我们已经看到如何改变概率阈值来选择或拒绝来自特定类别的样本。
逻辑回归默认使用 L2 正则化,可以检查改变正则化参数的结果,并与线性回归进行比较。我之前和岭回归讨论过这个问题,感兴趣的可以去看看。使用RFE
选择最佳参数是逻辑回归的一个重要部分,因为最好有很少或没有多重共线性,这是确保选择少量可以描述模型的相关参数的方法之一。
总而言之,我们已经学习了一些关于开发可用于分类的回归模型的基本思想。
我推荐你去看看吴恩达的课堂笔记或者 YouTube 上的讲座。本帖的基本思想受到了 Kumar,a .的《用 Python 学习预测分析》一书的影响,该书明确描述了线性和逻辑回归的联系。将伯努利函数和 logit 函数之间的联系联系起来是受 B. Larget (UoW,麦迪森)的演示幻灯片的启发,该幻灯片可公开获得。
保持坚强,干杯!
如果你对更深入的基础机器学习概念感兴趣,可以考虑加盟 Medium 使用 我的链接 。你不用额外付钱,但我会得到一点佣金。感谢大家!!
使用 SSD 的图像中的徽标检测
徽标有时也称为商标,在当今的营销世界中非常重要。产品、公司和不同的游戏联盟通常由它们各自的标志来识别。图像和视频中的徽标识别是许多应用中的关键问题,例如版权侵权检测、智能交通控制系统的车辆徽标、增强现实、上下文广告投放等。在本帖中,我们将探讨如何使用 Tensorflow API 的 SSD 来检测和定位电视节目(Big Boss India)图像中的品牌徽标。任务是从展会的图像中检测和定位六个品牌标志: fizz,oppo,samsung,garnier,faber,cpplus 。
什么是固态硬盘,它是如何工作的?
根据关于 SSD 的论文,SSD: Single Shot Multibox Detector 是一种使用单一深度神经网络检测图像中对象的方法。SSD 将边界框的输出空间离散化为一组默认框,每个要素地图位置具有不同的纵横比和比例。在预测时,网络为每个默认框中每个对象类别的存在生成分数,并对框进行调整以更好地匹配对象形状。此外,该网络结合了来自不同分辨率的多个特征地图的预测,以自然地处理各种尺寸的物体。在 PASCAL VOC、COCO 和 ILSVRC 数据集上的实验结果证实,SSD 具有与利用额外的对象提议步骤的方法竞争的准确性,并且速度快得多,同时为训练和推理提供了统一的框架。
目标检测、定位和分类的任务在网络的单次前向传递中完成。
Multi box concept in SSD(Source: Udemy A-Z Computer Vision)
固态硬盘的架构
标志检测数据集
这项任务的数据是通过从节目的视频剪辑中捕捉单个帧获得的。总共拍摄了 6267 张图像。我用了 600 张图片进行测试,剩下的用于训练部分。
现在,下一步是注释获得的图像。为此,我使用了 LabelImg 。LabelImg 是一个图形化的图像注释工具。生成的注释以 PASCAL VOC 格式保存为 XML 文件。存储库中提供了安装说明。
Annotating Image using labelImg
类似地,我必须浏览数据集的所有图像,并逐个注释它们。
TFRecords
如果我们正在处理大型数据集,使用二进制文件格式存储数据会对导入管道的性能产生重大影响,从而缩短模型的训练时间。二进制数据占用的磁盘空间更少,复制时间更短,从磁盘读取的效率也更高。这就是 TFRecord 出现的地方。然而,纯粹的性能并不是 TFRecord 文件格式的唯一优势。它通过多种方式针对 Tensorflow 的使用进行了优化。首先,它可以轻松地组合多个数据集,并与库提供的数据导入和预处理功能无缝集成。特别是对于太大而无法完全存储在内存中的数据集,这是一个优势,因为只有当时需要的数据(例如一批)才会从磁盘加载,然后进行处理。因为我们将使用 Tensorflow API,所以我们将把 XML 文件转换成 TFRecords。
将 XML 转换为 TFRecord
为了将 XML 文件转换成 TFRecord,我们将首先使用 python 脚本将它们转换成 CSV,这要感谢这个库。需要引入一些小的变化。下面是将 XML 文件转换成 CSV 文件的代码。
存储在**‘图像/训练’和‘图像/测试’**中的 XML 文件被转换成两个 CSV 文件,一个用于训练,一个用于测试,它们在文件夹【T8’‘数据’中生成。(如果您想要在自定义数据集上训练 SSD 模型,请注意这些细节)
一旦 XML 文件被转换成 CSV 文件,我们就可以使用 python 脚本从同一个存储库中输出 TFRecords,并做一些修改。
对于自定义数据集的训练,请在 class_text_to_int 函数中更改类名。此外,确保您按照这里的中的安装说明来安装依赖项,以运行上面的代码。同样克隆 tensorflow 存储库。以后会有帮助的。
一旦完成安装,我们就可以使用上面的代码片段生成 tfrecords 了。在您的终端中键入这个命令,为训练数据生成 tfrecord。
python generate_tfrecord.py — csv_input=data/train_labels.csv — output_path=data/train.record
啊终于来了!!我们有我们的 train.record。同样地,对测试数据也这样做。
python generate_tfrecord.py — csv_input=data/test_labels.csv — output_path=data/test.record
训练品牌标识检测器
为了获得我们的品牌徽标检测器,我们可以使用预先训练的模型,然后使用迁移学习来学习新对象,或者我们可以完全从头开始学习新对象。迁移学习的好处是训练可以快得多,你可能需要的数据也少得多。出于这个原因,我们将在这里进行迁移学习。TensorFlow 有相当多的预训练模型,带有可用的检查点文件和配置文件。
对于这个任务,我使用了 Inception 。你可以使用其他型号。你可以从这里获得模型列表及其下载链接。点击此处,获取相应型号的配置文件。现在,我们已经完成了模型和配置文件的下载,我们需要根据数据集编辑配置文件。
在您的配置文件中搜索“ PATH_TO_BE_CONFIGURED ,并将其更改为类似于上面代码片段中所示的内容。此外,更改配置文件中的类的数量。
在我们开始训练之前,还有最后一件事要做,就是创建标签图。标签映射基本上是一个字典,包含我们想要检测的类的 id 和名称。
detection.pbtxt
就是这样。就是这样。我们现在可以开始训练了。啊终于来了!
将您的所有数据复制到系统上克隆的 tensorflow 存储库(如果您之前没有,请克隆它)。并从’**models/object _ detection '**中在您的终端中键入此命令。
python3 train.py --logtostderr --train_dir=training/ --pipeline_config_path=training/ssd_inception_v2_coco_2017_11_17.config
可以等到总损失达到 1 左右。
测试品牌标志检测器
为了测试我们的模型做得有多好,我们需要导出推理图。在’models/object _ detection’目录中,有一个脚本为我们完成了这项工作:‘export _ inference _ graph . py’
要运行它,您只需要传入您的检查点和您的管道配置。你的检查点文件应该在’ training '目录下。只要找一个步长最大的(破折号后最大的数字),那就是你要用的。接下来,确保将 pipeline_config_path 设置为您选择的任何配置文件,然后最后选择输出目录的名称。例如:
python3 export_inference_graph.py \
--input_type image_tensor \
--pipeline_config_path training/ssd_inception_v2_coco_2017_11_17.config \
--trained_checkpoint_prefix training/model.ckpt-7051 \
--output_directory logos_inference_graph
一旦成功运行,您应该有一个名为’ logos_inference_graph ‘的新目录。在此之后,打开’object _ detection _ tutorial . ipynb,将’ MODEL_NAME 更改为’ logos_inference_graph ,并更改变量部分中的类的数量。接下来,我们可以删除笔记本中的整个下载模型部分,因为我们不再需要下载我们的模型。在’ Test_Images_Path '中,您可以输入存储测试图像的目录。
结果
以下是我的一些结果:
Samsung logo detected
Fizz logo detected
Cpplus logo detected
总结
为了检测图像中的徽标,我遵循了以下步骤:
- 获取数据集
- 使用 LabelImg 创建 XML 文件
- 将 XML 文件转换为 TFRecords
- 下载模型并编辑相应的配置文件
- 创建标注地图
- 开始训练
参考文献
- https://arxiv.org/pdf/1512.02325.pdf
- https://github.com/tensorflow/tensorflow
- https://python programming . net/introduction-use-tensor flow-object-detection-API-tutorial/
- https://github.com/tzutalin/labelImg
- https://github.com/datitran/raccoon_dataset
- https://medium . com/mosely-ai/tensor flow-records-what-them-and-how-to-use-them-c 46 BC 4 BBB 564
- https://towards data science . com/understanding-SSD-multi box-real-time-object-detection-in-deep-learning-495 ef 744 fab
如果你喜欢,请随意评论你的观点并鼓掌。
2018 伦敦设计节(第二部分):自然语言处理
第二部分:11,000 条推文的自然语言处理
介绍
在本系列的第 1 部分中,我对 2018 年伦敦设计节的 11,000 条推文进行了探索性的数据分析,这是一个为期七天的设计节,发生在 2018 年 9 月 15 日周六至 23 日周日之间。
伦敦设计节 2018 (LDF18)有一个非常活跃的活动计划,横跨伦敦 11 个不同的“设计区”、5 个“设计目的地”和 3 条“设计路线”。这是伦敦作为一个建筑环境的灵活性的另一个极好的例子,作为一个画布来展示创造性的想法。
本文的目的是介绍我的自然语言处理分析对这 11,000 条推文的研究结果,以了解情绪以及人们对 LDF18 的看法。
请向下滚动,通过交互式数据可视化查看我的分析!
Image by Ben Terrett on Flickr
数据和方法
这一事件的官方标签是#LDF18。在通过 Twitter API 在事件发生时收集了 11000 条包含这个标签的推文之后,我首先在 Python 笔记本中预处理和清理了文本数据。
然后,我使用谷歌的 langdetect 库 过滤掉非英语推文,并从 NLP 分析中删除所有转发,这样就不会出现重复。经过这些步骤,我剩下了 5700 条独特的推文。接下来,我使用谷歌云自然语言 API 来获取每条推文的情感。
最后,我使用 gensim 库的 Word2Vec 模型来获取整个 tweets 语料库中与单词“LDF18”相关的每个单词的单词嵌入向量。Word2Vec 用于从大型文本语料库中计算单词之间的相似度— Kavita Ganesan 的文章是一个很好的解释。
一旦我有了每个单词的向量,我就使用 scikitlearn 库来执行主成分分析(PCA)以进行降维,并绘制出与“LDF18”最相似的单词(最近邻)。
你可以在这里查看我的 Kaggle 内核对这篇文章的所有分析。
分析推文
在这一节中,我将展示我的自然语言处理(NLP)分析的发现。下面,我报告以下三个指标:
- 每日推文的情感分析;
- 词频和标签频率分析;
- Word2Vec 模型的输出:主成分分析(PCA)和最近邻分析。
Alphabet by Kellenberger White Photography by @leemawdsley 3— Taken from Flickr
情感分析
每条推文的情绪是使用谷歌的云 NLP API 计算的。下面的条形图显示了每天推文的平均情绪,其中-1 表示非常消极的情绪,+1 表示非常积极的情绪。
我们看到,LDF18 开始时的平均情绪相对较低,随着时间的推移逐渐上升。9 月 18 日星期二,也就是奖牌获得者晚宴后的第二天,出现了 0.53 的峰值——人们显然对此很高兴!
Figure 1: Line chart showing the average sentiment of the tweets per day
下表显示了按情感分类的前五条(绿色)和后五条(红色)推文。你可以通过左边的推文清楚地看到,积极的语言被云 NLP API 检测到,类似地,负面的推文在右边。
许多积极的推文是关于设计奖的奖牌获得者,还有那周举行的晚宴…小吃很棒,我会让你知道的!
LDF18 上展示的一些装置是关于塑料垃圾和气候变化的,不幸的是,NLP API 将提到这些装置的推文归类为“负面”;这凸显了情绪分析 API 的一些问题。
Table 1: Tabel showing the top five (left) and bottom five (right) tweets by sentiment score
文本频率分析
下面的条形图显示了一个词出现的次数,还有一个标签出现在所有推文中,分别在左边和右边。不出所料,“ldf18”出现的次数最多。
然而,这些结果在告诉我们人们对该事件的看法方面并不十分有用,因为标签的频率显然是单词频率的一个混淆变量。在未来的分析中,我将从文本频率分析中删除 hashtag 单词。
Figure 2: Bar graphs showing the count of words and hashtags appearing in all the tweets
最近的邻居
Word2Vec 是神经语言机器学习模型。它将大量文本(在本例中,来自 11,000 条推文的文本)作为输入,并产生一个向量空间,通常有数百个维度,每个唯一的单词对应于空间中的一个向量——单词嵌入。然后使用主成分分析将 Word2Vec 空间的维度降低到 x 和 y 坐标。
重要的是,Word2Vec 用于从 11,000 条推文中捕捉单词之间的相似性和关系。具体来说,空间中距离较近的对象意味着它们是相似的。“最近邻”是来自 Word2Vec 模型的少数几个基于余弦度量相似性得分与“LDF18”最相似的单词。
Figure 3: PCA output of the nearest neighbours of #LumiereLDN from the Word2Vec model
散点图显示了“LDF18”的最近邻。我们看到诸如“建筑”、“工艺”、“纺织品”和“设计”等名词是密切相关的。
但重要的是,形容词“漂亮”、“创新”、“灵感”也是密切相关的。一个非常积极的结果!统计表明,这些词最能代表人们在推特上谈论 LDF18 时的感受。
Waugh Thistleton Architects: MultiPly —Taken from Flickr — All rights reserved by the London Design Festival
结论
所以你有它!我在 11,000 条关于 2018 年伦敦设计节的推文中展示了我的 NLP 的调查结果。Word2Vec 模型的输出显示,人们对该事件持积极态度。
如果你有任何想法或建议,请在下面或在我的 Kaggle 内核上留下评论——如果能给 Kaggle 投票,我将不胜感激:)
有这么多的 NLP 库,我很可能会在未来使用 GloVe 、 Tensorflow 或 Bert 重新审视这个分析。
下次…
在我的下一篇文章(第 3 部分)中,我将展示我的计算机视觉分析的发现。期待看到哪些艺术品出现的次数最多。敬请关注。
感谢阅读!
Vishal
在你离开之前…
如果你觉得这篇文章有帮助或有趣,请在 Twitter、脸书或 LinkedIn 上分享这篇文章,这样每个人都能从中受益。
Vishal 是一名文化数据科学家,也是伦敦 UCL 学院的研究生。他对城市文化的经济和社会影响感兴趣。你可以在Twitter或者LinkedIn上与他取得联系。在insta gram或他的 网站 上看到更多 Vishal 的作品。
基于 GARCH 模型的长期资产配置策略——R
在这篇文章中,我想分享我在量化金融领域做的一个模拟练习的结果。我所遵循的方法是基于金融模型的(因此,一些定量金融知识肯定会使它更容易理解),但是,对于专注于数据科学的人来说,这篇文章可能会很有趣,因为我展示了一个如何使用并行蒙特卡罗模拟来预测股票价格的示例。
在这个练习中,我建立了一个基于资产价格预测的简化资产配置策略。为了预测资产价格,我使用了条件波动率模型,其中的自回归成分决定了回报过程的条件均值部分。
我只在媒体上发布一个缩略版本。我强烈推荐阅读我在 GitHub 上分享的更详细的“论文”(以及参考资料)。
1.方法学
数据生成过程
在量化金融中,处理资产回报是很常见的,可以定义为
其中 P 代表资产价格, t 是时间指数。以下等式表示实验中的数据生成过程:
随着
条件均值方程(第一个方程)由具有一阶滞后的自回归过程控制,条件方差方程是 Glosten、Jagannathan 和 Runkle (1993)的 GJR-GARCH 模型。它是 Bollerslev(1986 年)著名的 GARCH (广义自回归条件异方差 ) 模型的扩展,具有考虑正负创新对方差影响不同的情况的额外优势。换句话说,参数 alpha 衡量积极创新的效果,而 alpha + gamma 用于消极创新的情况。GARCH 模型是通过将 GJR-GARCH 的 gamma 设置为 0 得到的。
数据生成过程基于奥尔巴克(2013)提供的规范。然而,这个实验使用他的规范集中于股票收益的点预测和相关的方差,而没有建模更高的矩(偏度和峰度)。
在此分析中,GARCH 和 GJR-GARCH 模型均被考虑在内,并考虑了新息的以下分布( z_t ):正态分布(N)、偏态分布(SN)、 t (T)、偏态分布- t (ST)、广义误差分布(GED)及其偏态分布(SGED)。
此外,我采用了三种评估方法:固定、滚动和扩展窗口方法。对于固定模型,我在估计样本上估计 GARCH 模型,并在整个样本外预测中使用相同的参数集。在滚动方法中,我滚动长度等于整个估计样本的窗口,一次一个周期,而在扩展窗口方法中,我简单地扩展估计样本。
总之,固定窗口方法总是使用相同的数据集,滚动窗口使用相同数量但来自不同时段的数据,而扩展窗口使用最大量的数据。因此,我调查了 GARCH 模型类型、新息分布和估计变量的总共 36 种组合。
模拟样本路径
我通过模拟选定股票收益的长度为 K 周期的 N 条样本路径来解决长期资产配置问题。我遵循插入式方法,,即,我是在分布参数已知的假设下操作的。为了获得这些(以及初始化模拟所需的时间 T_0 新息和条件方差等变量),我使用 MLE 估计所有规格的选定 GARCH 模型,并实施估计的参数以从选定的分布中生成随机新息。更准确地说,我生成了 N * K 随机新息,其中范围 K 从 1 到 52,取决于模拟的时间点。
动态资产分配问题
在这个实验中,我只选择了一个股票指数,并以 1%的网格步长将权重限制在 0%到 100%之间,这是由于使用数值方法时的维数灾难。随着当今计算能力和云解决方案的快速增长,将其扩展到多资产框架应该不成问题。然而,我会关注研究论文,目前只关注单一风险资产。
因为建模无风险利率不是这个项目的目标,所以我让它随着时间的推移保持不变,并且等于估计期间无风险利率的平均值(它是-0.0819%)。
此外,我假设投资者面临的投资期限为 K 期,他的分配期开始于时间 T_0 。他使用估计样本(截至时间点 T_0 的数据)估计一个考虑的模型,并指定他的最优投资组合权重 w_{T_0} 。然后,他进行到时间段 T_0 + 1 ,因此在滚动/扩展窗口改变信息集的情况下,能够用更新的估计样本重新估计所考虑的模型。通过在时间上前进一个周期,他的投资范围减少到 K - 1 。在时段 T_0 + K - 1 中,他的范围等于 1,并且他可以使用直到该点的所有可用数据来根据估计方法选择他的最后分配权重。通过所述过程获得的组合权重序列 K 导致一个最终财富值 w_{T_0 + K} 。我遵循类似于 Barberis (2000)提出的方法。投资者的偏好由 CRRA(常数相对风险厌恶)幂效用函数描述。初始财富归一化为 1。我直接优化幂效用函数来获得最优权重。
请注意,投资者的问题可以描述为最大化以下等式:
这意味着投资者从时间 T_0 开始,最大化终端财富(W)总体决策。
近似条件期望的一种方法是采用跨路径样本均值:
然而,在这种情况下,这是不可能的,因为不同的路径具有不同的模拟预测变量,这又意味着不同的条件期望。使用的预测变量是:条件方差和滞后模拟回报由于自回归结构的条件平均方程。根据 Brandt 和 van Binsbergen (2007),我使用跨路径 OLS 回归来近似条件期望。跨路径样本均值可用于算法的最后一步。关于后向递归资产配置策略步骤的更详细描述,请参考 Brandt 和 van Binsbergen (2007)的论文。
为长期投资者评估不同规格的表现
先验,我预计具有更复杂创新分布的模型和/或使用滚动/扩展窗口的模型将优于简单模型。因此,我通过与所考虑的模型中的基准模型进行比较来衡量模型的性能。作为一项比较措施,使用了以下修正夏普比率(mSR)
其中m0和sigma 0是基准规格的平均收益和波动率,下标 p 是指比较中更复杂的规格。这种方法的一个缺点是它没有考虑投资组合收益的高阶矩(偏度,峰度)。换句话说,不考虑非正态分布的影响。
2.R 中的解析部分
加载和操作数据
在这个练习中,我使用了标准普尔 500 指数回报,这是一个美国最大的 500 家上市公司的市值加权指数。我之所以选择它,是因为美国市场在全球市场资本总额和交易量中所占的比例是最大的市场,因此它不太可能通过极端行为来推动结果,而这种极端行为可能会在更奇特的数据中出现。
我使用tseries
包中的get.hist.quote()
函数从雅虎财经下载每周收盘价。
从下载的价格,我计算简单的回报。
除了退货系列,我还需要一些外部数据,,即。,无风险利率和通货膨胀。对于无风险利率,我采用联邦基金利率。我还使用 FRED 数据库中的 CPI(消费者价格指数)数据来调整通货膨胀的回报。你也可以在我的 GitHub 上找到这些数据。
我将数据集分成两个子样本:估计样本(覆盖 1988-1999 年,共有 626 个观察值)和评估样本(2000 年,有 52 个观察值)。
下一步是将无风险和通货膨胀的频率从每月一次改为每周一次。
最后,我需要考虑退货系列中的通货膨胀。
汇总统计数据
要注意的第一个重要方面是,评估样本的年化平均回报率为负。在此期间也有较高的方差。这两个特征都会影响资产配置策略的表现。负偏度和过度峰度(高阶矩)符合资产收益的程式化事实,即,资产收益的分布不是高斯分布,可以用厚尾、尖峰(过度峰度效应)、负偏态分布来表征。然而,Jarque-Bera 正态性检验只在估计样本的情况下证实了这一假设。回报中也有一些序列相关性的证据(也是平方回报)。平方收益的相关性意味着二阶矩的时间变化,这也符合资产收益的程式化事实。
运行模拟
在运行模拟之前,我需要准备一个可能组合的网格。这三个类别包括:
- 模型类型:GARCH 或 GJR-GARCH
- 新息分布:高斯分布、偏态高斯分布、 t 、偏态 t 、广义误差分布和偏态 GED
- 估计类型:固定/滚动/扩展窗口
对于 GARCH 模型的估计,我使用了rugarch
包,它包含了所有必要的 GARCH 规范(GJR 变量,以及创新的多重分布)。由于这些计算相当繁重和耗时,我使用doParallel
和foreach
并行运行它们。我做的另一个假设是关于投资者的风险厌恶水平——我只考虑风险厌恶系数lambda = 5
不太厌恶风险的投资者。当然,通过在函数调用中更改参数值,可以很容易地获得其他参数值的结果。为了确保结果稳定,我对每个配置都进行了n = 100000
模拟。
分析结果
本节介绍模拟实验的结果。由于大量的估计变量,我将不包括 GARCH 模型的估计系数。相反,我把重点放在投资组合回报和各种规格之间的比较上。
获得模拟结果后,我计算已实现投资组合回报的汇总统计数据(均值、标准差、偏斜度、峰度和夏普比率)。
人们可以观察到,年化平均投资组合回报是积极的,在绝大多数情况下,高于最简单的高斯创新和固定窗口方法的 GARCH 模型。此外,在大多数情况下,年化标准差低于基准情况,夏普比率高于基准。
下图显示了模拟投资组合回报随时间的演变。对该图的分析得出结论,使用不同的模型规格导致分配策略的某种相似的性能。然而,在一些时期,可以观察到不同的投资组合回报。值得注意的是,通过遵循源于 GARCH 模型的策略,投资者能够获得比单纯投资标准普尔 500 指数(如 2000 年 4 月)更低的负回报。因此,减少了损失。因为关于滚动/扩展窗口估计类型的图可以类比地解释,所以我不在这里附加它们。
最后一步是评估基于更先进模型的资产配置策略如何优于简单的基准。为此,我选择了一个具有固定窗口的高斯 GARCH 模型作为最简单的模型,并将它作为基准。在修正的夏普比率的帮助下完成了对优异性的评估,并且结果呈现在下表中。
可以观察到,当将更复杂的模型规格与简单的基准进行比较时,就修正的夏普比率而言,性能几乎总是更好。固定窗口估计类型和 GED 分布式创新的少数案例表现比基准差,但没有明确的迹象表明其背后的原因。
3.结论
在这个练习中,我研究了投资者是否能从使用不同规格的 AR(1) — (GJR)GARCH 模型准确预测股票收益(以标准普尔 500 指数为例)中获益。因此,我假设投资者的无风险利率和风险厌恶水平不变。实证结果表明,在某些情况下,通过修改夏普比率,使用更复杂的单变量模型会导致更有利可图的资产配置策略。例如,与基准模型相比,具有偏斜 t 分布和扩展窗口估计的(GJR-)GARCH 具有最好的表现。
进一步工作的一些想法:
- 向实验中添加更多资产
- 向条件均值方程添加额外的外生变量(额外来自自回归分量)
- 检查在不同的模型中使用相同的资产配置框架(包含许多可能影响股票价格的变量的回归模型)是否会导致更好的资产配置
这个简短的实验到此结束。如果你对这个问题有任何想法,请告诉我。和往常一样,完整的 R 代码,以及更详细的“研究论文”版本可以在我的 GitHub 上找到。
我最近出版了一本关于使用 Python 解决金融领域实际任务的书。如果你感兴趣,我在贴了一篇文章介绍这本书的内容。你可以在亚马逊或者 Packt 的网站上买到这本书。
参考文献:
- Barberis,N. (2000)回报可预测时的长期投资,金融杂志,55(1),225-264。
- t . bollerslev(1986)广义自回归条件异方差,计量经济学杂志,31(3),307–327。
- Glosten,l .,Jagannathan,R. & Runkle,D. (1993)股票名义超额收益的期望值和波动性之间的关系,金融杂志,48,1779-1801。
- 奥尔巴克,A. (2013)时变高阶矩密度预测:模型置信集方法,预测杂志,32(1),19–31。
- 范宾斯卑尔根,J. H .和 M. W .勃兰特(2007 年)。通过递归优化投资组合权重或价值函数解决动态投资组合选择问题,《计算经济学》, 29(3–4),355–367。
相似之处:大海捞针
合著者:康斯坦丁诺·博萨斯和斯特凡诺·科斯坦蒂尼
在 Schibsted,我们使用数据科学来构建聚合用户行为和偏好的模型。广告商可以将这些结合起来,将用户分组,称为目标细分市场。
取决于它们是如何定义的,其中一些细分市场可能相当小众,限制了它们的覆盖范围。然而,广告商总是在寻找进一步扩大潜在受众的方法。
有什么比找到行为与他们已经瞄准的潜在客户相似的用户更好的呢?可以肯定的是,这些用户会比普通用户更容易接受他们的信息,从而提供了目标明确的受众。我们称这些额外的用户为长相相似的用户。
这听起来很棒,但是我们怎样才能找到他们呢?
我们的出发点是关于用户浏览行为的信息。例如,我们收集他们访问我们网站的不同方面的数据,如他们浏览的页面,他们访问这些页面的时间以及他们使用的设备。这可以帮助我们识别长相相似的用户。
然而,如此丰富的信息是福也是祸。这是一件幸事,因为它为我们提供了以各种方式模拟用户行为的灵活性,并选择最能描述用户活动的特性集。但这也是一个诅咒,因为考虑到数据的高维数,找到正确的特征集是一个挑战。如果选择了错误的功能集,就很难在浩瀚的用户大海中找到珍贵的针。
下图是根据已经标记的数据构建的,说明了这个问题。图像中的每个点都是每个用户原始特征的 2D t-SNE 投影。蓝点代表一组初始用户——在这种情况下是一组报纸订户——我们需要为他们寻找相似者。红点是真正的相似者(即初始集合中不包括的其他订户),而黄点是没有订阅报纸的普通用户。
t-SNE project of the feature space
我们的目标是挑选真正的订户(“红色”),排除普通用户(“黄色”)。正如我们在图中看到的,这似乎是一个棘手的问题。
在这篇文章中,我们展示了我们是如何解决这个问题的。这是一个实用的解决方案,允许我们充分利用原始种子集中包含的信息,充分利用我们可用的多种功能。
长相相似的问题
我们可以将我们的目标定义如下:
- 假设 u 是在 d 维空间中的特征向量形式的用户表示。
- 让
the initial set of users, called the ‘seed set’
a second set of users, where typically n >> m
- 根据某些标准返回 L ⊆ T ,其中包括看起来像 S 中的用户的用户。在我们的例子中,用户在 Schibsted 网站上的在线活动。
在我们的实验中,用户表示向量 u 是二进制的,对用户在线行为的特定特征的存在或不存在进行编码。
如何实现这一点?我们在下面讨论它,但是首先我们从一个难题开始:我们应该使用监督的还是无监督的学习方法?这两种方法都旨在找到 L,但是每种方法都以完全不同的方式实现
在无人监督的情况下,该模型逐个检查 S 中的所有用户,并且对于每个用户,它从 T 中检索其活动看起来与给定用户的活动最相似的用户。在这种方法下,“长相相似”用户的集合将包含与初始集合中包含的用户相似的用户。但是,结果集可能与初始集一样异构。
在受监督的情况下,我们使用集合 S 和 T 中的用户信息来训练受监督的机器学习算法,该算法将识别与初始集合中的用户相似的用户。该模型将尝试学习使初始种子集中的用户在一般人群中脱颖而出的隐含特征,并使用它们来寻找长相相似的用户。这种方法的主要优点是,假设初始集合中的用户共享一些共同的潜在特征,它可以非常有效地识别相似的用户。然而,由于缺乏明确的反例,寻找相似者不是一个普通的监督学习问题。有一些方法可以解决这些问题,比如积极未知学习,或者一类分类。
从工程的角度来看,无监督的方法更容易实现和维护,因为不需要模型的训练、参数调整、存储和服务。
简单明了
我们从我们可以使用的最简单的方法开始: K 近邻法 (KNN)。
在这种方法下,针对输入种子集 S 对群体 T 中的每个用户进行评分。我们通过计算 T 中每个用户与 S 中每个用户的相似度来给每个用户打分,然后取平均值。因此,对于每个用户,最终的相似性得分由下式给出:
user score
在计算了 T 中每个用户的相似性得分之后,我们可以按照与初始种子集的“接近程度”对他们进行排序,然后挑选得分最高的前 K 个用户作为相似集。
但是,这种方法有效吗?这个问题把我们带回了我们在引言中讨论过的数据维度问题。具体来说,我们的数据具有大约 30,000–40,000 的维度(取决于我们选择的特性集)。这让我们直面维度诅咒。
当特征空间如此巨大时,可用数据变得稀疏。因此,区分每个用户的活动和其他人的活动变得更加困难,因为每个人在某些方面看起来都与其他人不同。
尽管面临这一挑战,我们还是用我们的数据集评估了传统的 KNN 方法,以建立一个基线。余弦距离用于所有实验,因为我们发现它比我们数据中的其他度量产生更好的结果。
相似模型的评估不像典型的二进制分类问题那样简单,因为缺乏否定的基本事实。在早期的原型制作阶段,我们通过混淆完全已知的数据集中的部分标签来克服这个障碍。在这种情况下,我们使用传统的分类指标,如精确度和召回率。但是这种方法只能带我们走这么远。
在现实生活中,比如我们在这篇文章中考虑的情况,阴性样本是不可用的。因此,我们需要一个替代的性能指标。在这种情况下,我们选择使用Mean Average Precision(MAP),它测量模型将正面类排在 lookalike 排名顶部的程度。下图显示了地图计算是如何工作的,以及地图的改进意味着什么。首先,假设我们有一个 lookalike 算法,它提供了下图顶部所示的排名。我们知道阳性样本应该排在前面。在这种情况下,我们发现它们位于位置 1、5 和 7。相应的,这个排名的映射是 0.609。现在,假设我们发现了一项改进,改变了排名,如图底部所示。在这种情况下,随着阳性样本越来越向顶部聚集(在位置 1、2 和 5),MAP 上升到 0.866。
Mean Average Precision (MAP) explained
**在我们的例子中,普通 KNN 方法的 MAP 得分是 0.704 **。这个可以和一个随机排名的图比较,0.196。还不错,但是我们可以做得更好。是时候寻求更好地处理高维数据的方法了。
利用你所知道的
虽然天真的方法似乎能够在某种程度上识别长相相似的用户,但原始的特征空间可能并不能很好地服务于我们的目的。我们需要一种方法来降低数据的维数。
用于降维的标准技术是 PCA,然而当我们应用它时,我们没有得到任何对 MAP 分数的改进。这可以被解释为因为 PCA 试图仅保持具有最高可变性的正交分量,并且对于种子用户活动和大用户池之间出现的不同趋势是不可知的。
如果我们确定了哪些特征对问题最有价值,即有助于区分种子集用户和其他用户的特征,而不是使用 PCA 或其他降维方法,也许我们可以进一步提高性能。如果我们知道这一点,我们就可以更多地依靠最相关的特征来计算用户相似性。
我们从这样的假设开始,即输入种子集包含表现出我们想要在整个群体中识别的特定行为的用户,而群体中的大多数个体表现出一般行为。通过比较这两个集合,我们可以突出它们之间的差异,并使用该信息来识别应该给予更多重视的特征。
更正式地说,为了度量每个特征的重要性,我们可以使用信息论度量,比如互信息。具体来说,马等人(T3)发现,信息值(T5)(IV)工作良好:我们对我们的问题采用了类似的方法。信息值常用于变量选择,定义如下:
Information Value score
其中 p _i 和 q _i 分别是在种子集 S 和种群集 T 中激活特征 i (f_i)的用户比例。
由于我们的特征向量是二进制的,我们可以通过将计算的 IV 权重 w 乘以向量 u 来生成新的加权特征向量。这个过程产生一个新的特征空间,具有更高的鉴别潜力。
我们通过在新的特征空间中生成相同样本的 2D t-SNE 投影来直观地演示这一点。
t-SNE projection of the of the original features space and the weighted one
正如我们可以看到的,当我们使用 IV 加权特征时,用户的类别看起来更加分离:正面测试集现在与未知测试集明显区分开来。此外,我们可以看到属于阳性集合的样本与种子集合中的样本被分组在一起。正如所料,这对 lookalike 算法的性能有积极的影响:加权特征空间上的 MAP 是 0.791,比我们的基线好 12%以上。
扩大规模
每天大约有 2 亿用户访问 Schibsted 的媒体和市场网站。扩展加权 KNN 原型是一项严峻的挑战,也是成功交付产品的关键部分。
我们算法的简化复杂度分析如下:
两个向量之间的余弦相似度大约需要 3d 次运算(点积 1 次,每个向量范数 1 次),其中 d 是向量维数。
- 对于参考集样本,我们需要|S| x 3d +|S|操作(一次计算距离,一次对所有距离求和)。
- 我们已经注意到,如果种子集大小很大,那么对单个样本进行评分会非常昂贵。
- 最后,为了对整个参考集|T| x (|S|x3d + |S|)进行排序,需要进行运算。
即使我们的特征的稀疏特性意味着每次距离计算可以在比 3d 运算少得多的运算中解决,当处理几百万个用户时,总的计算工作量也是巨大的。
幸运的是,这个任务可以并行化。
在我们的生产设置中,我们使用 Spark 和 Scala。我们发现,利用我们的特征的稀疏性,通过实施稀疏矩阵乘法方法并结合在 Spark 中广播种子集稀疏矩阵和种子集范数,我们可以显著地加速该过程。如果 u_T^i 是待排序的特征向量, W 种子集稀疏矩阵, g 是保存种子集范数的向量, v 是 u_T^i 的范数,那么将特征向量乘以种子集矩阵z**=u_ti**t w就可以得到余弦距离的分子
alternative user score formula
下面是实现过程:
我们也知道近似最近邻搜索技术,如本地敏感哈希(LSH),但上面介绍的精确搜索的实施可以处理我们的用户群,并在中等规模的集群中在不到一个小时的时间内生成结果。
有用吗?
当机器学习算法在现实世界中表现良好时,它就会显示出真正的价值。为了验证这一点,我们设立了两个在线活动:第一个向属于已知细分市场的用户展示定向广告,第二个由第一个细分市场的相似用户制作。我们通过应用上述算法,使用已知片段作为种子集来构建第二片段。
长相相似的细分市场旨在扩大第一个细分市场的受众范围。然而,只有当该段的性能与原始段的性能相当时,这才是可实现的。下图比较了展示给原始细分市场(左)和相似细分市场(右)用户的广告的点击率 (CTRs)。图表显示,基于长相相似的广告活动的表现与最初的广告活动不相上下。
原始部分在桌面上表现更好,而长相相似的部分在移动设备上表现出更高的点击率。不过,在这两种情况下,差异都在误差范围内。最重要的是,相似片段的性能并不比原始片段的性能差很多。该结果表明,相似算法可以用于其预期的受众扩展目标。具体来说,在上面的案例中,我们能够在保持 CTR 性能的同时,将段的大小翻倍。总而言之,成功的第一次在线测试。我们目前正在对不同的广告活动和广告客户进行更多的测试,初步结果很有希望。
加拿大各大银行找工作?银行求职俱乐部给你洞察热门的 IT 技能
image credit https://upload.wikimedia.org/wikipedia/commons/3/39/NYC_Top_of_the_Rock_Pano.jpg
学习是对你职业生涯的专业投资。对技术学习的投资和对金融领域的投资一样有风险。是因为科技太快了,每天都有太多的流行语出现。许多技术来来去去,只有少数技术在特定领域占据主导地位。
三个月前,我正从一家大型传统科技公司转行到金融机构。我开始分析在我们加拿大的主要银行里什么样的 IT 技能是热门的。快速浏览几个招聘职位让我了解到哪些技能在银行很热门。因此,我决定发起一个项目——银行求职俱乐部,来分析。
我参与这个项目的旅程
收集数据
数据作为软件中的自然资源,是我首先需要的。没有这种正式的数据来源。所以我开始从银行的公开网站上搜集数据。我早就听说 python 有一套工具来完成这种工作,所以我尝试了一下。利用 dryscrape 和 BeautifulSoup ,我可以轻松地从内容由 JavaScript 代码动态创建的网站中提取基本信息。这是可能的,因为 dryscape 利用一个 headless webkit 服务器来获得 HTML 呈现。
这里有一个如何找到工作内容的例子。在这个站点中,内容的 div 有唯一的类名,我们可以用这个属性来标识内容。
**import** dryscrape
**from** bs4 **import** BeautifulSoupsession = dryscrape.Session()
session.set_attribute(**'auto_load_images'**, **False**)
session.visit(url)
time.sleep(2)
response = session.body()
soup = BeautifulSoup(response, **"lxml"**)
tags = soup.findAll(**'div'**, {**'class'**: **'jd-info au-target'**})
存储数据
我选择了 mongodb 作为我的持久存储,因为我的数据模型很简单。一个简单的 json 文档就足够了。不需要为表定义多个模式,也不需要通过创建桥表来处理关系。为了让我的 python 程序执行 db 操作,我利用了 pymongo 。
**from** pymongo **import** MongoClientclient = MongoClient(**'localhost'**, 27017)
db = client.job_bank_db
all_jobs = db.jobs
**for** job **in** jobs:
**try**
all_jobs.insert_one(job.__dict__)
**except** Exception **as** ex:
print(**"Found exception: "**)
print(job)
**continue**
Cron 作业
在我们的世界里,能自动化的事情就应该自动化。所以我有一个程序来提取银行工作的信息。我需要它每天至少执行一次,以保持我的应用程序显示最新的数据。在 Linux 的世界里,这很简单:
crontab -e
# than edit the file in specific format
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
服务
我用 Express.js 在 Node.js 中创建了一组 Restful web 服务,该服务的职责就像从 mongo 提供数据并进行过滤和排序一样简单。
即 GET /jobs 端点
*// GET jobs* router.**route**(**'/jobs'**)
.get(**function** (req, res) {
res.setHeader(**'Content-Type'**, **'application/json'**);
**query_object** = {};
**var** bank_name = req.**query**.bank;
**if** (bank_name) {
**query_object**.**company** = bank_name;
}
**var** skill = req.**query**.skill;
**if** (skill) {
skill = skill.replace(/\./g, **'-'**);
**query_object**[**'stats.'** + skill] = {**$gt**: 0};
}
**var** page = req.query.page;
**if** (page) {
page = parseInt(page);
} **else** {
page = 0;
}
**var** page_size = req.query.page_size;
**if** (page_size) {
page_size = parseInt(page_size);
} **else** {
page_size = 20;
}
**var** skip = page_size * page;
Job.find(query_object)
.sort(**'-post_date'**)
.limit(page_size)
.skip(skip)
.exec(**function** (err, jobs) {
**if** (err) {
res.send(err);
} **else** {
Job.count(query_object, **function** (err, c) {
result = {count: c, jobs: jobs};
res.json(result);
});
}
});
});
用户界面
UI 层在应用中越来越受到重视。越来越多的逻辑被转移到这一层。现在有一些不错的框架和库。React.js + Redux 成为我的选择,因为我喜欢它们如何处理应用程序中的状态和数据流的概念。有 react.js 教程和 redux 官方 doc 这样的好教程。另外, create-react-app 是一个方便的工具,可以帮助我快速创建一个可运行的结构项目。
从 UI 到 webservice 的通信并不简单。在开发过程中,我将它们作为两个不同的存储库,它们在开发过程中运行在不同的服务器上。react.js 应用运行在自己的嵌入式开发服务器上。当 web 服务在 express 服务器上运行时。向另一个服务器发出请求被认为是浏览器不允许的跨源资源共享。所以我需要在我的 react.js 应用程序的 package.json 中指定代理。
"proxy": "[http://localhost:8080](http://localhost:8080)"
通过这样做,应用程序内部发出的 http 请求将被路由到 localhost:8080 上托管的 webservice。解决这个问题不需要代码。
注意 此代理仅用于开发。
在生产中,您可以在同一个服务器上运行两者,因此不需要代理。这样,您可以通过覆盖一个目录来热更新 UI。
首先,生成生产缩小包。在 react.js 项目中运行下面的命令。
npm run build
将构建目录移动到 webservice 项目中。
cp build $service_project_dir
在 webservice 中,告诉服务器构建目录包含静态资源。
app.use(express.static(__dirname + '/build'));
启动服务器PORT=80 npm start
来自数据的初步见解
敏捷——这个行话
令人惊讶的是,敏捷是银行招聘信息中排名第一的关键词。这表明几乎所有的银行都在采用敏捷方法。因此,如果你有敏捷的经验,你有很大的优势。但是你应该预料到痛苦,因为在开始采用敏捷的大公司中可能会有许多冲突。
Java——广泛使用的语言
不管你讨厌它还是喜欢它,Java 仍然是银行就业市场上最需要的编程语言。有了这个,我们可以假设 SSH (Spring、Structs 和 Hibernate)可能是银行坚持使用的技术栈。
数据库
关系数据库仍然占主导地位。Oracle 是最常被提及的数据库,其次是 SQL server 和 DB2。NoSQL 目前不太出现在工作岗位上。
终于第一次发布完成了。随时欢迎反馈。
[## 加拿大银行的技术技能
该平台提供加拿大银行 IT 工作的热门 IT 技能分析。
银行-工作.俱乐部](http://bank-jobs.club/)
我的帖子:
从 CRUD web 应用开发到语音助手中的 SDE——我正在进行的机器学习之旅
全栈开发教程:将 AWS Lambda 无服务器服务集成到 Angular SPA 中
全栈开发教程:用运行在 AWS Lambda 上的无服务器 REST API 提供交易数据
全栈开发教程:在 Angular SPA 上可视化交易数据(1)
无损三重损耗
pexels.com
一种更有效的暹罗神经网络损失函数
在工作中,我们与暹罗神经网络(NN)合作,对电信数据进行一次性训练。我们的目标是创建一个可以轻松检测电信运营商网络故障的神经网络。为此,我们构建了 N 维编码来描述网络的实际状态。通过这种编码,我们可以评估网络的状态并检测故障。这种编码与单词编码( Word2Vec 或其他)的目标相同。为了训练这种编码,我们使用一个暹罗网络【科赫等人】来创建一个一次性编码,这样它就可以在任何网络上工作。暹罗网络的简单描述可以在这里找到。关于我们实验的更多细节,你可以阅读我的同事的博客,他是这个想法背后的主脑。
在 coffeeanddata.ca 上的原始帖子
目前的实验,到目前为止效果很好。这个网络可以分割不同的交通场景。正如您在这张图片上看到的,良好的流量(绿色)很容易从错误类型 1(红色)和错误类型 2(橙色)中分离出来
Current Model
问题是
那么问题是什么,它似乎工作得很好,不是吗?经过一番思考,我意识到损失函数有一个很大的缺陷。
首先是我们模型的代码。(不必阅读所有代码,我会指出问题。)
我的问题是这条损失函数线。
loss = K.maximum(basic_loss,0.0)
这里有一个主要问题,每次你的损失低于 0,你就失去了信息,大量的信息。首先让我们看看这个函数。
它基本上是这样的:
Schroff et al.
它试图使锚(当前记录)与正(理论上与锚相似的记录)尽可能接近负(与锚不同的记录)。
这一损失的实际公式为:
Schroff et al.
这个过程在论文 FaceNet 中有详细介绍:一个统一嵌入用于人脸识别和聚类的byFlorian Schroff,Dmitry Kalenichenko和James Philbin。
因此,只要负值比正值+α更大,算法就不会有增益来压缩正值和锚点。我的意思是:
Distance costs
让我们假设:
- 阿尔法是 0.2
- 负距离是 2.4
- 正距离是 1.2
损失函数结果将是 1.2–2.4+0.2 =-1。然后,当我们查看 Max(-1,0)时,我们最终得到 0 作为损失。正距离可以是大于 1 的任何值,损失也是一样的。在这种情况下,算法将很难减少锚和正值之间的距离。
作为一个更直观的例子,这里有两个场景 A 和 b。它们都代表了损失函数为我们测量的内容。
在 Max 函数之后,A 和 B 现在都返回 0 作为它们的损失,这是明显的信息损失。单纯看,可以说 B 比 a 好。
换句话说,你不能相信损失函数的结果,例如 50 年前后的结果。损失(训练和开发)为 0,但显然结果并不完美。
其他损失
另一个著名的损失函数是严乐存和他的团队在他们的论文中描述的对比损失,通过学习不变映射进行降维,也最大化了负面结果,这产生了相同的问题。
The Contrastive Loss Function, (LeCun)
解决办法
有了标题,你很容易猜到我的计划是什么…做一个损失函数,它将捕捉 0 以下的“丢失”信息。在一些基本的几何学之后,我意识到如果你包含了计算损失的 N 维空间,你可以更有效地控制它。所以第一步是修改模型。最后一层(嵌入层)需要控制大小。通过使用 Sigmoï de 激活函数而不是线性函数,我们可以保证每个维度都在 0 和 1 之间。
Sigmoïde activation
那么我们可以假设距离的最大值是 N,N 是维数。举个例子,如果我的锚点在 0,0,0,我的负点在 1,1,1。基于 Schroff 公式的距离将是 1 +1 +1 = 3 。所以如果我们考虑维度的数量,我们可以推导出最大距离。这是我提出的公式。
Linear loss function
其中 N 是嵌入向量的维数。这看起来非常相似,但通过使用 sigmode 和适当的 N 设置,我们可以保证该值保持在 0 以上。
初步结果
经过一些初步测试,我们最终有了这个模型。
Merge results
好的一面是,我们可以看到来自同一个集群的所有点都变得非常紧密,甚至到了它们变得相同的程度。但不利的一面是,这两种错误情况(橙色和红色)重叠了。
这样做的原因是,当红色和橙色分开时,这样的损失较小。所以我们需要找到打破成本线性的方法;换句话说,随着错误越来越多,成本越来越高。
非线性
代替线性成本,我们提出了非线性成本函数:
From Google Graph
curve function
其中当 N = 3 时,曲线由 ln 函数表示
有了这个新的非线性,我们的成本函数现在看起来像:
Lossless triplet loss
其中 N 是维数(网络的输出数;用于嵌入的特征数量),β是比例因子。我们建议将其设置为 N,但也可以使用其他值来修改非线性成本。
如您所见,结果不言自明:
Result of classification with lossless triplet loss
我们现在有非常浓缩的点群,比标准的三元组函数结果要多得多。
作为参考,损失函数的代码如下:
记住,为了使它工作,你需要你的 NN 最后一层使用 Sigmoï de 激活函数。
即使在 1000 个历元之后,无损三重损耗也不会像标准三重损耗那样产生 0 损耗。
差异
基于我的同事做的他的模型的很酷的动画,我决定做同样的事情,但是用两个损失函数的现场比较。这是现场结果,左边是标准三重损耗(来自 Schroff paper ),右边是无损三重损耗:
结论
这个损失函数看起来不错,现在我需要在更多的数据、不同的用例上测试它,看看它是否真的是一个稳健的损失函数。让我知道你对这个损失函数的看法。
想要阅读更多内容
关注我的博客: coffeeanddata.ca
参考
- 科赫、格雷戈里、理查德·泽梅尔和鲁斯兰·萨拉胡季诺夫。“用于一次性图像识别的连体神经网络。” ICML 深度学习工场。第二卷。2015.
- 《向量空间中单词表征的有效估计》 arXiv 预印本 arXiv:1301.3781 (2013)。
- 施洛夫、弗洛里安、德米特里·卡列尼琴科和詹姆斯·菲尔宾。" Facenet:人脸识别和聚类的统一嵌入."IEEE 计算机视觉和模式识别会议论文集。2015.
- 哈德塞尔、拉亚、苏米特·乔普拉和扬·勒昆。"通过学习不变映射来降低维数."计算机视觉与模式识别,2006 年 IEEE 计算机学会会议于。第二卷。IEEE,2006 年。
- 【https://thelonenutblog.wordpress.com/
- https://hacker noon . com/one-shot-learning-with-siamese-networks-in-py torch-8d daab 10340 e
低预算和高期望:机器学习初创公司
在之前关于如何雇佣人工智能顾问和如何给人工智能项目定价的文章中,我试图让你了解人工智能咨询领域的工作方式。我也让你们感受到了许多在的老牌组织在将他们的数据放入云端时所面临的特殊挑战。
这篇文章是关于那些更小更新的公司的。让我先说一下,并不是所有的创业公司都是一样的。每个人都是一朵特别的花,生长或枯萎都是如此。现在,我们来概括一下。在人工智能真正炙手可热的创业世界中,存在一种奇怪的动态,然而当谈到对预期进行定价时,预期和现实之间的一致性却很不正常。企业客户通常需要一些快速解决方案来部署 apache spark 或 hadoop 或等等,以便及时获取他们的数据。这还是在考虑机器学习之前。对于初创公司来说,这同样具有挑战性。
一旦可以访问数据,就需要设计、构建、测试和部署 ML 系统。对于某些模型来说,这非常简单,但是这些步骤仍然需要时间。可能需要尝试几种不同的模式。客户端几乎总是需要配置 GPU 资源,即使这仅仅意味着在 p2 实例上加载 AWS 中的 AMI。这需要更多的时间。不要忘记有时你想要一个保留实例来降低成本。也许你想比较 GCP 和 AWS 的平台。现在,系统几乎总是需要超过用户名和密码的安全性。我喜欢使用 PPK/pem 证书和谷歌认证器。所以简而言之,即使是创业公司的小型机器学习项目也没有那么小。
我开始写这篇文章之前,一个小的一个人创业公司上周接触到我们公司的一个项目,将需要 3 个月的兼职基础上,成本上限为 1000 美元。我喜欢非常节省时间,但这是愚蠢的。如果这个项目预计需要 4 个小时,我还是不得不拒绝。只是为了通过 NDA 和计费流程…是的。这说不通。
现在,这家创业公司不是想耍我。这是他们能承受的。我不得不建议这位企业家去为他的想法筹集资金,并保持联系。这些关于 ML 创业的困难的思考对我来说并不新鲜。
我喜欢凯文·德瓦尔特关于企业客户机器学习项目成本估算的表格。请参见下面的链接:
[## AI 第 1 年预算模板
规划你的第一个人工智能产品的起点
blog.prolego.io](https://blog.prolego.io/ai-year-1-budget-template-85d4d419a5a1)
Kevin 列出的成本比许多初创公司机器学习项目都高,因为许多初创公司没有针对其原型的大数据要求。然而,它应该让每个人都很好地了解保持机器学习项目正常运行的成本。
有些风险是值得的,比如早期未付费的客户演示,这样才有机会赢得项目。但是,有时候客户对可能发生的事情抱有非常不切实际的期望。时间、金钱、质量→选择 2
更奇怪的是。ML 开发是关于结果的,而不是你的顾问花了多少时间编码。在一个商品化的市场中,我们会对 ML 项目收费,就像软件公司对网络开发收费一样。更多的时间意味着更多的钱,工作时间和结果之间的关系是线性的(也许真的更像一条 tanh S 曲线)。然而,在 ML 中,努力输入经常导致未知的结果输出。数据科学仍然是一门艺术,有时最大的成果来自于知道在哪里寻找正确的库(低努力;高回报),而不是写最激进的代码(高努力;奖励高)。
我想分享一下我上周与一个客户的数据打交道的经历,让我明白 ML 的发展是一条曲折的道路:
我从客户的约 10,000 条记录的小型单表 mySQL 数据集开始,用于回归和分类模型。因为体积小,我从无监督迁移学习开始。我取得了不错的成绩,但怀疑自己还能做得更好。接下来,我着手开发一个监督学习模型,它可以编译,但结果更差。接下来,我继续研究生成模型。结果比以前更糟,迫使我回到最初的解决方案。我在最初的方法中添加了一些特性工程,并在性能上取得了一点点改进。现在,这个模型似乎已经达到了这个阶段的最佳状态。在这里,在概念验证项目的最后,我花费了超过 80%的精力在不会被使用的代码上。而性能最好的代码是我在项目的前 20%写的东西。大多是前 20 分钟!
我们从这件事中学到的是,时间和结果之间的关系是变化无常和怪异的。数据科学更多的是化学和柠檬派,而不是土木工程和纯数学。这是一个更加动态和实用的过程,而不是一个金钱投入/结果产出的等式。
我对创业期望的建议是,在开始你的机器学习项目之前,尽可能多地收集、组织和标记你的数据。与你的利益相关者讨论你的资源,不要羞于从不同的供应商那里得到多个报价。你会发现价格和质量的权衡,就像其他购物一样。缓和你的期望,但不是你的兴奋。部署机器学习的时间到了!
如果你喜欢这个帖子,那么请推荐它,分享它,或者给它一些爱(❤).我也很高兴在评论中听到你的反馈。
编码快乐!
-丹尼尔
丹尼尔@lemay.ai ←打个招呼。
LEMAY . AI
1(855)LEMAY-AI
您可能喜欢的其他文章:
TensorRT 低精度推理
声明:这是而不是一个 NVIDIA 的官方帖子。只是总结一下我从演讲、听的演讲和与人的互动中学到的和收集到的东西。Post 假设对深度学习(DL)有一些基本的了解。
深度学习程序通常有两个阶段,即,
- 训练,利用一堆数据和某些优化技术,机器学习归纳(嗯,这是它能得到的最简单的)。通常离线完成。
- 推理,机器将学习到的概括应用于看不见的数据。通常在生产环境中使用。
训练是对大量数据的迭代过程。它的计算量非常大。根据问题定义、数据等,可以使用从单个 GPU 到一群 GPU 的任何东西。
另一方面,推理在计算上相对容易(由于较小的批量和没有反向传递),但是在大多数 DNN(深度神经网络)应用中实现实时推理仍然是一个困难的问题。
注意,训练过程一般没有“实时的约束。另一方面,实际推理是受时间和力量(尤其是嵌入式)约束的。TensorRT 是 Nvidia 软件解决方案,用于为深度学习模型的生产部署生成优化模型。这篇 parallel forall 博客文章对 TensorRT,以前被称为 GPU 推理引擎(GIE ),博客使用旧行话)做了很好的介绍。
这篇博客将主要集中在一个重要的优化技术上:低精度推理(LPI) 。
在开始理解 LPI 之前,我将快速总结一下所有博文的相似之处。
Fig. 1: TensortRT in one picture
上图很好地概括了 TRT 的工作。它基本上是作为一个 SDK 公开的。你输入你已经训练好的网络(这将意味着模型定义和学习参数)和其他参数,如推理批量大小和精度,TRT 做优化,并建立一个执行计划,可以使用或序列化,并保存到磁盘上,供以后使用。推理时不需要深度学习框架。只要使用 TRT 输出的执行计划,就可以了。在服务器、台式机甚至嵌入式设备上使用它。此外,对于给定的模型,这是一次性的事情。没有附加条件:)
优化引擎
这就是奇迹发生的地方(嗯,不完全是,这只是科学)。TRT 做了一些优化。
- 图形优化:
Fig.2: Vertical Fusion — Input
Fig.3: Vertical Fusion — Optimized graph
上图解释了 TRT 所做的垂直融合优化。卷积©、偏置(B)和激活(本例中为 R、ReLU)都被合并到一个节点中(就实现而言,这意味着 C、B 和 R 只启动一个 CUDA 内核)。
Fig.4: Horizontal Fusion
是的。还有一种水平融合,其中如果具有相同操作的多个节点正在向多个节点馈送,则它被转换为一个单个节点向多个节点馈送。三个 1x1 CBRs 被融合成一个,并且它们的输出被定向到适当的节点。
其他优化
除了图形优化之外,TRT 还通过实验并基于诸如批量大小、卷积核(过滤器)大小等参数,为网络中的操作选择高效的算法和核(CUDA 核)。
低精度推理
那么,为什么我们真的需要低精度的推理呢?
正如已经提到的,执行时间和功率并不便宜,在实时应用中是至关重要的。考虑到所需的计算量,我们希望在不影响准确性的情况下,优化我们的推理,以利于时间和能力。因此,我们转移到参数的 8 位表示和推理时的激活。与 32 位相比,8 位需要更少周期来获取存储器。还有一个新的硬件指令(DP4A)形式的优势,我将在本文稍后介绍。
这有用吗?
是的,当然。如果不是这样的话,这个博客就是浪费时间了:)。在训练过程中,参数和激活在 FP32 中显示。FP32 的高精度有利于训练,因为每个训练步骤都会对参数进行少量修正。DL 算法通常对噪声有弹性。在学习模型的过程中,通常会尝试选择性地保留预测所需的特征。所以,扔掉不必要的东西是这个过程的一部分。所以我们希望低精度表示引入的噪声被模型扔掉(这里也是非常外行的术语)。据我所知,没有严格的数学证明说低精度应该在推理过程中像 FP32 一样好。
将 FP32 映射到 8 位
这是 TensorRT 为应用程序/客户端做的事情。应用程序/客户端只需要实现一个提供校准信息和一些缓存相关代码的接口。很快会有更多的报道。在此之前,让我们看看 TRT 进行 32 位到 8 位映射的步骤。
映射的候选对象是每一层的输入(将输入到第一层,并激活其余层)和学习参数。最简单的映射/量化形式是线性量化。
FP32 张量(T) = scale_factor(sf) * 8 位张量(t) + FP32_bias (b)
很简单,不是吗?让我们把它变得简单些。(从实验中)发现偏差项并没有真正增加任何价值。所以,摆脱它。
T = sf * t
注意这里的 sf 是每个层中每个张量的比例因子。现在,下一个问题是找到比例因子。一个简单的方法是如下图所示:
Fig.5: A simple max-max mapping
我们简单地将张量中的-|max|和|max| FP32 值分别映射到-127 和 127。其余的值相应地线性缩放。但是,这里有一个问题。实验表明,这种映射会导致显著的精度损失。因此,TRT 采取了以下措施:
Fig.6: Threshold instead of max
而不是看|max|值。固定一个阈值(如何?我们稍后会看到)。然后像前面一样进行映射。阈值范围内的任何值都调整为-127 或 127。例如,在上图中,三个“红叉”被映射到-127。
那么接下来的问题就是阈值 T 的最优值是多少?这里有两种分布。我们有 FP32 张量,它在 FP32 分布中表现得最好。但是,我们希望用不同的分布(8 位)来表示它们,这不是最好的分布。我们希望看到这些分布有多大的不同,并希望将差异最小化。TRT 使用 Kullback-Leibler 散度( KL-divergence )来衡量差异,并旨在将其最小化。
可选:什么是 KL-divergence?为什么是 KL-divergence?一些直觉:<可选开头> 让我们在这里稍微进入编码理论。假设我有一系列符号,我知道它们出现的概率。如果我要对符号进行最佳编码,我会使用比如说“T3”T 比特。注意 T 是最佳位数。让我们称这个代码为代码’ A ‘。现在,我有了同样的一组符号,但是它们出现的概率变了。现在,对于具有新概率的符号,如果我使用代码’ A ‘来编码符号,则用于编码的比特数将是次优的,并且大于’ T '。KL-divergence 精确地测量这种差异,即最优和次优之间的差异(由于选择了错误的代码)。在我们的例子中,张量值的正确代码是 FP32,但我们选择用 8 位错误代码来表示(嗯,不是错误,但你明白了)。所以有一个惩罚,用 KL 散度来衡量。我们的工作是尽量减少处罚。如果你已经用 DL 解决了一些问题,你可能会用交叉熵作为一个代价函数。KL 散度与交叉熵密切相关。虽然 KL-divergence 表示由于在错误代码中编码而导致的比特数(或所需的额外比特数)的差异,但是交叉熵表示在该错误代码中编码符号所需的确切比特数。所以, KL-divergence =(交叉熵)——(最优码所需比特数)。 <可选结束>
因此,我们需要最小化 FP32 值和相应的 8 位值之间的 KL 偏差。TRT 使用简单的迭代搜索最小散度,而不是基于梯度下降的方法。步骤如下:
Fig.7: Threshold finding process
校准
TRT 采用基于实验的阈值迭代搜索。校准是其中的主要部分。应用程序/客户向 TRT 提供了一个样本数据集(理想情况下是验证集的子集),称为“校准数据集”,用于执行所谓的校准。TRT 在校准数据集上运行 FP32 推理。收集激活直方图并生成具有不同阈值的 8 位表示的集合并选择具有最小 KL 散度的一个。KL 散度在参考分布(FP32 激活)和量化分布(8 位量化激活)之间。TRT 2.1 提供了IInt8EntropyCalibrator
接口,客户端需要实现该接口来提供校准数据集和一些用于缓存校准结果的样板代码。
DP4A
这就是 TRT 如何进行优化的简要介绍。还有一件事不完全相关,但 TRT 依赖于 8 位快速推理。从 Pascal 一代 GPU(选定的 SKU)开始,有一种称为 DP4A 的新硬件指令。
Fig.8: DP4A (Dot Product of 4 8-bits Accumulated to a 32-bit)
它基本上是一条指令,执行 4 次 8 位乘法,并累加成一个 32 位整数。点积构成了卷积运算的数学基础,该指令通过最小化执行时间和功耗,提供了非常好的提升。这篇关于 CUDA 8 的博客更详细地讨论了 DP4A。如果有兴趣,一定要去看看。
因此,总的来说,优化的空间很大。考虑到 TRT 的优化和正确的硬件(支持 DP4A 的 GPU),您不仅可以将 GPU 推向极限,同时还可以保持其效率。所以去做一些有效的推断,直到你推断出生命的意义:D
**一些参考:**我无耻地从博客和演示文稿中抄袭数据:)
图 1 至图 4:tensort
图 5 至图 8 : GTC PPT
这大部分是基于在 2017 年 GTC 上的这个出色的展示。
PS:请随意评论/批评/ ♥这篇文章。