营销分析:客户参与,随机森林风格
我们将讨论如何建立一个关于客户营销参与的随机森林预测模型。通过更好地预测客户将如何参与某些营销活动,营销人员可以为不同的受众量身定制策略[1]。我们在这里寻找的官方营销术语是“参与的可能性”一个具体的例子是区分哪种类型的客户会对哪种类型的广告做出反应(例如,20-39 岁的女性对脸书广告和谷歌广告的反应——完全是编造的)。
数据设置
今天的数据由 ka ggle[2]:
https://www . ka ggle . com/pankajjsh 06/IBM-Watson-marketing-customer-value-data/downloads/IBM-Watson-marketing-customer-value-data . zip/1慷慨提供
是时候导入所有的包了。
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib inline
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.metrics import roc_curve, auc
接下来,带来数据。
#load data
df = pd.read_csv('WA_Fn-UseC_-Marketing-Customer-Value-Analysis.csv')
custd.head()
作为模型输出的“响应”变量不是一个数字。这将被调整成一个数字,否则 Python 会发疯的。
#Encoding output variable
custd['Engaged'] = custd['Response'].apply(lambda x: 1 if x == 'Yes' else 0)
应用功能将“是”的回答转换为“1 ”,将其他所有回答转换为“0”。“是”表示客户参与了,而“否”表示没有参与。所以平均参与率是
custd['Engaged'].mean()
0.1432,意味着我们的平均参与率大约为 14%。现在,你知道为什么他们说销售是一个数字游戏。只有少数人说是。
特征工程
让我们来看看我们的客户参与模型的特性。
#Checking out features
custd.describe()
酷,我们用 describe 隔离了所有的数值或连续列。
continuous_features = ['Customer Lifetime Value', 'Income', 'Monthly Premium Auto',
'Months Since Last Claim', 'Months Since Policy Inception',
'Number of Open Complaints', 'Number of Policies', 'Total Claim Amount']
现在,来处理所有的分类栏目。
columns_to_encode = ['Sales Channel', 'Vehicle Size', 'Vehicle Class', 'Policy', 'Policy Type',
'EmploymentStatus', 'Marital Status', 'Education', 'Coverage']categorical_features = []
for col in columns_to_encode:
encoded_df = pd.get_dummies(custd[col])
encoded_df.columns = [col.replace(' ', '.') + '.' + x for x in encoded_df.columns]
categorical_features += list(encoded_df.columns)
custd = pd.concat([custd, encoded_df], axis=1)
custd['Is.Female'] = custd['Gender'].apply(lambda x: 1 if x == 'F' else 0)categorical_features.append('Is.Female')
在将所有需要的变量编码成数字后,我们需要将所有内容组合回一个数据框架中。
all_features = continuous_features + categorical_features
response = 'Engaged'
sample_custd = custd[all_features + [response]]
sample_custd.columns = [x.replace(' ', '.') for x in sample_custd.columns]
all_features = [x.replace(' ', '.') for x in all_features]
sample_custd.head()
在一些特征工程之后总是检查你的数据以确保你没有错过任何东西,这不是一个坏主意。在我们的例子中,看起来我们成功地将所有东西都转换成了数字。现在来看模型!
构建随机森林
我们需要做的第一件事是在训练集和测试集之间分割数据,以便稍后进行评估。
# model phase - train/test
x_train, x_test, y_train, y_test = train_test_split(sample_custd[all_features], sample_custd[response], test_size=0.3)
现在我们可以训练和拟合随机森林模型。请随意调整模型设置,以获得更好的解决方案。
#Building random forest model
rf_model = RandomForestClassifier(n_estimators=200,max_depth=5)#Features
X = x_train
#Output
y = y_train#Fit model to training data
rf_model.fit(X, y)
另外,在随机森林中,你可以看到一棵树是如何投票的。
#looking at individual trees
rf_model.estimators_
#individual tree setting
rf_model.estimators_[0]
#individual tree prediction
rf_model.estimators_[0].predict(x_test)[:10]
上面的数组是 0 号树对前 10 个样本的投票结果。很酷,对吧?回到 random forest,我们来看看模型是怎么想的,哪些功能对客户参与度最重要。
#Examining what RF thinks are important features
rf_model.feature_importances_
feature_importance_df = pd.DataFrame(list(zip(rf_model.feature_importances_, all_features)))
feature_importance_df.columns = ['feature.importance', 'feature']featsorted = feature_importance_df.sort_values(by='feature.importance', ascending=False)
featsorted
好吧,那是一张长桌子。让我们以图形的形式让它更容易阅读——十大最重要的特性。
featsortedtop10 = featsorted.head(10)featsortedtop10.plot(kind='bar', x='feature')
根据 random forest 模型,退休员工最倾向于参与我们的营销工作。这并不奇怪,因为我们的数据集是关于一家保险公司的营销。
模型评估
in_sample = rf_model.predict(x_train)
out_sample = rf_model.predict(x_test)print('In-Sample Accuracy: %0.4f' % accuracy_score(y_train, in_sample))
print('Out-of-Sample Accuracy: %0.4f' % accuracy_score(y_test, out_sample))
样本内精度:0.8746
样本外精度:0.8814
准确度是正确预测的数量除以预测的总数。基本上,随机森林模型在预测谁将参与营销活动方面是正确的。
print('In-Sample Precision: %0.4f' % precision_score(y_train, in_sample))
print('Out-of-Sample Precision: %0.4f' % precision_score(y_test, out_sample))
样本内精度:0.9574
样本外精度:0.8714
精度是真阳性的数量除以真阳性和假阳性的数量。当你想知道预测有多正确时,你需要精确。例如,有多少客户实际参与了 X 营销活动,而不是那些被预测参与和没有参与的客户。
print('In-Sample Recall: %0.4f' % recall_score(y_train, in_sample))
print('Out-of-Sample Recall: %0.4f' % recall_score(y_test, out_sample))
样本召回率:0.1450
样本外召回:0.1618
召回是真阳性的数量除以真阳性和假阴性的数量。换句话说,有多少模型正确地预测了与 X 活动接触的客户,而不是那些实际接触的客户。
当我学习精确和回忆的区别时,我有点困惑。对我有帮助的是看到一个好的和另一个坏的区别。例如,高精度和低召回率可以发现目标输出,但是会遗漏一些目标输出机会。另一方面,高召回率和低精确度可能导致发现所有目标输出,但是预测实际上没有的目标输出。
# ROC and AUC curves
in_sample = rf_model.predict_proba(x_train)[:,1]
out_sample = rf_model.predict_proba(x_test)[:,1]
in_sample_fpr, in_sample_tpr, in_sample_thresholds = roc_curve(y_train, in_sample)
out_sample_fpr, out_sample_tpr, out_sample_thresholds = roc_curve(y_test, out_sample)
in_sample_roc_auc = auc(in_sample_fpr, in_sample_tpr)
out_sample_roc_auc = auc(out_sample_fpr, out_sample_tpr)print('In-Sample AUC: %0.4f' % in_sample_roc_auc)
print('Out-Sample AUC: %0.4f' % out_sample_roc_auc)
样本内 AUC: 0.8824
样本外 AUC: 0.8623
plt.figure(figsize=(10,7))plt.plot(
out_sample_fpr, out_sample_tpr, color='darkorange', label='Out-Sample ROC curve (area = %0.4f)' % in_sample_roc_auc
)
plt.plot(
in_sample_fpr, in_sample_tpr, color='navy', label='In-Sample ROC curve (area = %0.4f)' % out_sample_roc_auc
)
plt.plot([0, 1], [0, 1], color='gray', lw=1, linestyle='--')
plt.grid()
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('RandomForest Model ROC Curve')
plt.legend(loc="lower right")plt.show()
ROC 曲线显示了真阳性和假阳性的比率,您希望曲线最快到达左上角以获得最佳模型性能。我们的样本内和样本外曲线都没问题。如果两者之间的差距越来越大,那么这是一个迹象,表明该模型过于适合训练数据,而没有找到营销参与的一般模式[4]。
结论
恭喜,我们已经从头到尾建立了一个营销客户参与随机森林模型。首先,我们做了一些简单的数据探索,并对数据进行了特征工程处理,使之成为数值。接下来,我们创建了随机森林模型,并查看了各个决策树。之后,我们评估了训练集和测试集的数据,得到了一个非常好的 ROC 曲线。从我们的数据来看,客户退休似乎是一个关键特征,而总索赔和收入接近。向前发展的业务解决方案可以建议总是预先获取这些数据点。
免责声明:本文陈述的所有内容都是我个人的观点,不代表任何雇主。
参考
[1] A. McEachern,什么是客户参与,为什么它很重要?(2019)https://blog . smile . io/什么是客户参与度以及它为什么重要
[2] IBM Watson,营销客户价值数据(n . d .)
https://www . ka ggle . com/pankajjsh 06/IBM-Watson-Marketing-Customer-Value-Data/downloads/IBM-Watson-Marketing-Customer-Value-Data . zip/1
[3] B. Mikulski,Precision vs . recall-explain(n . d .)https://www . mikulskibartosz . name/Precision-vs-recall-explain/
[4] Y. Hwang,《营销数据科学实践》( 2019 年),派克特出版社
通过马尔可夫链进行营销分析
通过马尔可夫链了解客户的下一步行动
Image Source : http://setosa.io/ev/markov-chains/
假设你是一家在市场上销售快速消费品的公司。
让我们假设客户将遵循以下流程进行最终购买:
这些是客户在购买过程中的任何时候都会处于的状态。
现在,如何找出客户在 6 个月后会处于哪种状态?
马尔科夫链来救援了!!
我们先来了解一下什么是马尔可夫链。
马尔可夫链:
马尔可夫链是描述一系列可能事件的随机模型,其中每个事件的概率仅取决于前一个事件达到的状态
马尔可夫链是在概率上彼此相关的连续事件。
这些事件也称为状态
这些状态一起形成了所谓的状态空间。
下一个事件或下一个状态的概率只取决于当前状态,而不取决于先前的状态。马氏链的这个性质叫做无记忆性。它不关心过去发生了什么,只关注当前的信息来预测下一个状态会发生什么。
马尔可夫链——状态、概率和转移矩阵
让我们深入一点。
马尔可夫链提供了
关于当前状态的信息
&
从一种状态转移到另一种状态的转移概率
利用以上两个信息,我们可以预测下一个状态。
用数学术语来说,当前状态称为初始状态向量
所以,我们得到的是:
最终状态=初始状态*转移矩阵
经典例子
马尔可夫链的一个经典例子是预测天气。我们有两种不同的天气状况:晴天和雨天。让我们假设今天是晴天。我们有以下可能性:
假设今天是晴天,明天是晴天的概率(处于相同状态的概率):0.9
假设今天是晴天,明天下雨的概率:0.1
假设今天下雨,明天是晴天的概率(处于相同状态的概率):0.5
假设今天下雨,明天下雨的概率(处于相同状态的概率):0.5
Source: Wikipedia
这里的初始向量是:
转换矩阵=
第二天的天气=
回忆一下**终态=初态*转移矩阵?**以上代表相同。
那么推论是什么呢?
第二天有 90%的可能性天气晴朗,10%的可能性下雨。
回到问题
回到问题上来,我们需要知道产品发布 6 个月后客户的状态。
我们可以假设客户在任一时间点可能处于 4 种状态!!
1.意识
2.考虑
3.购买
4.不购买
我们有以下信息:
客户总数= 200,000
每个州/类别的客户数量
从一个状态转移到另一个状态的转移概率
关于在这几个月开展的一些活动或广告的信息(活动/广告的目的是增加购买产品的客户数量)
营销分析目标:
获得 6 个月后所有 4 个州的客户数量
评估该活动在增加购买该产品的顾客数量方面是否有效
所以,让我们深入数学部分。
注:A —认知,C —考虑,P —购买,NP —不购买
初始状态向量=
转换矩阵=
可以更清楚地看到所有 4 个状态之间的运动:
顾客的最终状态=初始状态向量*转移矩阵
结果评估
现在让我们评估我们的结果。
起始向量
最终向量
我们可以注意到,“了解”和“考虑”的人数有所减少。这是一件好事,因为人们实际上从“意识”和“考虑”状态转移到了“购买”状态(增长了近 34%!!)还要注意,处于“不购买”状态的人数减少了(减少了 11%)。
总的来说,我们的分析表明活动/广告奏效了!!
马尔可夫链在营销分析和 NLP 等其他领域有许多其他应用。
敬请关注更多文章…
如果你喜欢我的文章,请给它几个掌声!!!
更多详情,请联系我:
另外,一定要看看我们在 MMM 上的视频:
版权所有 2018https://www.arymalabs.com/版权所有。
Python 中 Markov 链的营销渠道属性——第 2 部分:完整演练
在渠道属性的背景下,arkov chains 为我们提供了一个框架,以统计方式模拟用户旅程,以及每个渠道如何考虑用户从一个渠道到另一个渠道的旅行,最终转换(或不转换)。通过使用这些转移概率,我们可以确定单个渠道对我们总转化率的统计影响。
关于营销归因和马尔可夫链的更多细节,参见第 1 部分。
在关于这个主题的第一部分中,我们讨论了什么是营销归因,为什么准确和正确的归因越来越重要,以及马尔可夫链背后的理论如何应用于这个领域。
虽然那篇文章包含了如何以编程方式将马尔可夫链应用于 Python 中的示例客户数据集的实际例子,但它也涉及到对 R 包channel attribute的严重依赖。
对于生产应用程序来说,这种对独立软件和语言的依赖程度并不理想,相反,我们希望将整个归属过程放在一个应用程序中——在本例中是 Python。
在本文中,我将通过实际的代码示例来说明如何实现这一点。
数据
对于这个更新的演练,我已经更新了数据集,以便与我们在实际生产环境中可能遇到的数据格式更加一致。数据集可以在 这里下载 。
对于每一个独特的客户和访问我们的数据集这一次包含以下信息在每一行:
- Cookie:随机生成的客户 id,使我们能够将后续访问与同一个客户联系起来
- 时间戳:访问发生的日期和时间
- 交互作用:分类变量,表示发生的交互作用的类型
- Conversion:指示转换是否发生的布尔变量
- 转换值:潜在转换事件的值
- 渠道:将客户带到我们网站的营销渠道
该数据集包含约 240,000 名独立客户的约 586,000 个营销接触点,这些接触点产生了约 18,000,000 次转化事件。在表格格式中,数据集将如下所示:
数据预处理
为了将我们的数据转换成适用于马尔可夫链算法的理想格式,我们需要做一些预处理。
我们将从导入熊猫开始,加载我们的数据集,并创建一个列来指示每个用户的接触点顺序:
接下来,我们希望将数据框从长格式格式化为宽格式,因此我们最终将得到一个数据框,其中包含每个用户一行,以及一个接触点列表中按时间顺序排列的用户旅程总数。
我们首先将按时间顺序排列的接触点分组到一个列表中,将最终转换/非转换事件的列表合并到该数据框中,最后在用户旅程列表的末尾添加一个“空”或“转换”事件。
这将为我们提供一个如下所示的数据框架:
马尔可夫链
我们现在可以转向实际的马尔可夫链方法。
马尔可夫链的算法可以总结为两个步骤:
- 计算状态空间中所有状态之间的转移概率
- 计算移除效应(关于移除效应的更多信息,参见第 1 部分
我们将从定义所有用户旅程、总转化率和基础转化率的列表开始。所有我们以后会用到的东西:
接下来,我们将定义一个函数来识别所有潜在的状态转换,并输出包含这些转换的字典。在计算转移概率时,我们将使用它作为输入:
并且计算所有转移概率的函数可以定义为:
上面应该给我们留下一个字典,其中包含所有的转换以及给定历史数据时它们各自的转换概率。
最后一步是确定每个营销渠道的去除效果。为此,我们将利用线性代数和矩阵操作,因此让我们将上述转移概率字典转换为数据框架(矩阵):
我们刚刚制作的转换矩阵本身实际上包含了大量有价值的信息。它的一个直接衍生物将是生成一个方向图或转换热图来可视化典型的用户旅程。
Heat map for transition probabilities in our data set
使用历史背景和上面的热图,我们不仅可以深入了解每个营销渠道如何推动用户参与我们的转化活动,还可以获得营销渠道之间如何互动的关键信息。鉴于当今典型的多点接触转化之旅,这些信息可以证明是非常有价值的,并允许我们优化我们的多渠道客户转化之旅。
现在,我们可以迭代地遍历每个通道,并评估如果我们从状态空间中删除一个通道,它将对整体转换产生的影响。我们将这样做,并将产生的移除效果添加到输出词典中:
由此产生的移除效应字典可用于计算我们每个营销渠道的马尔可夫链属性:
为了更好地感受我们的劳动成果,让我们来看一下每个渠道的最终归因转换值。
如果您一直关注我们的原始数据集,您应该会看到下面的条形图,其中显示了通过马尔可夫链算法归属于每个渠道的总转化率:
重要的是要记住,虽然本例中的数据集包含大量数据,但它只包括 5 个营销渠道。在现实世界中,我们可能会使用数倍于此数量的渠道(如果我们应用更细粒度的模型,如特定于活动的归因模型,则数量会更多),因此增加了典型用户旅程的复杂性,以及对支持这种复杂程度的归因模型的需求。
为营销渠道分配准确的信用可能是一项复杂但有益的任务。使用本文中概述的马尔可夫链方法,可以让你的属性更准确地反映你的用户是如何与你的营销互动的。
关于作者
Morten 是 Wealthsimple 的一名数据科学家,他利用数据科学帮助人们实现财务自由。
Wealthsimple 的数据科学团队一直在寻找新的创新、聪明和有抱负的人加入团队。查看我们的职业页面或联系 LinkedIn 。
基于 Python 的马尔可夫链分析与仿真
用概率解决现实世界的问题
马尔可夫链是一个离散时间的随机过程,它以一定的概率从一个状态前进到另一个状态,这可以用一个图和状态转移矩阵 P 来表示,如下所示:
这样的链,如果它们是一阶马尔可夫链,展示了马尔可夫性质,即下一个状态仅依赖于当前状态,而不依赖于它是如何到达那里的:
在这篇文章中,我们看两个不同的概念,一个是从马尔可夫链模拟,另一个是计算它的平稳分布。稳定分布是当样本数量接近无穷大时,系统在每个状态下花费的时间分数。如果我们有 N 个状态,平稳分布是一个长度为 N 的向量,其值总和为 1,因为它是一个概率分布。
我们还看两个例子,一个简单的玩具例子,以及一个可能的现实世界场景分析问题。
计算平稳分布
注意,在下面的第一个实现中,不是对状态转换的模拟,只是对稳定分布的计算。
让我们从计算分布的迭代方法开始。我们正在做的是将转移矩阵提升到迭代次数的幂:
平稳分布通常被称为π。
因此
import numpy as np
import pandas as pd
from random import seed
from random import random
import matplotlib.pyplot as plt
P = np.array([[0.2, 0.7, 0.1],
[0.9, 0.0, 0.1],
[0.2, 0.8, 0.0]])state=np.array([[1.0, 0.0, 0.0]])
stateHist=state
dfStateHist=pd.DataFrame(state)
distr_hist = [[0,0,0]]for x in range(50):
state=np.dot(state,P)
print(state)
stateHist=np.append(stateHist,state,axis=0)
dfDistrHist = pd.DataFrame(stateHist)
dfDistrHist.plot()plt.show()
计算很快收敛到稳定分布:
如前所述,π是稳定分布。
在这种情况下,这也可以通过一组超定方程的线性代数解来实现:
A=np.append(transpose(P)-identity(3),[[1,1,1]],axis=0
b=transpose(np.array([0,0,0,1]))
np.linalg.solve(transpose(A).dot(A), transpose(A).dot(b)
这也返回[0.49,0.42,0.09],平稳分布π。
我们是如何计算的,如下所示:
可以证明,如果πP=π,πi=1,马尔可夫链是平稳的,具有平稳分布π
其中 i 为单位列向量,即概率之和必须恰好为 1,也可以表示为
做一些代数运算:
结合π i =1:
而 b 是除最后一个元素外所有元素都为 0 的向量。
继鲁切-卡佩里之后,
假设增广矩阵[A|b]的秩等于系数矩阵 A 的秩,则 as 可以由此求解 Pi,即平稳分布。
同样,这个算法实现可以被通用化、扩展,并作为一个类来实现。
从马尔可夫链模拟
通过注意到来自任何给定状态(概率矩阵中的对应行)的移动集合形成多项式分布,可以从马尔可夫链进行模拟。因此,可以通过模拟多项式分布来模拟马尔可夫链。
从多项式分布进行模拟的一种方法是将长度为 1 的线分成与概率成比例的区间,然后根据 0 和 1 之间的均匀随机数选取一个区间。
参见维基百科这里https://en.wikipedia.org/wiki/Multinomial_distribution。
这在下面的函数 simulate_multinomial 中进行了说明。我们从
然后我们使用 cs ,即 P 中概率的累积和,以便按比例分配随机数。
import numpy as np
import pandas as pd
from random import seed
from random import random
import matplotlib.pyplot as pltP = np.array([[0.2, 0.7, 0.1],
[0.9, 0.0, 0.1],
[0.2, 0.8, 0.0]])stateChangeHist= np.array([[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]])state=np.array([[1.0, 0.0, 0.0]])
currentState=0
stateHist=state
dfStateHist=pd.DataFrame(state)
distr_hist = [[0,0,0]]
seed(4)# Simulate from multinomial distribution
def simulate_multinomial(vmultinomial):
r=np.random.uniform(0.0, 1.0)
CS=np.cumsum(vmultinomial)
CS=np.insert(CS,0,0)
m=(np.where(CS<r))[0]
nextState=m[len(m)-1]
return nextStatefor x in range(1000):
currentRow=np.ma.masked_values((P[currentState]), 0.0)
nextState=simulate_multinomial(currentRow) # Keep track of state changes stateChangeHist[currentState,nextState]+=1 # Keep track of the state vector itself
state=np.array([[0,0,0]])
state[0,nextState]=1.0 # Keep track of state history
stateHist=np.append(stateHist,state,axis=0)
currentState=nextState # calculate the actual distribution over the 3 states so far
totals=np.sum(stateHist,axis=0)
gt=np.sum(totals)
distrib=totals/gt
distrib=np.reshape(distrib,(1,3)
distr_hist=np.append(distr_hist,distrib,axis=0)print(distrib)
P_hat=stateChangeHist/stateChangeHist.sum(axis=1)[:,None]
# Check estimated state transition probabilities based on history so far:print(P_hat)dfDistrHist = pd.DataFrame(distr_hist)# Plot the distribution as the simulation progresses over timedfDistrHist.plot(title="Simulation History")
plt.show()
从图中可以看出,在大约 400 个模拟步骤之后,分布开始收敛到稳定分布。
分布收敛到[0.47652348 0.41758242 0.10589411]:
该分布与我们之前通过求解马尔可夫链计算的平稳分布非常接近。其实四舍五入到两位小数是一样的:[0.49,0.42,0.09]。
正如我们在下面看到的,从转换历史中重建状态转换矩阵给了我们预期的结果:
[0.18,0.72,0.10]
【0.91,0.00,0.09】
【0.19,0.80,0.00】
这个算法实现可以是通用的、可扩展的,并作为一个类来实现。
它展示了如何用 Python 实现简洁紧凑的算法。
媒体、电信或类似行业的应用。
比方说,对于与高价值客户一致的特定人口统计,我们在订阅媒体市场(例如付费电视)中有 4 个“竞争对手”,分布相对稳定但不断变化[.55,0.2,0.1,0.15],最后一组有 15%的人没有任何特定的订阅服务,更喜欢按需消费免费内容。
https://www.livechatinc.com/blog/churn-rate/
第二大竞争对手(b)刚刚推出了一款新的高端产品,现任者怀疑该产品正在侵蚀他们的市场份额。他们想知道如果他们不干预,最终会如何影响他们的市场份额。他们还想了解自己内部的客户流失动态,以及这与他们的市场份额之间的关系。
让我们假设他们知道他们有时会失去竞争对手的客户,包括免费内容,特别是随着他们的高平均每用户收入(ARPU)客户群的发展,他们有时会赢得客户,但他们不了解全貌。
所以,我们想象他们委托我们做一项研究。
为了简单起见,我们在这里对人口动态做了很多隐含的假设。例如,我们假设转移概率保持不变。
首先,我们进行一项市场调查,以了解消费者如何在不同的供应商之间移动,从那里我们可以构建一个概率矩阵如下:
a、b、c、d 代表我们的市场参与者。
市场研究表明,消费者从一个服务提供商转向另一个服务提供商的估计概率如下:
我们感兴趣的第一个问题是,考虑到所有其他流失概率,如果 A 继续以估计的速度流失客户到 B,将会发生什么。
使用我们之前导出的矩阵解,并用 Python 编码,我们可以计算新的平稳分布。
P = np.array([[0.9262, 0.0385, 0.01, 0.0253],
[0.01, 0.94, 0.01, 0.04],
[0.01, 0.035, 0.92, 0.04],
[0.035, 0.035, 0.035, 0.895]])A=np.append(transpose(P)-identity(4),[[1,1,1,1]],axis=0)b=transpose(np.array([0,0,0,0,1]))np.linalg.solve(transpose(A).dot(A), transpose(A).dot(b))
这给了我们新的平稳分布[0.19,0.37,0.18,0.25]
然而,当我们检查系数矩阵和增广矩阵的秩时,我们注意到,与更简单的例子不同,它们并不对应。这意味着分析问题的公式可能没有唯一的解,所以我们想用另一种技术来检验它。
NP . linalg . matrix _ rank(NP . append(A,NP . transpose(b . shape(1,5)),axis=1))
5
np.linalg.matrix_rank(A)
4
可以看出,迭代解(其中我们将转移矩阵提升到 n 的幂)不收敛,这给我们留下了模拟选项。
从上面我们可以估计,长期来看,平稳分布会是这样的:[0.19,0.4,0.18,0.23],实际上非常接近解析解。
换句话说,现有企业的市场份额预计将下降到 20%左右,而竞争对手的市场份额将上升到 40%左右。
由此也可以看出,对于更复杂的问题,现实世界中看似合理的解析解和模拟解,确实还是对应的。
我希望您喜欢这篇关于如何使用离散马尔可夫链解决现实世界问题的基本介绍,并鼓励您思考自己组织中可以用这种方式回答的问题。您还可以通过计算留住客户的价值来扩展这个示例,从而计算出在留住客户方面投资的价值。
版权所有 2020 Herman Scheepers
特此免费授予任何获得本条款中的代码和相关文档文件所暗示的本软件副本(“软件”)的人不受限制地经营本软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售本软件副本的权利,并允许获得本软件的人根据以下条件这样做:
上述版权声明和本许可声明应包含在软件的所有副本或重要部分中。
本软件按“原样”提供,不含任何明示或暗示的担保,包括但不限于对适销性、特定用途适用性和不侵权的担保。在任何情况下,作者或版权所有者都不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权诉讼或其他诉讼中,还是在与软件或软件的使用或其他交易相关的诉讼中。
音乐生成的马尔可夫链
从本文中,您将了解马尔可夫链模型,以及如何将它应用于音乐生成。
什么是马尔可夫链?
马尔可夫链是描述一系列可能事件的模型。这个序列需要满足马尔可夫假设——下一个状态的概率取决于前一个状态,而不是序列中的所有前一个状态。
这听起来像是对真实案例的简化。例如,为了应用马尔可夫链进行天气预测,我们需要假设明天的天气只取决于当前的天气,并假设没有其他因素,如一年中的时间等
尽管在许多情况下这种简化,我们将能够生成有用的预测,但同时,我们将能够通过降低计算成本来更快地解决我们的任务。
马尔可夫链模型在金融、自然语言处理和任何有时间序列数据的地方都有很多应用。
用马尔可夫链生成音乐
有很多优秀的论文和博客文章解释了马尔可夫链。所以不深究理论细节,让我们把这个模型应用到实践上!马尔可夫链最普遍的应用是语言和语音,例如,预测句子中的下一个单词。但是如果我们尝试创造音乐呢?
和自然语言一样,我们可以把音乐想象成一系列音符。但是因为我弹吉他,所以我会用和弦来操作。如果我们研究和弦序列并学习它的模式,我们会发现某些和弦可能更多地跟随特定和弦,而其他和弦很少跟随那个和弦。我们将构建我们的模型来发现和理解这种模式。
好吧,计划是这样的:
- 取和弦集
- 计算和弦跟随特定和弦的概率分布
- 定义第一个和弦或随机选择
- 考虑概率分布,随机选择下一个和弦
- 对生成的和弦重复步骤 4
- …
- 随机音乐太棒了!
分步指南:
对于数据源,我准备了一个带有和弦序列的 CSV 文件,这些和弦序列来自利物浦的一个著名乐队。你可以在 GitHub 上找到这个文件。
序列示例:
['F', 'Em7', 'A7', 'Dm', 'Dm7', 'Bb', 'C7', 'F', 'C', 'Dm7',...]
首先,我们制造二元模型:
['F Em7', 'Em7 A7', 'A7 Dm', 'Dm Dm7', 'Dm7 Bb', 'Bb C7', ...]
现在,如果我把和弦 F 作为一个序列中的初始和弦,其他和弦跟随它的概率是多少?
有 18 个以和弦 F 开头的二元组:
['F Em7', 'F C', 'F F', 'F Em7', 'F C', 'F A7sus4', 'F A7sus4', ...]
然后,我们将计算每个独特的二元模型在序列中出现的频率:
{'F Em7': 4, 'F C': 4, 'F F': 3, 'F A7sus4': 4, 'F Fsus4': 2, 'F G7': 1}
如果我们归一化,我们会得到概率:
{'F Em7': 0.222,
'F C': 0.222,
'F F': 0.167,
'F A7sus4': 0.222,
'F Fsus4': 0.111,
'F G7': 0.056}
这通常可以用图表的形式来解释:
Weighted graph of possible next chord
这个图的每个节点,除了中间的初始节点 F,代表了我们的序列可以达到的可能状态,在我们的例子中,它们是可能跟随 F 的弦,一些弦比其他弦有更高的概率,一些弦根本不能跟随 F 弦,例如 Am,因为没有二元模型可以将这个弦与 F 组合。
现在,马尔可夫链是一个随机过程,或者你更喜欢随机过程。为了进入下一个状态,我们将随机选择和弦,但是根据概率分布,在我们的例子中,这意味着我们更有可能选择和弦 C 而不是 G7。
对于给定的和弦 F,下一个和弦有 6 个候选和弦:
options
>>> ['Em7', 'C', 'F', 'A7sus4', 'Fsus4', 'G7']
每个和弦都有相应的概率:
probabilities
>>> [0.222, 0.222, 0.167, 0.222, 0.111, 0.056]
Numpy 由于 1.7.0 版本可以根据给定的概率分布执行随机采样,所以我们使用:
import numpy as npchoise = np.random.choice(options, p=probabilities)
假设我们随机选择的结果是 Em7。现在我们有了一个新的状态,可以再次重复整个过程。
整个工作流程如下所示:
# Our current state
chord = 'F'# create list of bigrams which stats with current chord
bigrams_with_current_chord = [bigram for bigram in bigrams if bigram.split(' ')[0]==chord]# count appearance of each bigram
count_appearance = dict(Counter(bigrams_with_current_chord))# convert apperance into probabilities
for ngram in count_appearance.keys():
count_appearance[ngram] = count_appearance[ngram]/len(bigrams_with_current_chord)# create list of possible options for the next chord
options = [key.split(' ')[1] for key in count_appearance.keys()]
# create list of probability distribution
probabilities = list(count_appearance.values())# Make random prediction
np.random.choice(options, p=probabilities)
因为这是一个随机过程,每次你运行这个模型,都会得到不同的结果。为了实现可重复性,您可以像这样设置种子:
np.random.seed(42)
我们可以将整个过程概括为两个功能:
def predict_next_state(chord:str, data:list=bigrams):
"""Predict next chord based on current state."""
# create list of bigrams which stats with current chord
bigrams_with_current_chord = [bigram for bigram in bigrams if bigram.split(' ')[0]==chord]
# count appearance of each bigram
count_appearance = dict(Counter(bigrams_with_current_chord))
# convert apperance into probabilities
for ngram in count_appearance.keys():
count_appearance[ngram] = count_appearance[ngram]/len(bigrams_with_current_chord)
# create list of possible options for the next chord
options = [key.split(' ')[1] for key in count_appearance.keys()]
# create list of probability distribution
probabilities = list(count_appearance.values())
# return random prediction
return np.random.choice(options, p=probabilities)def generate_sequence(chord:str=None, data:list=bigrams, length:int=30):
"""Generate sequence of defined length."""
# create list to store future chords
chords = []
for n in range(length):
# append next chord for the list
chords.append(predict_next_state(chord, bigrams))
# use last chord in sequence to predict next chord
chord = chords[-1]
return chords
现在我们可以生成一个我们想要的长度的序列:
generate_sequence('C')
序列示例:
['Bb',
'Dm',
'C',
'Bb',
'C7',
'F',
'Em7',
'A7',
'Dm',
'Dm7',
'Bb',
'Dm',
'Gm6'
...
]
我试着用吉他弹奏它,它听起来确实像一首来自利物浦的乐队可能写的歌。唯一缺少的是文本,但我们可以使用在文本语料库上训练的相同模型来为歌曲生成文本:)。
摘要
我们仅仅用简单的马尔可夫链触及了冰山一角,随机模型的世界是如此之大,包括隐马尔可夫链、马尔可夫链蒙特卡罗、哈密顿蒙特卡罗等等。但是在每个模型的本质上都有相同的马尔可夫假设——下一个状态依赖于当前状态,而不依赖于先前的状态序列。
因为这个简单而强大的规则,马尔可夫链模型在许多领域得到了应用,也可以成功地应用于音乐的产生。
这里最酷的事情之一是,我们将根据我们训练模型的语料库得到不同的结果。在来自电台司令和模型的语料库上训练将生成电台司令风格的和弦序列。
代码和数据集可以在我的 GitHub 资源库中找到。
参考资料:
体育运动中的马尔可夫链模型
*一个模型从数学上描述了我们对数据的期望——*在这种情况下,来自体育数据。一种简单类型的模型,称为马尔可夫链,在几种不同运动的分析中得到应用——每一种运动都有某种离散的性质,我很快会对此进行精确的解释。属于这一类的运动包括网球、棒球和排球。对于这篇博文,我会考虑网球。
Tennis star Serena Williams
如果一个模型描述了我们对数据的期望,我们必须承认所涉及的数据很难捕捉到游戏的一切。具体来说,网球的马尔可夫链模型描述了我们对有限数据的预期——这些数据只记录了哪个球员在比赛中赢得了每一分。关于其他一切的信息,如球的轨迹,甚至截击的长度或发球的失误,仍然是未知的。此外,数据只涉及两个玩家之间相遇的一小部分。网球比赛分成几组,几组分成几场比赛。所以如果小威赢得了她的第一场比赛,她将需要留下来赢得更多的比赛。我们的模型只关注这些游戏中的一个游戏的分数结果数据。
在网球比赛中,当一名选手达到两个目标时,每场比赛就赢了:她的得分(1)必须至少达到 4 分,并且(2)必须超过对手 2 分。分数以“爱”(0 分)开始,然后是“15”(1 分)、“30”(2 分)、“40”(3 分)。如果双方都至少得了 2 分,比分就是“平手”。如果两个玩家都至少得 2 分,但其中一个领先 1 分,则得分为“优势*【那个玩家】”。*
每打出一个点,只有两种情况可能发生:一个玩家(姑且称她为“A”)可以赢得该点,或者另一个玩家(姑且称她为“B”)可以赢得该点。该模型将值 p 分配给玩家 A 赢得一分的概率,并将值 q 分配给玩家 B 获胜的概率。对于每个点,不存在其他可能性,所以 p + q = 1。重要的是,该模型假设这些概率永远不会改变,无论游戏如何展开。此外,每个点的结果独立于其他点的结果。
我把游戏的每一个分数放在一个图表上(见下面),并用箭头指出,哪个分数可以导致下一个分数,导致其他分数。在马尔可夫链术语中,每个分数代表游戏的一个状态,从这个状态可以发生零个或多个转换到其他状态。如上所述,从大多数状态来看,恰好存在两种可能的转换(A 赢得下一点,或者 B 赢得下一点)。在网球中,有 15 种这样的状态,显示为圆圈。马尔可夫链术语称它们为瞬态。从另外两个状态开始,游戏不再继续,也不会发生进一步的转换。我将这些异常的吸收态显示为矩形,分别标记为“A 赢”和“B 赢”我们的建模假设意味着,游戏最终肯定会离开所有的瞬态,进入一个吸收态(因此有了这个术语)。经验证实了这一预期。
A diagram of the Markov chain for tennis
在这个图中,每个圆都有两个箭头。如果玩家 A 赢得这一点,游戏向左转移,沿着标有 p (其概率)的箭头指向“A 赢”。然而,对于概率 *q,*游戏遵循另一个箭头,(记住 p + q = 1),向右朝着“B 赢。”
是什么让这个模型成为马尔可夫链?首先,状态之间的特定转换仍然是不确定的,但是,像所有随机现象一样,服从可量化的概率规则。第二,该模型满足被称为马尔可夫属性的条件,该条件向分析师保证,为了预测关于游戏未来的任何事情,游戏的当前状态包括关于游戏的所有相关信息(过去和当前),这些信息可以帮助做出这样的预测(未来)。
换句话说,Markov 属性断言,假设我们已经知道当前状态,那么通过图采取的先前路径不会给我们提供有用的额外信息来对游戏进行预测。例如,如果 A 赢得了前 3 分,但随后输掉了接下来的 3 分,游戏可能会进入平手状态。或者,A 可能会失去 3 个未回答的点,然后赶上。还存在许多其他平手的途径,实际上是无限的,因为游戏可能会在平手、优势 A 和优势 b 之间无限波动。马尔科夫属性表明,无论采取哪种途径,对未来的预测都只取决于当前状态平手,而不是游戏如何到达那里。
马尔可夫属性仍然只是一个建模假设。关于真正的网球是真的吗?模型不会告诉我们。只有从许多实际游戏中获得大量数据,我们才能评估支持或反对这一假设的证据的强度。相反,体育运动中流行的“动量”概念可能表明,最近得分更多的球员有更有利的未来——比马尔可夫链预测的更有利。或者,一个“重整旗鼓以东山再起的假设”可能暗示,最近输球的玩家比我们的模型所认为的更有机会获胜。不用说,马尔可夫性质明确地否定了这些可能性:根据我们编纂的假设,不存在这样的现象。
统计学家经常重复乔治·博克斯的话,说所有的模型都是错的,但有些是有用的。马尔可夫链可能不能完美地代表网球,但该模型仍然有用,因为它可以产生对比赛的宝贵见解。请注意,该模型只包含一个参数, p 或 q (一个参数,因为这两个量加起来等于 1——一旦知道了其中一个,就可以确定另一个)。有了这些知识,个人的结果仍然是不确定的,但你可以发现任何事件的概率,此外,任何与游戏相关的量的分布。
例如,知道了 p 不会让你知道 A 是否会赢得任何给定的分数,更不用说任何给定的游戏、盘或比赛。当然啦!也就是说,知道了 p ,模型将允许你确定 A 赢得游戏的概率,至少假设建模假设成立。此外,虽然您无法预先知道任何一个特定游戏将持续多长时间,但您可以发现,例如,在一个模型游戏中所玩点数的分布。事实上,您可以计算这种分布的相关统计数据——包括平均值、中值、标准差,甚至超过 10 分的游戏比例。事实上,所有这些计算都可以完成,不仅仅是对单个值的 p ,而是对任何可能的值,这使得模型真正有用,并给建模者带来了希望,即关于模型的一般事实将转化为关于游戏的深刻见解。如果我们碰巧观察到一场或多场比赛持续超过 50 分,在一场有 250 场比赛的锦标赛中,假设所有球员都旗鼓相当,我们应该有多惊讶?用我们的模型对网球进行分析,证实了 Box 的格言,尽管在许多细节上不可避免地存在错误,但仍可能证明是有启发性的。
马尔可夫链蒙特卡罗
将您对 MCMC 的理解提升到中级水平
当我学习马尔可夫链蒙特卡罗(MCMC)时,我的导师告诉我们有三种方法来解释 MCMC。
- 基本知识:MCMC 允许我们利用计算机来做贝叶斯统计。
- 中级 : MCMC 是一种可以找到我们感兴趣的参数的后验分布的方法。具体来说,这种类型的算法以一种依赖于马尔可夫属性的方式生成蒙特卡罗模拟,然后以一定的速率接受这些模拟以获得后验分布。"
- 进阶:一堂完整的统计学课。
我写这篇博客的目的是让你达到中级水平。
先从基础的开始吧。
MCMC 到底是什么?要回答这个问题,我们首先需要复习一下贝叶斯统计。贝叶斯统计是建立在这样一个理念上的,即一件事情发生的概率受事先假设的概率和数据显示的某件事情发生的可能性的影响。在贝叶斯统计中,概率用分布来表示。
如果先验和似然概率分布是正态分布,我们就能够用一个函数来描述后验分布。这被称为封闭解。这种类型的贝叶斯如下所示。正如你所看到的,后验分布是由先验分布和似然分布共同形成的,并在中间的某处结束。
Created in Matplotlib inspired by Matt Brems
但是当概率不是很大的时候呢?当概率看起来更像这样时会发生什么?
Rbb [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0)], from Wikimedia Commons
在这种情况下,可能性没有正态分布,所以我们最终得到一个右偏后验分布。因为我们不能用公式来表达,我们必须使用马尔可夫链蒙特卡罗。
马尔可夫链蒙特卡罗的三个部分
一:蒙特卡洛
- 蒙特卡罗模拟通过生成随机数来模拟复杂系统。
- 在下面的 gif 的情况下,蒙特卡洛生成一个参数为(0-1,0-1)的随机点,通过确定曲线下结束的点的数量,我们能够近似整个圆的面积,并从π开始。
nicoguaro [CC BY 3.0 (https://creativecommons.org/licenses/by/3.0)], from Wikimedia Commons
二:马尔可夫链
- 马尔可夫链本质上是一个变量如何在图中“行走”的表示,或者一个随机变量如何随时间从一种状态改变到另一种状态。
image source http://www.mathcs.emory.edu/~cheung/
- 上图展示了情绪状态的马尔可夫链。在这个链条中,如果你很快乐,有 20%的几率你会把情绪状态变成一般,20%的几率你会变得悲伤,60%的几率你会保持快乐。
马尔可夫链由马尔可夫属性决定
F(Xt+1|Xt) = f(Xt+1|Xt,Xt-1,Xt-2,….)
如果我知道现在正在发生什么,知道发生了什么让我们走到这一步或前一步,等等。没给我提供更多信息。
这方面例子有:
- 孟德尔遗传学。在下面的例子中,子豆的颜色完全受父豆的颜色影响。第一代的豆子颜色受到前一代的影响,但在确定第二代的颜色时不需要考虑这一点。
Pbroks13 [CC BY-SA 3.0 (https://creativecommons.org/licenses/by-sa/3.0)]
- 棋盘游戏:当玩大富翁游戏并试图确定玩家去某个空间的概率时,你需要的唯一信息是玩家目前在哪里。玩家之前的回合在哪里并不影响它接下来的走向,除了它决定了这一回合在哪里。
三:接受-拒绝抽样
MCMC 的第三部分是接受-拒绝抽样。当我们对新的观察进行采样时,我们决定它是否在正确的方向上,然后决定我们是保留它还是丢弃它。
两种常见的接受-拒绝算法是 Metropolis-Hasting 算法和不掉头采样器。不准掉头的数学比我在这篇中等文章中解释的要复杂,但是如果你想深入研究,可以看看这篇文章。
这是我对大都市生活的高层次解释
- 我们在 x 点。
- 我们对下一步做一个猜测。我们称之为 x*
- 然后,我们计算 x*/x 的概率比。这是使用似然性和先验分布的乘积计算的。
- 如果 p(x*)/p(x)的比值(也称为接受概率)大于 1,我们接受 x*作为新位置。
- 即使接受概率小于 1,我们也不自动拒绝 x*。我们通过从均匀(0,1)分布中选择一个随机数来抛硬币。如果数字小于接受概率,我们接受 x*,如果数字大于接受概率,我们拒绝 x*,并重新开始这个过程。
把所有的放在一起
- 我们随机生成数字:这是蒙特卡罗部分
- 我们允许我们生成的数字影响下一个生成的数字:这就是马尔可夫链
- 然后我们决定生成的新数字是否“朝着正确的方向前进”:接受-拒绝算法
- 然后我们检查收敛性:我们确定我们的数据何时收敛到一个合理的分布。收敛点之后随机生成的值成为我们的后验分布
我希望这有助于您在中级水平上理解 MCMC。
1.(经允许)直接从马特·布莱姆斯的演讲中借用。
2。一个很棒但是很数学的 MCMC 移植:https://blog . stata . com/2016/11/15/Bayesian-statistics-introduction-to-part-2-MCMC-and-the-metropolis-Hastings-algorithm/
马尔可夫链和 hmm
内部 AI
主要概念、属性和应用
Hidden Markov
在本文中,我们将关注马尔可夫模型,何时何地应该使用它们,以及隐马尔可夫模型。本文将着重于理论部分。在第二篇文章中,我将展示这些主题的 Python 实现。
马尔可夫模型,尤其是隐马尔可夫模型(HMM)用于:
- 语音识别
- 书写识别
- 物体或人脸检测
- 经济情景生成和特定财务任务
- 和几个 NLP 任务…
本文原载于我的个人博客:【https://maelfabien.github.io/machinelearning/HMM_1/#
我在这个资源库上发布我所有的文章和相应的代码:
本报告包含练习、代码、教程和我的个人博客文章
github.com](https://github.com/maelfabien/Machine_Learning_Tutorials)
不要犹豫开始回购:)
一.随机模型
Discrete-Time Stochastic Process
让我们从定义什么是随机模型开始。它本质上是一个离散时间过程,在时间 1,2,…取值,称为“状态,观察到:q1,q2,…”。状态简单地对应于过程的实际值,通常由有限空间定义:S=1,…Q。
该过程从初始状态开始 q1。然后,根据转移概率,我们在状态之间移动。我们可以使用贝叶斯法则计算状态序列的概率:
为了描述模型的特征,我们需要:
- 初始概率 P(q1)
- 所有的转移概率
正如你可能猜到的,这很难实现,因为我们需要知道很多参数。
二。离散时间马尔可夫链模型(DTMC)
1.什么是马尔可夫链?
DTMC
离散时间马尔可夫链(DTMC)是时间和事件的离散随机过程。马尔可夫链依赖于马尔可夫特性,即在过程中有一个有限的相关性:
让我们来说明这一点:考虑一个简单的迷宫,其中有一只老鼠被困。我们将把 qt 表示在 t 步之后老鼠所处的迷宫的位置。我们假设老鼠对它在迷宫中走过的路程没有记忆(T21)。它只是按照写在每一步棋旁边的概率,随机地走到那个位置。
DTMC Illustration
这里的状态可以代表很多东西,包括在 NLP 中。例如,我们可以:
- 1 =名词,
- 2 =动词,
- 3 =形容词…
例如,我们会对名词后有动词的概率感兴趣。
2.转移概率
如果离散时间马尔可夫链的转移概率不依赖于时间 t,则称其为齐次:
我们可以将该过程概括为一个转移矩阵,表示为 A =【AIJ】,i ∈ 1…Q,j ∈ 1…Q。如果:
- 所有条目都是非负的
- 每行总计为 1
在我们的例子中,转移矩阵是:
Transition matrix
注意,如果 a 是随机的,那么 A^n 也是随机的。
3.州
描述一个状态有几种方式。设 pii 为离开 I 后回到状态 I 的概率:
- 如果 pii <为 1,则状态 I 为瞬态
- 如果 pii=1,状态 I 是循环的
- 如果 aii=1,则状态 I 正在吸收
因此,如果返回到表示为 Tii 的相同状态之前的平均时间是有限的,则状态是正循环的。
如果一个状态 j 可以从任何其它状态 I 经过有限步到达,则 DTMC 是不可约的。不可约的 DTMC 实际上是一个强连通的图。
如果离散时间马尔可夫链只能在大于 1 的某个整数的倍数处返回状态,那么该链中的状态就是周期性的。
例如:
Periodic Markov Chain
否则称为非周期性。具有自循环的状态总是非周期性的。
4.逗留时间
设 Ti 是跳到其他状态之前在状态 I 花费的时间。
然后,Ti,即逗留时间,遵循几何分布:
预期花费的平均时间是 E(T)=1 / aii
5.m 步转换
在 m 个步骤中从 I 到 j 的概率表示为:
M-step transition
我们可以将 a22(4)视为时间 t=4 时鼠标位于位置 2 的概率。因此,从 I 到 j 正好 n 步的概率由 fij(n)给出,其中:
6.状态的概率分布
设πi(n)是在时间 n 处于状态 I 的概率:πI(n)= P(Xn = I)
那么,π(n)=[π1(n),π2(n),…]是概率分布的向量,它取决于:
- 初始转移矩阵 A
- 初始分布π(0)
注意π(n+1) = π(n)A,递归地:
对于不可约/非周期 DTMC,分布π(n)收敛到一个极限向量π,它与π(0)无关,是π = πP 的唯一解
并且∑i πi = 1
πi 也叫定态概率,稳态或均衡分布。
7.生成序列
为了模拟老鼠在迷宫中的路径,我们可能希望生成序列。
当我们想产生一个序列时,我们从一个初始状态 q1=1 开始。总的想法是:
- 我们选择一个随机数来知道我们应该从哪个状态开始
- 然后,选择一个随机数来知道我们移动到哪个状态
假设我们有以下简单的模型:
这对应于下面的矩阵 A 和初始概率向量π:
生成器的工作方式如下,通过连续抽取随机数来识别哪个过渡是指。
Sequence Generation, Step-by-step
第一步,我们选择一个随机数,看看它在初始概率向量中的位置。这给了我们第一个状态。
然后,我们选择下面的数字,它对应于状态 q1 的转移概率(矩阵 A 的第一行)。如果值小于 0.3,我们停留在 q1。否则,我们移到 q2。诸如此类…
8.解码序列
解码一个序列的目的是识别通向当前状态的最可能的路径。例如,如果鼠标处于状态 3,并经过 5 步到达那里,您需要确定最可能的路径。
9.用例
可以使用马尔可夫链:
- 通过解码字符序列并识别最可能的语言来识别句子的语言。
- 预测宏观经济形势,如市场崩溃和衰退与扩张之间的周期。
- 预测资产和期权价格,并计算信用风险。
- …
三。隐马尔可夫模型
隐马尔可夫模型(HMM)广泛用于:
- 语音识别
- 书写识别
- 物体或人脸检测
- 词性标注和其他自然语言处理任务…
我推荐看看 Luis Serrano 在 HMM 上做的介绍。
我们将把重点放在词性标注上。词性标注是一个过程,通过这个过程,我们能够将一个给定的单词标注为名词、代词、动词、副词…
例如,PoS 可以用于文本到语音的转换或词义消歧。
在这个具体情况下,同一个单词bear
有完全不同的意思,对应的 PoS 也因此不同。
让我们考虑下面的场景。在你的办公室里,有两个同事经常聊天。你知道他们要么谈论工作要么谈论假期。因为他们看起来很酷,你想加入他们。但是你离理解整个对话太远了,你只能听到句子中的一些单词****
在加入对话之前,为了不显得太怪异,你想猜猜他说的是工作还是假期。例如,你的朋友可能会说这样的句子:
1.排放概率
你只听清楚 python 或 bear 这几个字,并试着猜测句子的上下文。由于你的朋友都是 Python 开发人员,所以当他们谈论工作时,他们 80%的时间都在谈论 Python。
这些概率被称为排放概率。
2.转移概率
你听着他们的对话,每分钟都在试图理解这个话题。你朋友的谈话有某种连贯性。事实上,如果一个小时他们谈论工作,下一分钟他们谈论假期的可能性更低。
我们可以为这种情况定义我们称之为的隐马尔可夫模型:
改变或不改变话题的概率被称为转移概率。
- 你理解的词语被称为观察,因为你观察它们。
- 他们谈论的主题被称为隐藏状态,因为你无法观察到它。
3.离散时间隐马尔可夫模型
HMM λ是由两个随机过程组合而成的序列:
- 一个观察到一个:O=o1,o2,…,oT,这里的话
- 一个隐藏的一:q=q1,q2,…qT,这里是谈话的话题。这被称为过程的状态。
HMM 模型由下式定义:
- 初始概率的向量 π=[π1,…πq],其中πi=P(q1=i)
- 未观察到的序列 a 的转移矩阵:a =[AIJ]= p(Qt = j∣qt1 = j)****
- 观察值的概率矩阵b =【bki】= p(ot = sk∣Qt = I)****
HMMs 背后的主要假设有哪些?
- 观测值对隐藏态的条件独立性:p(O1,…,ot,…,oT ∣ q1,…,qt,…,qT,λ) = ∏i P(ot ∣ qt,λ)
- 平稳马尔可夫链 : P(q1,q2,…,Qt)= p(q1)p(q2∣q1)p(q3∣q2)…p(qt∣qt−1)
- 观测值和状态序列的联合概率:p(O1,o2,…oT,q1,…,qT ∣ λ) = P(o1,…,oT ∣ q1,…,qT,λ) P(q1,…,qT)
HMM 是贝叶斯网络的一个子案例。
4.求转移概率
跃迁概率是基于我们所做的观察。我们可以假设,在仔细听完之后,每一分钟,我们都能理解他们谈论的话题。不过,这并没有给我们提供他们目前正在谈论的话题的全部信息。
在过去的 15 分钟里,你有 15 次观察, W 表示工作, H 表示假期。
我们注意到,在五分之二的情况下,话题工作导致话题假期,这解释了上图中的转移概率。
5.找出排放概率
因为我们对他们讨论的话题有观察,并且我们观察了讨论中使用的词语,我们可以定义排放概率的估计值:
6.随机时间内某个主题的概率
假设你要去喝咖啡,当你回来的时候,他们还在说话。你根本不知道他们在说什么!在那个随机时刻,他们谈论工作或假期的概率是多少?
我们可以从之前的观察中数出:10 次他们谈论假期,5 次谈论工作。因此,它表明我们有 1/3 的机会让他们谈论工作,2/3 的机会让他们谈论假期。
7.如果听到“Python”这个词,每个题目的概率是多少?
如果你听到“Python”这个词,那么这个话题是工作还是假期的概率就是用贝叶斯定理定义的!
接近 57%。
8.如果你听到一个单词序列,每个题目的概率是多少?
让我们从连续两次观察开始。假设我们连续听到“Python”和“Bear”这两个词。有哪些可能的组合?
- 巨蟒和工作联系在一起,熊和工作联系在一起
- 蟒蛇和假期联系在一起,熊和工作联系在一起
- 蟒蛇和假期联系在一起,熊和假期联系在一起
- 蟒蛇和工作联系在一起,熊和假期联系在一起
这些场景可以这样总结:
所以最有可能隐藏的状态就是节假日和假期。如果你听到两个以上的单词呢?假设是 50?计算所有可能的路径变得非常具有挑战性!这就是为什么维特比算法被引入,以克服这个问题。
9.维特比算法解码
维特比算法**背后的主要思想是,当我们计算最优解码序列时,我们并不保留所有的潜在路径,而是只保留最大似然对应的路径。**
它是这样工作的。我们从一系列观察到的事件开始,比如说Python, Python, Python, Bear, Bear, Python
。这个序列简单地对应于一个观察序列:P(o1,o2,…,oT ∣ λm)
对于第一个观察,假设我们观察 Python,主题是 Work 的概率是它是 Work 的概率乘以假设它是 Work,它是 Python 的概率。
最可能的状态序列简单地对应于:
然后我们可以继续下一个观察。接下来会发生什么:
对于每个位置,我们使用前一个主题是工作或假期的事实来计算概率,对于每个情况,我们只保留最大值,因为我们的目标是找到最大可能性。因此,下一步是对假日主题进行同样的估计,并保持两条路径之间的最大值。
如果您解码整个序列,您应该会得到与此类似的东西(我已经对每一步的值进行了舍入,所以您可能会得到稍微不同的结果):
因此,当我们观察Python, Python, Python, Bear, Bear, Python
时,最有可能的序列是Work, Work, Work, Holidays, Holidays, Holidays
。
如果在这么长时间的跟踪之后,你终于去和你的同事聊天,你应该期待他们谈论假期:)
在时间 T 结束于状态 I 并且对应于观测 o1,…,oT 的潜在状态的最佳序列的联合概率由δT(i)表示。这是上述可能的途径之一。
通过递归,可以表明:
其中 bj 表示观察矩阵 B 的概率,aij 表示未观察序列的转移矩阵的值。这些参数是从一系列观察值和可用状态中估计出来的。δ就是我们在前进的每一步中取的最大值。
我不会在这里详细讨论。你应该简单地记住有两种方法来解决维特比,向前(正如我们已经看到的)和向后。
当我们只观察到部分序列并且面对不完整的数据时,使用 EM 算法。
10.生成序列
正如我们在马尔可夫链中看到的,我们可以用 hmm 生成序列。为此,我们需要:
- 首先产生隐藏状态 q1
- 从 q1 开始,生成 o1,例如 Work then Python
- 然后产生 q1 到 q2 的转换
- 从 q2 生成 o2
- …
流程是如何运作的?如上所述,这是一个两步过程,我们首先生成状态,然后进行观察。
Sequence Generation
结论:
👏👏👏
在本文中,我们介绍了马尔可夫链和 hmm 的基本理论,包括术语、假设、性质、序列生成和解码。
我希望这篇关于马尔可夫链和隐马尔可夫模型的介绍是有帮助的。我在下面的部分列出了我的消息来源。
在下一篇文章中,我将尝试用 Python 来说明这些概念。
来源:
- 国家高级矿业学院:https://www.emse.fr/~xie/SJTU/Ch4DMC.ppt
- MVE220 财务风险:http://www . math . chalmers . se/Stat/grund ub/CTH/mve 220/1617/reding projects 16-17/intromarkovchainsandapplications . pdf
- Udacity 的 HMMs:https://www.youtube.com/watch?v=kqSzLo9fenk
- 个人博客主持人:https://maelfabien.github.io/machinelearning/HMM_1/#
- 个人博客嗯:https://maelfabien.github.io/machinelearning/HMM_2/#
马尔可夫链:如何训练文本生成像乔治·马丁那样写作
马尔可夫链已经存在了一段时间,而且还会继续存在。从预测键盘到交易和生物学应用,它们已经被证明是多功能工具。
下面是一些马尔可夫链的行业应用:
- 文本生成(你是为此而来的)。
- 金融建模和预测(包括交易算法)。
- 物流:模拟未来的运输或行程。
- 搜索引擎:PageRank 可以看作是用马尔可夫链模拟一个随机的互联网冲浪者。
到目前为止,我们可以告诉这个算法是有用的,但到底什么是马尔可夫链?
什么是马尔可夫链?
马尔可夫链是一个随机过程,它模拟一组有限的状态,具有从一个给定状态跳到另一个状态的固定的条件概率。
这意味着,我们将有一个“代理”,它随机地在不同的状态之间跳跃,有一定的概率从一个状态跳到另一个状态。
为了展示马尔可夫链是什么样子,我们可以使用一个有向图,其中每个节点是一个状态(带有标签或相关数据),从节点 a 到节点 b 的边的权重是从状态 a 跳到状态b的概率。
这里有一个例子,将天气建模为马尔可夫链。
我们可以将从状态 a 到状态 b 的概率表示为矩阵分量,其中整个矩阵表征了我们的马尔可夫链过程,对应于有向图的邻接矩阵。
然后,如果我们将当前状态表示为一个独热编码,我们可以通过获取当前状态并查看其对应的行来获得下一个状态的值的条件概率。
之后,如果我们重复采样由第 n 个状态的行描述的离散分布,我们可以模拟一系列任意长度的状态。
文本生成的马尔可夫链
为了用马尔可夫链生成文本,我们需要定义一些东西:
- 我们的国家会是什么样的?
- 从一个状态跳到另一个状态的概率是多少?
我们可以为文本生成做一个基于字符的模型,其中我们将我们的状态定义为我们看到的最后 n 个字符,并尝试预测下一个字符。
我已经在我的用于文本生成的LSTM文章中对此进行了深入研究,结果喜忧参半。
在这个实验中,我将选择使用之前的 k 单词作为我的当前状态,并对下一个令牌的概率进行建模。
为了做到这一点,我将简单地为每一个由 k 个单词组成的不同序列创建一个向量,它有 N 个组成部分,其中 N 是我的语料库中不同单词的总数。
然后我会在第 i 个向量的第 j 个分量上加 1,其中 I 是第Ik 个单词序列的索引, j 是下一个单词的索引。
如果我归一化每个单词向量,那么我将有下一个单词的概率分布,给定前面的 k 记号。
迷惑?让我们看一个小语料库的例子。
训练我们的链条:玩具例子。
假设我的语料库是下面这句话。
This sentence has five words
我们将首先选择 k :在采样/ 预测下一个单词之前,我们的链将考虑的单词量。对于这个例子,让我们使用 k=1。
现在,我们的句子中有多少个不同的单词序列?它有 5 个,每个单词一个。如果它有重复的单词,他们不会添加到这个数字。
我们将首先初始化一个 5×5 的零矩阵。
之后,我们将在“this”行的“sentence”对应的列中加 1。然后在“句子”的行上加上 1,在“has”的列上加上 1。我们将继续这个过程,直到我们看完整个句子。
这将是生成的矩阵:
The diagonal pattern comes from the ordering of the words.
因为每个单词只出现一次,所以这个模型只是一遍又一遍地生成同一个句子,但是你可以看到添加更多的单词会使这个变得有趣。
我希望现在事情更清楚了。让我们跳到一些代码!
用 Python 编写我们的马尔可夫链
现在是有趣的部分!我们会在整个一首冰与火之歌文集上训练一个马尔可夫链(哈!你以为我会引用这部剧吗?太糟糕了,我是个爱看书的人!).
然后我们将为 k 生成不同值的句子。
在这个实验中,我决定将两个空格之间的任何内容都视为一个单词或标记。
按照惯例,在自然语言处理中,我们处理标点符号(如’,‘或’.')作为令牌。为了解决这个问题,我将首先以两个空格的形式给每个标点符号添加填充。
下面是这个小预处理以及加载语料库的代码:
我们将立即开始训练我们的马尔可夫链,但首先让我们看看我们的数据集:
我们有超过 200 万个代币,代表超过 32000 个不同的单词!对于一个作家来说,这是一个相当大的语料库。
要是他能多加 80 万就好了……
训练我们的链条
继续,下面是我们如何为任意的 k (在本例中为 2)初始化我们的“k 序列后的单词”计数矩阵。
语料库中有 2185918 个单词,429582 个不同的 2 个单词的序列,每个序列后面都有 32663 个单词中的一个。
这意味着矩阵中只有 0.015%多一点的成分是非零的。
因此,我使用了 scipy 的 dok_matrix ( dok 代表键的字典),一个稀疏矩阵实现,因为我们知道这个数据集将非常稀疏。
在初始化我们的矩阵后,采样是非常直观的。
下面是代码:
这里有两件事可能引起了你的注意。第一个是 alpha 超参数。
这是我们的链的创造力:一个(通常很小,或零)的机会,它会选择一个完全随机的单词,而不是语料库建议的那些。
如果数字很高,那么下一个单词的分布将接近均匀。如果为零或更接近,那么分布将更接近语料库中看到的分布。
对于我将展示的所有示例,我使用了值为 0 的 alpha 。
第二件事是加权选择函数。我必须实现它,因为 Python 的随机包不支持超过 32 个元素的列表的加权选择,更不用说 32000 个元素了。
结果:生成的句子
首先,作为基线,我尝试了一种确定性的方法:如果我们选择一个单词,使用 k=1,并总是跳到当前单词之后最有可能的单词,会发生什么?
至少可以说,结果并不令人满意。
**I** am not have been a man , and the Wall . " " " "
**he** was a man , and the Wall . " " " " " " "
**she** had been a man , and the Wall . " " " " " "
因为我们是确定性的,“a”后面总是跟着“man”,“the”后面总是跟着“Wall”(呵呵)等等。
这意味着我们的句子会很无聊,可预测,而且有点荒谬。
现在对于一些实际的世代,我尝试使用一个词的随机马尔可夫链,α值为 0。
一词马尔可夫链结果
以下是一些由 15 个单词组成的句子,种子单词用粗体表示。
'**the** Seven in front of whitefish in a huge blazes burning flesh . I had been'
'**a** squire , slain , they thought . " He bathed in his head . The'
'**Bran** said Melisandre had been in fear I've done . " It must needs you will'
'**Melisandre** would have feared he'd squired for something else I put his place of Ser Meryn'
'**Daenerys** is dead cat - TOOTH , AT THE GREAT , Asha , which fills our'
'**Daenerys** Targaryen after Melara had worn rich grey sheep to encircle Stannis . " The deep'
正如你所看到的,产生的句子是非常荒谬的,尽管比前几个有趣得多。
每一对单词都有一定的意义,但整个序列完全没有意义。
这个模型确实学到了一些有趣的东西,比如丹妮莉丝后面通常跟着坦格利安,对于只知道前一个单词来说,“本该害怕”是一个很好的结构。
然而,总的来说,我认为这还远远没有达到它应有的水平。
当增加单词链的 alpha 值时,我得到的句子开始变得更加随机。
2 字马尔可夫链的结果
两个单词的链产生了一些更有趣的句子。
尽管它通常听起来完全随机,但它的大部分输出可能会在开始时愚弄你一会儿。
'**the world** . *And Ramsay loved the feel of grass* *welcomed them warmly* , the axehead flew'
'**Jon Snow** . *You are to strike at him* . *The bold ones have had no sense*'
'**Eddard Stark** had done his best to give her *the promise was broken* . By tradition the'
'**The game** of thrones , so you must tell her the next buyer who comes running ,'
'**The game** trail brought her messages , strange spices . *The Frey stronghold was not large enough*'
'**heard the** scream of fear . I want to undress properly . Shae was there , fettered'
句子保持了局部的连贯性(你要打击他,或者拉姆齐喜欢草的感觉),但随后将非常连贯的单词序列连接成一团乱麻。
任何句法、语法或语义的感觉都明显缺失。
顺便说一下,我根本没有挑选那些句子,这些是我采样的第一批输出。
随意自己玩代码,你可以在评论里分享你得到的最古怪的句子!
作为最后一个实验,让我们看看用三个词的马尔可夫链能得到什么。
三字链结果
以下是模型在用 3 个单词的序列进行训练时生成的一些句子。
'**I am a** master armorer , lords of Westeros , sawing out each bay and peninsula until the'
'**Jon Snow is** with the Night's Watch . I did not survive a broken hip , a leathern'
'**Jon Snow is** with the Hound in the woods . He won't do it . " Please don't'
'**Where are the** chains , and the Knight of Flowers to treat with you , Imp . "'
'**Those were the** same . Arianne demurred . " So the fishwives say , " It was Tyrion's'
'**He thought that** would be good or bad for their escape . If they can truly give us'
'**I thought that** she was like to remember a young crow he'd met briefly years before . "'
好吧,我真的很喜欢其中的一些,尤其是最后一个。这听起来有点像你能在书中找到的真实句子。
结论
实现马尔可夫链比听起来容易得多,在真实语料库上训练它很有趣。
坦白地说,结果比我预期的要好,尽管在 LSTM 的小失败后,我可能把标准定得太低了。
在未来,我可能会尝试用更长的链或完全不同的语料库来训练这个模型。
在这种情况下,尝试一个 5 个单词的链又有了基本确定的结果,因为每个 5 个单词的序列几乎总是唯一的,所以我不认为 5 个单词和以上的链是感兴趣的。
你认为哪个语料库会产生更有趣的结果,尤其是对于更长的链?请在评论中告诉我!
如果你想了解更多关于马尔可夫链的知识,可以考虑查看一下 这本深入的书 。那是一个代销商链接,也就是说我从中获得一小笔佣金。
原载于 2019 年 10 月 25 日http://www . data stuff . tech。
马尔科夫风险投资公司
利用马尔可夫链生成风险投资公司名称的探索
风险投资家在命名方面不是很有创意,所以我决定尝试使用马尔可夫链来生成一些名字。(我是帮手。)
首先,我尝试了数据科学中描述的普通马尔可夫链。基本上,我把我的投资者姓名数据集转化成一个配对列表。所以如果我们有:
Sequoia Capital
Union Square Ventures
GV (Google Ventures)
我们最终会得到:
('Sequoia', 'Capital')
('Union', 'Square')
('Square', 'Ventures')
('GV', '(Google')
('(Google', 'Ventures)')
然后我们根据第一个单词分组,找出所有可能的转换。例如,从我的未删节数据集:
'Sequoia': [
'Capital',
'Financial',
'National',
'Capital',
'Capital',
'Capital',
'Capital',
'Scout',
'Apps',
'Investment',
'Capital',
'Energy',
'Private',
'Capital',
'Capital',
'Apps',
'Capital',
'Capital',
'Capital',
'Capital'
]
当我等待循环突突地创建所有这些重复的列表时,我的眼睛开始抽搐。这可以做得更好。
不管怎样,现在您可以选择一个起始单词(比如“Benchmark”),然后从列表中随机选择一个与“Benchmark”配对的单词,以获得名称中的下一个可能的单词。然后在某个时候你切断了它。
这种方法的结果并非不切实际:
Adler & Jack W. Baird Capital # 5 words
Dongxing Capital Corp Equity # 4 words
Sage Hill Angels # 3 words
…但我认为我们可以做得更好。
改进算法
首先,我们随机选择第一个单词。由于大约 50%的风险投资家的名字中有“合伙人”、“资本”、“基金”或一些类似的样板词,很可能我们会以第一个词“LLC”或其他什么结束。因此,我们应该有一些“开始词”的概念,所以我们将来只从那个集合中选择。
同样困扰我的是,我必须明确地说出我希望名字有多长:当你到了“LP”的时候,你可以很确定这个名字已经结束了。因此,让我们添加一个“停用词”的概念。
最后,大部分代码和时间都花在了将到的图形硬塞进 dict 中。让我们使用 networkx,而不是我们自己来管理。
修改后的配对生成看起来像:
import networkx as nxgraph = nx.DiGraph()
START_WORD = '---START---'
STOP_WORD = '---STOP---'def AddPair(start, stop):
"""Add an edge to the graph (or increment the weight of an existing edge)."""
if start in graph and stop in graph[start]:
graph[start][stop]['weight'] = graph[start][stop]['weight'] + 1.0
else:
graph.add_edge(start, stop, weight=1.0)def AddName(name):
words = name.split(' ')
AddPair(START_WORD, words[0])
for i in range(0, len(words)-1):
AddPair(words[i], words[i+1])
AddPair(words[-1], STOP_WORD)investors.name.apply(AddName)
…这只需要运行时间的一小部分。另一个好处是你可以生成漂亮的图表:
嗯,有点漂亮。
现在我们可以从START_WORD
开始,随机选择一条路径,直到到达STOP_WORD
:
def GenerateVc():
name = []
current_word = ChooseNext(START_WORD)
while current_word != STOP_WORD:
name.append(current_word)
current_word = ChooseNext(current_word)
return ' '.join(name)
ChooseNext
会取一个词,根据边权重随机选择。numpy
有一个很好的np.random.choice
方法,它采用一个概率数组,但是这些概率的总和必须是 1。首先,我要遍历所有的边,缩小权重,作为概率。
def NormalizeWeights():
for start in graph:
total_weight = graph.out_degree(start, weight='weight')
for stop in graph.successors(start):
graph[start][stop]['weight'] = graph[start][stop]['weight'] / total_weight
然后使用这些权重实现ChooseNext
:
def ChooseNext(word):
next_words = list(graph.successors(word))
weights = [graph[word][n]['weight'] for n in next_words]
return np.random.choice(next_words, p=weights)
然后我们可以调用GenerateVc
来创建一个不错的 VC 名称数组:
for i in range(0, 20):
print(GenerateVc())# Produces:
Cream City Digital Farm Ventures LLC
INESA Venture Fund LLC
Koms Co. Ltd.
Startup Lab
Japan Securities Investment Management Co. Ltd.
Novestra
Desert Sky Venture Capital Partners Co Ltd
Vuzix
Warren Citrin Impact Partners
Advantage Capital Partners
Genesis Campus, a Day
Denota Ventures LLC
Main Street Capital
Dry Canyon Creek Capital
Cenes Immo
Sheffield University of Iowa Capital Partners
Hamilton Portfolio Ltd.
CSC
Brocade Communications
BPL Global Health & Associates
听起来差不多。
大规模枪击和恐怖主义
我们对小概率和罕见事件的痴迷
我上个月在我父亲的忌日前后开始考虑这篇文章。即使是圣诞节,节日前后的几个星期也总是有些阴郁。死亡和死亡的想法与我的孩子们对圣诞老人的到来和新年的欢迎的天真兴奋交织在一起。我父亲于 2001 年去世,就在 911 事件后几个月。在与胃肠癌短暂斗争后,他去世了。在他的治疗过程中,我们有机会思考恐怖分子是如何改变世界的。
我没有理解这个悖论。我和我父亲认为,美国面临的最大威胁已经显现。但是,当时我也坚信他的癌症是个异数。也许这要归咎于他年轻时的暴露;反常的事情。多年以后,我开始意识到我的想法是多么简单。比起死于恐怖袭击,我更有可能与癌症抗争。
我现在明白了暴力,就像恐怖主义和大规模枪击事件一样,在我们的生活中扮演了一个很小的角色。我在经历了我应得的那份死亡后发表了这个声明。在过去的 16 年里,我一直是美国陆军的一名士兵,我可以证明,在 2:1 的比例下,战斗并不是军人葬礼的主要原因。
事实上,上周末我刚刚参加了另一场非战斗军事葬礼。自杀、摩托车事故、车祸、癌症和心脏病比巡逻队从地球上夺走了更多的朋友。这显然不会是每个士兵的经历,但对大多数人来说是这样的,而且与数据一致。
事实是,你可能不会死于大规模枪击或恐怖事件。它们是极其罕见的事件。你可能以前被告知过这一点,但这与此类事件获得的新闻报道和政治关注形成了鲜明的对比。在过去的半个世纪里,美国人口中受害者的平均数量接近下面列出的数值。
+ — — — — — — — — + — — — — — — — — — - — — — — — — +
| Incident Type | Avg Annual Victims |
+ — — — — — — — — + — — — — — — — — — - — — — — — — +
| Mass Shootings | 2.5 per 10 mil in population |
| Terrorism | 18.8 per 10 mil in population |
+ — — — — — — — — + — — — — — — — — — - — — — — — — +
我们关注这些事件有很多原因。也许是因为它们非常适合政治叙事。或者,也许暴力是我们祖先最关心的问题,而我们的生物线路没有文明变化得那么快。
然而,有基于数据的理由来证明罕见事件的困扰。它们(罕见事件)可能是更大事件的前兆。有时草丛中无法解释的运动是一只狮子。也许偶尔发生的涉及枪支和恐怖主义的事件是流行病迅速蔓延的征兆,而不仅仅是偶发的社会背景噪音。从数据科学的角度来看,此类事件的影响是非线性的。简单来说,这些事件是指数级恶化还是频率快速增加?
我几乎总是发现忽视人类的直觉是一个错误。通常,人们持有特定的信仰是有充分理由的。在大规模枪击和恐怖主义的情况下,数据的一些特征可能解释了我们的痴迷。看看美国,这是每起事故中受害者总数的视图。
这些事件类型中的每一种都有一个故事要讲述。通常对于离散的罕见事件,使用泊松过程进行建模和预测。这就是,例如,T2,地震通常是如何被理解的。然而,泊松过程具有稳定的到达间隔时间(事件之间的平均时间)的无记忆假设。可视化统计到达间隔时间显示大规模枪击事件变得越来越常见(目前与恐怖主义一样常见),从 80 年代开始频率急剧增加。
令人欣慰的是,大规模枪击事件的平均受害者总数逐年稳定。另一方面,恐怖主义在到达间隔方面是稳定的,但在每次事件的受害者总数方面有很大的变化。观察这两种罕见事件之间差异的另一种方法是比较事件之间的平均时间与死亡人数。
大规模枪击事件的死亡人数似乎被限制在 100 人左右,而不管事件之间的时间间隔。然而,在恐怖主义问题上,引人注目的局外人讲述了一个不同的故事。趋势线(不可否认是粗略的)表明,事件之间的时间间隔越长,可能的死亡人数就越多。事实上,死亡人数呈非线性增长。因此,举例来说,每增加 10 年的平均间隔时间,死亡人数就会增加 10 倍。
从这个角度来看,一个真正大规模的恐怖主义事件,杀死 10 万到 100 万人,不仅是可能的,而且是可能的。根据这个基本模型的极端界限,我们可以预期这样的事件每 50-100 年发生一次。
这些类型的罕见事件趋势可以被我们的心理所识别,甚至在我们有意识地意识到它之前。大规模枪击事件的频率正在加快,低影响力恐怖主义是一个更大事件的指标。这两个问题都在我们的脑海中,因为我们的直觉告诉我们要注意,数据也是如此。
用于创建本文的所有数据和代码都可以在这个 MatrixDS 项目中找到。
通过解决黑客马拉松问题掌握机器学习的基础知识
了解如何一步一步解决回归问题,并在黑客马拉松排行榜中获得体面的排名
黑客马拉松是在短时间内学习和实现新概念的好方法。今天,我们将讨论机器学习的基本步骤,以及如何在试图使用 MachineHack 黑客马拉松的数据集获得体面排名的同时,获得回归问题的良好准确性。
解决任何机器学习问题的基本步骤是
- 识别目标和独立特征
- 清理数据集
- 特征工程
- 特征编码和缩放
- 功能选择
- 检查目标变量的分布
- 从图表中获得微调特性的洞察力
- 模型应用和超参数整定
- 组合不同的模型
唷…要涵盖很多步骤,初学者很容易被吓倒…所以让我们深入这个问题,一步一步来…
您可以通过在 MachineHack 网站上创建帐户来下载数据集,并通过注册以下黑客马拉松来下载数据集:- 机票价格预测
现在,您从黑客马拉松获得的 zip 文件中提供了 3 个文件:-
Files provided in the dataset: 1)Data_train.xlsx 2)Sample_submission 3)Test_set
这里的Data_Train.xlsx
包含我们需要用来训练模型的数据集,Sample_submission
顾名思义指定了在黑客马拉松中需要提交的输出的格式,Test_set
是我们需要应用我们的模型来预测机票价格的数据集,我们在黑客马拉松中的分数将基于该数据集进行评估。
现在,我们需要记住的一件事是,无论我们将对Data_Train
数据集特征应用何种转换,都需要对Test_set
数据集应用相同的转换,以便模型从两者获得相似类型的输入。
接下来,从 GitHub 资源库下载 juptyer 笔记本,该资源库详细介绍了上述所有步骤:
好吧,如果你已经走到这一步,这意味着你对学习新事物是认真的,那么在另一个标签中开始一些好听的音乐,进入 区 让我们开始吧…
1.识别目标和独立特征
解决任何机器学习问题的第一步是识别源变量(自变量)和目标变量(因变量)。
在机器学习环境中,目标变量是应该输出的变量。例如,如果进行分类,它可以是二进制 0 或 1;如果进行回归,它可以是连续变量。
独立变量*(也称为特征)*是被分析过程的输入。
我们在官方网站上获得了关于数据集的以下信息:-
训练集的大小:10683 条记录
测试集大小:2671 条记录
特性 :
航空公司:航空公司的名称。
旅行日期:旅行的日期
Source:服务开始的来源。
目的地:服务结束的目的地。
路线:航班到达目的地所采用的路线。
Dep_Time:旅程从源头开始的时间。
到达时间:到达目的地的时间。
持续时间:飞行的总持续时间。
Total_Stops:出发地和目的地之间的总停靠站数。
Additional_Info:关于航班的附加信息
价格:门票的价格
让我们使用pd.read_excel
命令在 jupyter 笔记本中导入数据集。你可以在这里找到关于在熊猫中导入各种文件的信息。
让我们在 pandas 中使用df.head()
命令来了解数据集中的列。请记住,我已经将我们用来训练模型的数据集的名称保留为df_train
df.head() is used to print first 5 rows of the dataset
在这里,我们可以看到价格列是目标变量,因为它有连续的值,也就是说,它不能被分类到特定的类别,这个问题是一个监督回归问题。
2。清理数据集:
首先,让我们使用df.isnull()
命令检查数据集中缺失值的数量:-
Check null values
由于我们的数据集中只有一个空值,我只是简单地删除它,因为试图估算一个值似乎不是一个好的选择。
但是请记住,一般的经验法则是,如果任何特定列中超过 30%的值丢失,那么我们可以排除该列。
在 pandas 中,通过运行下面的命令很容易删除空值:-
此处inplace
参数用于隐式执行操作,即将操作直接应用于指定的数据帧。
接下来,我们应该检查我们的数据集是否有任何重复的行并删除它们:-
df.duplicated()
用于查找数据帧中重复条目的总数。
Check duplicate rows
接下来,我们需要通过运行以下命令删除重复的条目:-
#remove duplicate rows in training dataset
df_train.drop_duplicates(keep='first',inplace=True)
在上面的drop_duplicates
命令中,keep='first'
选项允许我们保留第一次出现的行值,同时删除所有后续出现的行值。
现在,您还可以只通过在这一步查看数据集来删除不必要的列。在当前的数据集中,没有这样的列,所以我们可以继续。
如果您观察笔记本的 数据清理 部分中采取的步骤,我们已经合并了Additional_Info
列中的重复值,并重命名了 Total_Stops 列中的值。
- 特征工程:-
特征工程是使用问题的领域知识和一点常识来创建新特征的过程,这些新特征可以增加机器学习模型的预测能力。这一步确实需要相当多的想象力,对输入特性的批判性思考,以及运用你的创造性。
Date_of_Journey
列本身并不十分有用,但我们可以从中创建新的功能,如航班是否在周末、星期几和月份。
Feature engineering
惊叹声…这看起来像是一段很难理解的复杂代码…相信我,这不是我一个人想出来的,可能永远也不会。但这就是 StackOverflow 前来救援的地方。你可以从下面的链接中进一步阅读代码,因为这将有助于你
a)理解在 python 中完成相同任务的各种方式
b)以防明天这段代码变得多余或对你不起作用,猜猜哪个网站会帮助你找到解决方案😉
链接:-
查看熊猫的某一天是否是周末
从熊猫的日期时间变量中获取年、月和日
然后,我们将持续时间列的值转换为分钟:-
Feature engineering on duration column
如果您看一下Duration
列,值的格式类似于2h 50m
,一些行只包含小时值,而一些行只包含分钟值(就像某人如何享受不到一小时就结束的飞行,但这是改天讨论的问题)
所以在上面的代码中,最初的 for 循环将小时和分钟部分分开,而第二个 for 循环用于将持续时间转换为分钟。
我甚至试着转换成秒来提高准确度,但是请不要遵循这些愚蠢的步骤,除非你有大量的空闲时间,并且一心想要提高排行榜上的排名👻
接下来,我们创建了一个名为Duration_minutes
的新列,并从 dataframe 中删除了原来的Duration
列。
我也在 Arrival_Time 列执行了类似的步骤,您可以在笔记本中跟进。
- 特征编码和缩放:-
我们通常对独立的输入变量进行特征缩放和编码,因此让我们在数据帧中将目标变量和输入变量彼此分开。
Split the dataset
这里X
包含输入特征的数据框,而y
是我们的目标变量。我将在下一节介绍对y
应用对数转换的原因。现在,让我们关注我们的输入变量 dataframe,即X
第一步是将输入变量分为分类变量和数字变量。
分类变量包含有限数量的类别或不同的组。分类数据可能没有逻辑顺序。例如,分类预测包括性别、材料类型和支付方式。
数值变量顾名思义包含连续或离散的数值。
我们可以使用df.select_dtypes()
方法进行拆分:-
select_dtypes is used to separate numerical and categorical features
在分类特征的情况下,我们可以应用标签编码或一个热编码。
您可以在这里进一步了解这两种技术:
在当前数据集中,我们已经对分类要素进行了标注编码。
Label encoding variables
对于数字特征,我们可以执行不同类型的缩放,如最小最大、标准缩放器或 BoxCox 变换。
我尝试了各种标准缩放、最小-最大缩放和数字的 boxcox 变换。最终,boxcox 变换给出了最好的准确度分数。
Boxcox transformation
Box-Cox 变换是一系列幂变换函数,用于稳定方差并使数据集看起来更像正态分布。关于 box-cox 变换的解释可以在这里找到。
lam
变量指定要应用的转换类型:-
- λ=-1。是一种互易变换。
- λ=-0.5 是倒数平方根变换。
- λ= 0.0 是对数变换。
- λ= 0.5 是平方根变换。
- λ= 1.0 就是没有变换。
完成上述转换后,我们将分类和数字特征连接起来,得到一组转换后的输入变量。
- 功能选择 :-
我们可以应用基于树的回归模型,如随机森林回归器、额外树和 xgboost,来获得特性的重要性。
例如,RandomForestRegressor 模型可应用于数据集,如下所示
Random Forest
我们首先使用train_test_split
方法将数据集分成训练和测试样本。test_size
参数指定了训练和测试数据的比例。值为 0.3(即 30%)会将数据分为 70:30 的训练数据和测试数据。然后,我们定义了 RandomForestRegressor 模型,并将其应用于训练样本(X_train,y_train)。
然后对测试输入样本(X_test)进行预测,并与原始目标样本(y_test)进行比较,得到各种精度指标。我将在本文的后续部分讨论准确性度量。
现在,让我们使用下面的函数来看看模型预测的特征重要性:-
Feature Importances
在上面的函数中,我们根据模型提供的特征重要性,按照重要性降序创建了一个新的数据框架。
然后,我们使用 matplotlib 库创建一个水平条形图,以直观地查看特性的重要性。
在随机森林回归的情况下,函数的输出为:-
Feature Importances
正如我们所看到的,持续时间列具有最高的重要性,而航班始发的来源城市具有最低的特征重要性。
我们可以从上面生成的图表中手动选择特性,也可以使用sklearn
中的SelectFromModel
模块自动选择最合适的特性。
我尝试根据上述功能的重要性在选定的功能上运行该模型,但准确性略有下降,如果我们在现实世界中部署该模型,这可能会很好,因为该模型现在有点更健壮,但对于黑客马拉松来说,准确性最重要,所以我最终保留了所有功能。
- 检查目标变量的分布:-
我们应该使用分布图来检查回归问题中目标变量的分布。如果它是偏斜的,那么对数、指数或 sqrt 变换的应用可以帮助减少偏斜以获得正态分布。
在我们的例子中,目标变量的分布最初有点向右倾斜
应用对数变换后,它呈正态分布:-
Normalized distribution
最后,对数转换确实提高了模型的整体准确性,这也是我在上面第 4 步开始时对目标输入应用对数转换的原因。
- 从图表中获得洞察力:-
检查目标列相对于输入变量的变化以及各种输入变量的分布:-
Scatter plot
价格应该随着持续时间的增加而增加,但这里的情况并非如此。
接下来,我们检查价格相对于停靠点总数的变化:-
Total stops vs Price
从上图中可以看出:-
正如所料,经停次数越多,机票价格越高
数字特征的分布可以使用直方图来检查,而分类特征的分布可以使用条形图或箱线图来检查。
在分类特征的情况下,检查是否有任何列值可以组合在一起,而在数字特征的情况下,检查分布是否可以归一化,即均匀分布。
Airlines frequency bar plot
后来,我回到分类特征,把最后四个航空公司分类组合在一起。
对Additional_Info
列执行类似的步骤:-
Additional Info frequency bar plot
您可以在 jupyter 笔记本中找到数值特征的直方图,并根据需要进行必要的转换。
- 模型应用和超参数调整:-
在尝试了不同类型的回归模型后,我发现 ExtraTrees、RandomForest 和 XGboost 比其他模型的精度略高,因此是时候对所有 3 个模型进行超参数调整以进一步提高精度了。
在机器学习中,超参数是在学习过程开始之前设置其值的参数。我们需要得出超参数的最佳值,因为这些值在模型之外,并且它们的值不能从数据中估计。
超参数调整是为学习算法选择一组最佳超参数的过程。进行超参数调优的两种常见方法是 GridSearchCV 和 RandomisedSearchCV。
虽然 GridSearchCV 是详尽的,但 RandomisedSearchCV 有助于快速获得一系列相关值。更多关于他们的信息可以在这里找到。
Randomized Search CV
在 RandomForest 算法的例子中,下面这篇来自《走向数据科学》的文章有助于我们理解如何正确地进行超参数调优:- 文章链接
类似的方法可以应用于 ExtraTrees 和 XGBoost 回归模型。
- 组合不同型号
堆叠是一种集成学习技术,其中我们可以通过元分类器或元回归器来组合多个回归模型。基于完整的训练集来训练基础级模型,然后基于基础级模型的输出作为输入特征来训练元模型。
在最后一步中,我使用叠加技术将上述三个模型结合起来,以提高整体准确性
Stacked model
这里使用的基本模型是 ExtraTrees、Random Forest 和 XGBoost 回归器,而使用的元模型是 Lasso。你可以在这里了解更多关于如何实现堆栈的信息。
接下来,我们拟合堆叠模型,并对测试数据样本进行预测
Fit the model
接下来,我创建了一个简单的函数来打印回归模型中所有可用的准确性指标
Print accuracy report
一旦我们训练了堆叠模型,我们只需将模型应用于预测数据集,并将值提交给 hackathon 网站,这就完成了解决机器学习问题所需的所有基本步骤。
堆叠模型的最终指标是:-
R - 平方在 0-1 范围内测量模型和因变量之间的关系强度。关于其他指标的信息可以在这里找到。
希望在完成上述所有步骤后,你至少对如何处理有监督的机器学习问题有了一点了解。如果你有任何疑问、建议或更正,请在评论区提出来,如果你喜欢这篇文章,请与他人分享,以示欣赏。
最后但并非最不愉快的编码🤓
主数据管理:数据战略的重要组成部分
Image from Pixabay
首先,什么是主数据管理(MDM)?主数据是指对企业业务至关重要的关键数据,通常用于多个学科和部门。 MDM 是建立和维护企业级数据服务,为整个企业和所有业务合作伙伴提供准确、一致和完整的主数据。主数据管理的概念起源于 2008 年左右,当时数据仓库和 ERP 应用程序在许多组织中流行起来。随着数据量和数据库数量的增加,以及用户输入和读取数据的数量的增加,确保使用正确的主数据定义变得越来越重要,以便在数据中有一个单一事实,没有差异、重复或过时。第一个例子与客户信息有关。在大型组织中,可能存在由多个应用程序或部门孤岛填充和管理的多个客户数据库,现实世界中的同一个客户可能会收到来自同一家公司的多封直接邮件或通知。随着数据的增长,主数据不仅包括客户信息,还包括其他关键数据资产,如潜在客户、供应商、小组成员和产品的数据。MDM 的实现一直是一个挑战,因为需要流程、技术和工具的所有三个方面来确保主数据在整个企业内得到协调和同步。
MDM 为什么重要?
随着最近大数据的爆炸式增长以及分析和物联网的快速发展,引用和应用高质量主数据的一致性变得前所未有的重要。企业不仅需要确保其关键数据资产得到高效和准确的管理,还需要通过加入或引用公司已经拥有的现有主数据来拥抱新的数据资产,以充分实现经济潜力。因此,MDM 需要成为公司增长和盈利的数据战略的重要组成部分,也是首席数据官(CDO)等高管的核心任务之一。
在过去的 10 年中,MDM 计划失败的主要原因有两个:1)只依赖技术和工具,没有业务部门的认可和支持;2)专注于修复和解决当前的数据问题,没有前瞻性思维。要使 MDM 成功,它首先需要是一个业务驱动的过程,并被业务部门和高管所接受。在许多情况下,建立和维护统一的主数据需要对业务流程进行根本性的改变,而一些最困难的 MDM 问题根本不是技术性的。接下来,前瞻性战略对于将MDM 作为组织中数据管理的重要组成部分至关重要,因为它主动为未来的成功奠定了基础。大量的经验告诉我们,当数据集刚刚被引入 ETL 和商业智能项目时,MDM 的实现是最容易和最平稳的。尝试修复现有的数据资产和流程通常需要高成本和大量的工作,这也可能会对当前的可交付成果产生很大的影响。下面的比较说明了在开始时实施 MDM 与修复现有数据和系统问题之间的巨大差异:
推迟实施 MDM
- 孤岛中的重复流程和昂贵的开发
2.无处不在的数据质量问题,没有简单的跟踪方法
3.客户满意度低
4.数据资产的潜力没有得到充分发挥
5.难以迁移到新的数据平台
从头实现 MDM
- 以更低的成本实现高效、快速的开发
2.数据质量问题更少,修复速度更快
3.客户满意度高
4.创造更多收入机会
5.需要时更容易迁移到新的数据平台
通过以上比较,很明显,MDM 应该是任何公司的数据战略的重要组成部分,并且应该具有前瞻性和长期承诺。换句话说,MDM 需要被视为一项投资,从长远来看,这将带来回报,并为公司在大数据、分析和物联网领域的增长和盈利能力奠定坚实的基础。
成功实施 MDM 的四个步骤
一旦制定了 MDM 策略,下一步就是在企业内部实现主数据管理。这是一个很大的话题,可以在一本书里深入探讨。在本文中,我将给出一个非常高层次的介绍,并指出成功实现 MDM 的 4 个关键步骤。每一个步骤都将保证在将来有自己的主题,有更多的阐述和详细的例子。
步骤 1:建立整个组织都接受的数据治理
这是 MDM 最关键和最重要的部分,也是最困难的部分。实施 MDM 需要数据治理委员会的承诺,该委员会通常具有以下结构:
- 管理和咨询信息控制台—首席管理人员和部门主管
- 信息管家—通常来自 IT 或 CDO 组织的数据治理经理/主管
- 数据管家—来自每个业务部门的领域专家
该委员会的主要任务包括:
- 建立数据治理政策和程序,并根据业务需求或数据、运营和技术的变化对其进行修订
- 建立定期沟通渠道,明确传达和强化政策
- 为数据问题建立正确的上报流程,确定优先级并明智高效地做出决策。
- 确保所有利益相关方的认同和所有权
下面列出了数据治理委员会应该做出决策的一些关键领域:
- 公司数据集的整体视图以及企业中的核心数据资产
- 记录并定义在适当的安全性和法规约束下,数据资产应如何共享或使用
- 为数据资产或数据对象中的数据元素建立标准定义和业务规则
- 确定正确的行动或计划过程,以确保数据策略和程序在整个组织中得以实施和执行
- 解决定义模糊或冲突
步骤 2:将 MDM 应用于新的数据添加或新的应用程序
永远记住,使 MDM 成功的最简单和最有效的方法是在创建数据时强制数据一致性。MDM 是一个长期项目,需要公司的长期投入。任何以方式改变数据的尝试都会使努力变得无效和昂贵。数据治理策略和定义通过两种渠道实现:1)通过任何新项目和应用程序开发;2)通过使用数据治理软件。许多组织的 MDM 实现停滞不前,因为他们在尝试修复现有系统和问题时面临高成本和高工作量;他们没有意识到,从 MDM 开始的最佳方式是将其应用于新项目,这将首先测试它,并使组织能够积累专业知识和经验。
此外,大部分数据治理应该作为数据相关项目的一部分直接实施到应用程序和报告中。例如,数据治理应该在以下技术实现中实施和传播其定义、策略和原则:
- 数据库的逻辑和物理设计(数据建模)
- 在 ETL 过程中定义列/字段名称和业务规则
- 在报告引擎中定义显示名称和公式
- 使用 ERP 和 Salesforce 等第三方软件时的配置和设置
- 由质量保证(QA)测试和用户验收测试(UAT)强制执行
第三步:选择合适的 MDM 软件
理想的 MDM 软件应该具有以下功能:
- 引用和访问公司中主数据资产的元数据(例如,RDBMS、Hive、平面文件等。)
- 使信息和数据管理员能够在工具中轻松地定义和修改定义
- 能够检查数据并配置业务规则,以应用或实施数据本身中定义的内容
市面上有很多工具可以做 1)和 2),但是用同一个工具做 3)并不容易。这就是为什么一个 MDM 软件同时也可以是一个数据集成工具,或者说反之亦然。最近人工智能(AI)的快速发展使这种软件更加强大,增强了数据管理,在未来几年有着光明的前景。
请记住,工具仍然是工具。如果没有治理委员会和来自高层管理人员的赞助,软件本身就不能发挥魔力,也是不充分的。此外,每个部门的信息管理员和数据管理员的不断沟通和强化也比软件本身发挥着更重要的作用。
步骤 4:利用 MDM 功能管理现有和遗留系统
许多公司可能无法从零开始创建新的主数据集,这意味着他们需要改造现有的数据库和相关应用程序。将 MDM 应用于现有的数据资产通常需要大量的工作,由于的复杂性和成本,这也可能会失败或中止。为了使 MDM 工作取得成功,需要仔细规划,以建立一个包含多个阶段的路线图。有时,在数据或系统迁移到新平台之前,仅部分应用 MDM 可能是一个更好的策略,同时重点关注将 MDM 应用于正在添加的新主数据或正在构建的新应用程序和流程,以便将增强的新数据源与主数据结合起来。
结论
MDM 已经成为组织充分实现其数据集的收入和利润潜力的必要条件,但实现起来并不容易。MDM 首先需要成为数据战略的一个永久部分,这样公司才能有一个长期的承诺。接下来,它需要来自最高管理层的一致治理和赞助,以及来自 IT/CDO 部门的信息管家和业务部门的数据管家的持续努力。修复现有数据和系统问题的挑战不应该阻止企业采用 MDM。相反,将 MDM 应用到新的数据源和新的应用程序将为逐步将其成功应用到现有的数据和系统奠定基础。
最好的数据科学家每天使用的数据操作工具
Photo by Simon Matzinger from Pexels
作为数据科学家,您所做的一切都是从数据操作开始的
dplyr 包有一组丰富的工具和函数,您可以使用它们进行数据辩论、探索性数据分析、特性工程等。
在接下来的几分钟里,我们将介绍一些绝对重要的函数,作为一名数据科学家,您会发现自己每天都在使用这些函数。
选择:展现重要的变量
dplyr 中可用的函数与您在 SQL 甚至 Python 中使用的函数密切相关,这取决于您正在执行的任务。
这里的主要区别是,使用 sql,您的代码可能看起来像这样……(并且您不会在dplyr select
中包含聚合函数,但稍后会详细介绍)
SELECT mpg, cyl, carb
FROM mtcars
相反,使用dplyr
我们首先指定想要操作的数据集,然后使用管道操作符%>%
有效地说,“嘿,这是我们的数据集,我调用的下一个动作或函数应该对它执行!”
因此,我们将有效地看到语法略有变化的函数翻转。继续这个例子,“嘿,mtcars 是我的数据集,我想从中选择 mpg、cyl 和 carb。”
您可以通过管道从一个函数传递到另一个函数。超级方便,容易习惯。稍后会有更多的介绍。
mtcars %>%
select(mpg, cyl, carb)
说到数据操作,我个人更喜欢 dplyr 的方法。对您可能正在执行或检查的任何数据操作进行逻辑分解要容易得多,因为您通过管道函数来有效地在每一行中重新创建数据集。
使用R
或SQL
,您的输出将如下所示:
过滤器:给我我想要的!
您可以将 filter 看作是 dplyr 对 SQL 的 where 语句的回答。如果你不用 SQL 来思考,这差不多就是你如何去掉任何不符合你想要的标准的东西。
例如,假设您只想查看 4 缸汽车。
您可以声明mtcars %>%
,然后调用包含您所关心的标准的filter
函数。
mtcars %>%
filter(cyl == 4)
您的输出将如下所示:
您将看到所有记录都包含 4 个柱面。
其他条件运算符
您也可以使用其他条件操作符,比如<
或>
。您可以在字符串、逻辑等上这样做。
mtcars %>%
filter(cyl >= 4)
我们现在可以看到各种各样的例子,其中cyl
列大于或等于 4。
组合过滤器
想象这样一个场景,是的,您想要过滤掉cyl
大于或等于 4 的记录…太好了;但是您还想过滤掉那些mpg
小于 20 的记录。
您可以使用&
或|
来组合这些标准。&
表示两个标准都必须满足,而|
将包括至少满足两个标准之一的记录。
你不局限于两个或三个或四个标准。您可以将任意数量的过滤器链接在一起!
看看这些例子!
mtcars %>%
filter(cyl >= 4 & mpg < 20)mtcars %>%
filter(cyl >= 4 | mpg < 20)
突击测验
您认为哪个代码片段会返回更多的记录?
第二个将总是返回更多(除非所有 4 缸或更多的车辆都少于 20 个mpg
,那么它们将返回相同数量的记录。)
这是因为过滤器不太严格。只需满足两个标准中的一个,而&
则需要满足两个标准。
您也可以使用逗号分隔标准,其行为与&
操作符相同。
不要忘了把你的函数放在一起
到目前为止,你已经学习了两个关键函数,select
& filter
。您很可能想要连续组合输出。这个秘密就是管道操作员。
在执行了select
操作之后,您现在有了一个新的数据集。它是mtcars
加上你在上面做的任何操作。当您使用管道操作符(%>%
)时,您实际上告诉了R
下一个函数将作为该行输出的延续!看看下面我们是如何结合最后两个动作的。
mtcars %>%
select(cyl, mpg, carb)%>%
filter(cyl >= 4 & mpg < 20)
保存你的创作!
在我们讨论其他可以使用的函数之前,告诉您如何有效地保存数据集也是值得的。
你可以像在R
中声明任何变量一样做这件事。<-
mtcars_sub <- mtcars %>%
select(cyl, mpg, carb)%>%
filter(cyl >= 4 & mpg < 20)
安排:让我们井然有序!
好了,现在这已经不碍事了…让我们进入arrange
功能。
mtcars %>%
filter(cyl >= 4)%>%
arrange(mpg)
现在,假设您想颠倒顺序,从最高到最低查看mpg
。你所要做的就是扔进一个desc()
。
mtcars %>%
filter(cyl >= 4)%>%
arrange(desc(mpg))
我们现在看到同样的输出从大到小排序mpg
。
变异:创建新变量
mutate
函数是我们创建新列的方法。这可能是将多个列值相加,根据一个列的值创建分类桶,将宁滨分类细化,或者为其他任何内容创建额外的列。
我将在这里跳到一个例子中,但请记住,我对汽车的熟悉程度是有限的…因此,我对我即将创建的指标的效用的理解有点天真。
假设你想知道每缸的马力是多少。您需要声明新的变量名,然后包含如何计算这个新字段的逻辑。
mtcars %>%
mutate(hp_per_cyl = hp / cyl)
分组依据和汇总
总结一下,最后要涉及的主要dplyr
操作是它的分组&聚合功能。
在 SQL 中执行聚合时,使用GROUP BY
来声明分组变量。但是,聚合逻辑(平均值、总和、最大值、最小值、计数等。)位于SELECT
语句中——我们在开始时讨论过。
对于这个例子,让我们按气缸数分组&然后看看平均每加仑英里数和马力。
mtcars %>%
group_by(cyl)%>%
summarize(mean_mpg = mean(mpg), mean_hp = mean(hp))
正如你可能已经猜到的,更高的气缸数与每加仑英里数成反比,与马力密切相关。
实际上,您可能只是评估这些特定变量之间的相关性,但这足以显示group_by
& summarize
的操作。
结论
Dplyr
是一个非常有用的库,它包含了其他数据争论语言的功能,并且它将一个函数传输到另一个函数的格式允许您跟踪否则可能会非常混乱的查询。
Dplyr
还提供了更多我们没有机会在这里详述的东西,但我们所涵盖的内容将为您扩展到dplyr
的一些更复杂的功能(如mutate_each
、summarise_if
以及许多其他功能)打下良好的基础。
让我知道你喜欢什么,你想了解更多!
在 @datasciencelessons 查看我的其他媒体帖子,并在 Twitter 上关注我 @data_lessons 。
一如既往,祝数据科学快乐!
原载于 2019 年 12 月 23 日http://datasciencelessons.com。