使用“假设工具”研究机器学习模型。
Google 的一个开源工具,无需编码就能轻松分析 ML 模型。
好的从业者扮演侦探的角色,探索以更好地理解他们的模型
在这个可解释和可解释的机器学习时代,人们不能仅仅满足于简单地训练模型并从中获得预测。为了能够真正产生影响并获得好的结果,我们还应该能够探索和研究我们的模型。除此之外,在继续使用模型之前,算法的公平性约束和偏见也应该清楚地记住。
调查一个模型需要问很多问题,并且需要有侦探的敏锐度来探查和寻找模型中的问题和不一致之处。此外,这样的任务通常很复杂,需要编写大量的自定义代码。幸运的是, What-If 工具已经被创建来解决这个问题,使得更多的人能够更容易、更容易、更准确地检查、评估和调试 ML 系统。
假设工具(WIT)
假设工具 是一个交互式可视化工具,旨在研究机器学习模型。缩写为 WIT,它使人们能够检查、评估和比较机器学习模型,从而能够理解分类或回归模型。由于其用户友好的界面和对复杂编码的较少依赖,每个人,无论是开发人员、产品经理、研究人员还是学生,都可以出于自己的目的使用它。
WIT 是 Google 在PAIR**(People+AI Research)**倡议下发布的开源可视化工具。PAIR 将谷歌的研究人员聚集在一起,研究并重新设计人们与人工智能系统的交互方式。
该工具可以通过 TensorBoard 访问,或者作为 Jupyter 或 Colab 笔记本的扩展。
优势
该工具的目的是为人们提供一种简单、直观和强大的方法,仅通过可视化界面在一组数据上使用经过训练的 ML 模型。以下是机智的主要优势。
What can you do with the What-If Tool?
我们将在使用该工具的示例演练中涵盖上述所有要点。
民众
为了说明假设工具的功能,PAIR 团队发布了一组使用预训练模型的演示。您可以在笔记本上运行演示,也可以直接通过网络运行。
Take the What-If Tool for a spin!
使用
WIT 可以在 Jupyter 或 Colab 笔记本内部使用,或者在 TensorBoard 网络应用内部使用。这已经在文档中很好很清楚地解释了,我强烈建议你去读一遍,因为通过这篇短文解释整个过程是不可能的。
整个想法是首先训练一个模型,然后使用假设工具可视化训练好的分类器对测试数据的结果。
使用 WIT 与 Tensorboard
要在 TensorBoard 中使用 WIT,您的模型需要通过 TensorFlow 模型服务器提供服务,并且要分析的数据必须作为 TFRecords 文件存在于磁盘上。有关在 TensorBoard 中使用 WIT 的更多详细信息,请参考文档。
在笔记本上使用 WIT
为了能够在笔记本中访问 WIT,您需要一个 WitConfigBuilder 对象来指定要分析的数据和模型。这篇文档提供了在笔记本上使用 WIT 的一步一步的概要。
您也可以使用演示笔记本并编辑代码以包含您的数据集来开始工作。
游戏攻略
现在让我们通过一个例子来探索 WIT 工具的功能。这个例子取自网站上提供的演示,叫做收入分类,其中我们需要根据一个人的人口普查信息来预测他的年收入是否超过 5 万美元。该数据集属于 UCI 人口普查数据集 ,由年龄、婚姻状况、受教育程度等多个属性组成。
概观
让我们从探索数据集开始。这里有一个链接到网络演示,以便跟进。
假设分析工具包含两个主要面板。右侧面板包含您已加载的数据集中各个数据点的可视化。
在这种情况下,蓝点是模型推断收入低于 50k 的人,而红点是模型推断收入高于 50k 的人。默认情况下,WIT 使用 0.5 的肯定分类阈值。这意味着,如果推断得分为 0.5 或更高,则该数据点被认为处于积极的类别,即高收入。
这里值得注意的是数据集是在 Facets Dive 中可视化的。Facets Dive 是 PAIR 团队再次开发的 FACETS 工具的一部分,帮助我们理解数据的各种特性并探索它们。如果您不熟悉这个工具,您可以参考我不久前写的这篇关于 FACETS 功能的文章。
[## 用 Google FACETS 可视化机器学习数据集。
Google 的开源工具,可以轻松地从大量数据中学习模式
towardsdatascience.com](/visualising-machine-learning-datasets-with-googles-facets-462d923251b3)
您也可以通过简单地从下拉菜单中选择字段,以大量不同的方式组织数据点,包括混淆矩阵、散点图、直方图和小倍数图。下面列举了几个例子。
左侧面板包含三个标签Datapoint Editor,``Performance & Fairness
;还有Features.
1.数据点编辑器选项卡
数据点编辑器有助于通过以下方式进行数据分析:
- 查看和编辑数据点的详细信息
它允许深入到一个选定的数据点,该数据点在右侧面板上以黄色突出显示。让我们尝试将年龄从 53 更改为 58,并单击“运行推理”按钮,看看它对模型的性能有什么影响。
通过简单地改变此人的年龄,模型现在预测此人属于高收入类别。对于这个数据点,早些时候正面(高收入)阶层的推断得分是 0.473,负面(低收入)阶层的得分是 0.529。但是,通过改变年龄,正的班级分数变成了 0.503。
- 寻找最近的反事实
了解模型行为的另一种方式是查看哪些小的变化会导致模型改变其决策,这被称为反事实 s。只需点击一下,我们就可以看到与我们选择的数据点最相似的反事实,以绿色突出显示。在数据点编辑器选项卡中,我们现在还可以在原始数据点的特征值旁边看到反事实的特征值。绿色文本表示两个数据点不同的特征。WIT 使用 L1 和L2 距离来计算数据点之间的相似性。
在这种情况下,最接近的反事实稍老,有不同的职业和资本收益,但在其他方面是相同的。
我们还可以使用“显示与所选数据点的相似性”按钮查看所选点和其他点之间的相似性。WIT 测量从选定点到每隔一个数据点的距离。让我们更改 X 轴散点图,以显示到所选数据点的 L1 距离。
- 分析部分相关图
部分相关性图(短 PDP 或 PD 图)显示了一个或两个特征对机器学习模型的预测结果的边际效应( J. H. Friedman 2001 )。
数据点的年龄和教育的 PDP 如下:
上图显示:
- 该模型已经了解到年龄和收入之间的正相关关系
- 更高的学位使模型对更高的收入更有信心。
- 高资本收益是高收入的一个非常强有力的指标,远远超过任何其他单一特征。
2.绩效与公平选项卡
该选项卡允许我们使用混淆矩阵和 ROC 曲线来查看整体模型性能。
- 车型性能分析
为了测量模型的性能,我们需要告诉工具什么是基本事实特征,即模型试图预测的特征,在这种情况下是“超过 50K ”。
我们可以看到,在默认阈值水平为 0.5 时,我们的模型大约有 15%的时间是不正确的,其中大约 5%的时间是假阳性,10%的时间是假阴性。更改阈值以查看其对模型准确性的影响。
还有一个“成本比率设置和一个“优化阈值按钮,也可以调整。
- ML 公平性
机器学习中的公平性与建模和预测结果一样重要。训练数据中的任何偏差将反映在训练的模型中,并且如果部署这样的模型,则结果输出也将有偏差。WIT 可以以几种不同的方式帮助调查公平问题。我们可以设置一个输入要素(或一组要素)来分割数据。例如,让我们看看性别对模型性能的影响。
Effect of gender on Model’s performance
我们可以看到这个模型对女性比对男性更准确。此外,该模型对女性高收入的预测比男性低得多(女性为 9.3%,男性为 28.6%)。一个可能的原因可能是由于女性在数据集中的代表性不足,我们将在下一节探讨这个问题。
此外,该工具可以最优地设置两个子集的决策阈值,同时考虑与算法公平性相关的多个约束中的任何一个,例如人口统计均等或机会均等。
3.功能选项卡
要素选项卡提供数据集中每个要素的汇总统计数据,包括直方图、分位数图、条形图等。该选项卡还允许查看数据集中每个要素的值的分布。例如,让我们探讨性别、资本收益和种族特征。
我们推断 capital gain
非常不均匀,大多数数据点被设置为 0。
Native Country DIstribution || Sex distribution
类似地,大多数数据点属于美国,而女性在数据集中没有得到很好的代表。由于数据是有偏差的,它的预测只针对一个群体是很自然的。毕竟,一个模型从提供给它的数据中学习,如果数据来源有偏差,结果也会有偏差。机器学习已经在许多应用和领域证明了它的实力。然而,机器学习模型的工业应用的关键障碍之一是确定用于训练模型的原始输入数据是否包含歧视性偏见。
结论
这只是一些假设工具特性的快速浏览。WIT 是一个非常方便的工具,它提供了探究模型的能力,并将其传递到最重要的人手中。简单地创建和训练模型不是机器学习的目的,但理解为什么以及如何创建模型才是真正意义上的机器学习。
参考资料:
- 假设工具:机器学习模型的无代码探测
- https://pair-code.github.io/what-if-tool/walkthrough.html
- https://github . com/tensor flow/tensor board/tree/master/tensor board/plugins/interactive _ inference
使用 word2vec 分析新闻标题并预测文章成功
深入分析
文章标题的单词嵌入能预测受欢迎程度吗?关于情绪和股票的关系,我们能了解到什么?word2vec 可以帮助我们回答这些问题,还有更多。
Sentiment distributions for popular news websites
单词嵌入是表示单词以及文档(单词集合)中包含的潜在信息的一种强大方式。使用新闻文章标题的数据集,其中包括来源、情感、主题和受欢迎程度(份额数)的特征,我开始查看我们可以通过文章各自的嵌入来了解它们之间的关系。
该项目的目标是:
- 使用 NLTK 预处理/清理文本数据
- 使用 word2vec 创建单词和标题嵌入,然后使用 t-SNE 将它们可视化为集群
- 形象化标题情绪和文章流行度的关系
- 尝试从嵌入和其他可用特征预测文章流行度
- 使用模型堆叠来提高流行度模型的性能(这一步并不成功,但仍然是一个有价值的实验!)
导入和预处理
我们将从进口开始:
**import** **pandas** **as** **pd**
**import** **gensim**
**import** **seaborn** **as** **sns**
**import** **matplotlib.pyplot** **as** **plt**
**import** **numpy** **as** **np**
**import** **xgboost** **as** **xgb**
然后读入数据:
main_data = pd.read_csv('News_Final.csv')
main_data.head()
# Grab all the titles
article_titles = main_data['Title']*# Create a list of strings, one for each title*
titles_list = [title **for** title **in** article_titles]
*# Collapse the list of strings into a single long string for processing*
big_title_string = ' '.join(titles_list)
**from** **nltk.tokenize** **import** word_tokenize
*# Tokenize the string into words*
tokens = word_tokenize(big_title_string)
*# Remove non-alphabetic tokens, such as punctuation*
words = [word.lower() **for** word **in** tokens **if** word.isalpha()]
*# Filter out stopwords*
**from** **nltk.corpus** **import** stopwords
stop_words = set(stopwords.words('english'))
words = [word **for** word **in** words **if** **not** word **in** stop_words]
*# Print first 10 words*
words[:10]
接下来,我们需要加载预先训练好的 word2vec 模型。你可以在这里找到几款这样的。由于这是一个新闻数据集,所以我使用了谷歌新闻模型,该模型被训练了大约 1000 亿个单词(哇)。
*# Load word2vec model (trained on an enormous Google corpus)*
model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary = **True**)
*# Check dimension of word vectors*
model.vector_size
所以模型会生成 300 维的词向量,我们要做的就是创建一个向量,让它通过模型。每个向量看起来像这样:
economy_vec = model['economy']
economy_vec[:20] *# First 20 components*
word2vec(可以理解)不能从一个不在其词汇表中的单词创建向量。正因为如此,我们需要在创建单词向量的完整列表时指定“if word in model.vocab”。
*# Filter the list of vectors to include only those that Word2Vec has a vector for*
vector_list = [model[word] **for** word **in** words **if** word **in** model.vocab]
*# Create a list of the words corresponding to these vectors*
words_filtered = [word **for** word **in** words **if** word **in** model.vocab]
*# Zip the words together with their vector representations*
word_vec_zip = zip(words_filtered, vector_list)
*# Cast to a dict so we can turn it into a DataFrame*
word_vec_dict = dict(word_vec_zip)
df = pd.DataFrame.from_dict(word_vec_dict, orient='index')df.head(3)
基于 t-SNE 的维数约简
接下来,我们将使用 t-SNE 挤压(阅读:对这些单词向量进行降维),看看是否有任何模式出现。如果你不熟悉 t-SNE 和它的解释,看看这篇关于 t-SNE 的优秀的、互动的 distill.pub 文章。
摆弄 SNE 霸王龙的参数很重要,因为不同的值会产生非常不同的结果。我测试了 0 到 100 之间的几个困惑值,发现每次都产生大致相同的形状。我还测试了几个介于 20 和 400 之间的学习率,并决定保持默认的学习率(200)。
出于可见性(和处理时间)的考虑,我使用了 400 个单词向量,而不是大约 20,000 个单词向量。
**from** **sklearn.manifold** **import** TSNE
*# Initialize t-SNE*
tsne = TSNE(n_components = 2, init = 'random', random_state = 10, perplexity = 100)
*# Use only 400 rows to shorten processing time*
tsne_df = tsne.fit_transform(df[:400])
现在,我们准备绘制缩减的单词向量数组。我使用adjust_text
智能地将单词分开,以提高可读性:
sns.set()# Initialize figure
fig, ax = plt.subplots(figsize = (11.7, 8.27))
sns.scatterplot(tsne_df[:, 0], tsne_df[:, 1], alpha = 0.5)
*# Import adjustText, initialize list of texts*
**from** **adjustText** **import** adjust_text
texts = []
words_to_plot = list(np.arange(0, 400, 10))
*# Append words to list*
**for** word **in** words_to_plot:
texts.append(plt.text(tsne_df[word, 0], tsne_df[word, 1], df.index[word], fontsize = 14))
*# Plot text using adjust_text (because overlapping text is hard to read)*
adjust_text(texts, force_points = 0.4, force_text = 0.4,
expand_points = (2,1), expand_text = (1,2),
arrowprops = dict(arrowstyle = "-", color = 'black', lw = 0.5))
plt.show()
如果你有兴趣尝试一下adjust_text
来满足自己的绘图需求,你可以在这里找到它。一定要用 came caseadjustText
导入,请注意adjustText
目前不兼容matplotlib
3.0 以上版本。
令人鼓舞的是,即使向量嵌入已经减少到二维,我们也看到某些项目聚集在一起。例如,我们在左/左上角有个月,我们在底部有个公司财务术语,我们在中间有更多的个通用的、非主题性的词(比如‘full’,‘really’,‘slew’)。
请注意,如果我们用不同的参数再次运行 t-SNE,我们可能会观察到一些类似的结果,但我们不能保证看到完全相同的模式。t-SNE 不是决定性的。相关地,聚类的紧密度和聚类之间的距离并不总是有意义的。它主要是作为一种探索工具,而不是相似性的决定性指标。
平均单词嵌入
我们已经了解了单词嵌入如何应用于这个数据集。现在我们可以转移到一些更有趣的 ML 应用程序上:找到聚集在一起的标题,看看会出现什么样的模式。
我们可以使用一个更简单的(有时甚至更有效)技巧:对每个文档中单词向量的嵌入进行平均,而不是使用 Doc2Vec,doc 2 vec 没有可用的预训练模型,因此需要漫长的训练过程。在我们的例子中,文档指的是标题。
我们需要重做预处理步骤来保持标题完整——正如我们将看到的,这比拆分单词要复杂一些。谢天谢地,Dimitris Spathis 已经创建了一系列函数,我发现它们非常适合这个用例。谢谢你,迪米特里斯!
**def** document_vector(word2vec_model, doc):
*# remove out-of-vocabulary words*
doc = [word **for** word **in** doc **if** word **in** model.vocab]
**return** np.mean(model[doc], axis=0)
*# Our earlier preprocessing was done when we were dealing only with word vectors*
*# Here, we need each document to remain a document*
**def** preprocess(text):
text = text.lower()
doc = word_tokenize(text)
doc = [word **for** word **in** doc **if** word **not** **in** stop_words]
doc = [word **for** word **in** doc **if** word.isalpha()]
**return** doc
*# Function that will help us drop documents that have no word vectors in word2vec*
**def** has_vector_representation(word2vec_model, doc):
*"""check if at least one word of the document is in the*
*word2vec dictionary"""*
**return** **not** all(word **not** **in** word2vec_model.vocab **for** word **in** doc)
*# Filter out documents*
**def** filter_docs(corpus, texts, condition_on_doc):
*"""*
*Filter corpus and texts given the function condition_on_doc which takes a doc. The document doc is kept if condition_on_doc(doc) is true.*
*"""*
number_of_docs = len(corpus)
**if** texts **is** **not** **None**:
texts = [text **for** (text, doc) **in** zip(texts, corpus)
**if** condition_on_doc(doc)]
corpus = [doc **for** doc **in** corpus **if** condition_on_doc(doc)]
print("**{}** docs removed".format(number_of_docs - len(corpus)))
**return** (corpus, texts)
现在我们将使用这些来进行处理:
*# Preprocess the corpus*
corpus = [preprocess(title) **for** title **in** titles_list]
*# Remove docs that don't include any words in W2V's vocab*
corpus, titles_list = filter_docs(corpus, titles_list, **lambda** doc: has_vector_representation(model, doc))
*# Filter out any empty docs*
corpus, titles_list = filter_docs(corpus, titles_list, **lambda** doc: (len(doc) != 0))x = []
**for** doc **in** corpus: *# append the vector for each document*
x.append(document_vector(model, doc))
X = np.array(x) *# list to array*
t-SNE,第二轮:文档向量
现在我们已经成功地创建了文档向量数组,让我们看看用 t-SNE 绘制它们时是否能得到类似的有趣结果。
*# Initialize t-SNE*
tsne = TSNE(n_components = 2, init = 'random', random_state = 10, perplexity = 100)
*# Again use only 400 rows to shorten processing time*
tsne_df = tsne.fit_transform(X[:400])fig, ax = plt.subplots(figsize = (14, 10))
sns.scatterplot(tsne_df[:, 0], tsne_df[:, 1], alpha = 0.5)
**from** **adjustText** **import** adjust_text
texts = []
titles_to_plot = list(np.arange(0, 400, 40)) *# plots every 40th title in first 400 titles*
*# Append words to list*
**for** title **in** titles_to_plot:
texts.append(plt.text(tsne_df[title, 0], tsne_df[title, 1], titles_list[title], fontsize = 14))
*# Plot text using adjust_text*
adjust_text(texts, force_points = 0.4, force_text = 0.4,
expand_points = (2,1), expand_text = (1,2),
arrowprops = dict(arrowstyle = "-", color = 'black', lw = 0.5))
plt.show()
挺有意思的!我们可以看到,t-SNE 将文档向量折叠到一个维度空间中,在这个空间中,文档根据其内容是与国家、世界领导人和外交事务有关,还是与技术公司有关而展开。
现在让我们来探讨一下文章流行度。人们普遍认为,一篇文章的标题越煽情或越吸引人,它就越有可能被分享,对吗?接下来,我们将看看在这个特定的数据集中是否有这方面的证据。
流行度和情感分析
首先,我们需要删除所有没有流行度测量或来源的文章。流行度的零测量在该数据中表示为-1。
*# Drop all the rows where the article popularities are unknown (this is only about 11% of the data)*
main_data = main_data.drop(main_data[(main_data.Facebook == -1) |
(main_data.GooglePlus == -1) |
(main_data.LinkedIn == -1)].index)
*# Also drop all rows where we don't know the source*
main_data = main_data.drop(main_data[main_data['Source'].isna()].index)
main_data.shape
我们仍然有 81,000 篇文章要处理,所以让我们看看是否可以找到情绪和股票数量之间的关联。
fig, ax = plt.subplots(1, 3, figsize=(15, 10))
subplots = [a **for** a **in** ax]
platforms = ['Facebook', 'GooglePlus', 'LinkedIn']
colors = list(sns.husl_palette(10, h=.5)[1:4])
**for** platform, subplot, color **in** zip(platforms, subplots, colors):
sns.scatterplot(x = main_data[platform], y = main_data['SentimentTitle'], ax=subplot, color=color)
subplot.set_title(platform, fontsize=18)
subplot.set_xlabel('')
fig.suptitle('Plot of Popularity (Shares) by Title Sentiment', fontsize=24)
plt.show()
很难确定这里是否有任何关系,因为一些文章在它们的份额计数方面是显著的异常值。让我们试着对 x 轴进行对数变换,看看我们是否能揭示任何模式。我们还将使用一个 regplot,因此seaborn
将为每个图覆盖一个线性回归。
*# Our data has over 80,000 rows, so let's also subsample it to make the log-transformed scatterplot easier to read*
subsample = main_data.sample(5000)
fig, ax = plt.subplots(1, 3, figsize=(15, 10))
subplots = [a **for** a **in** ax]
**for** platform, subplot, color **in** zip(platforms, subplots, colors):
*# Regression plot, so we can gauge the linear relationship*
sns.regplot(x = np.log(subsample[platform] + 1), y = subsample['SentimentTitle'],
ax=subplot,
color=color,
*# Pass an alpha value to regplot's scatterplot call*
scatter_kws={'alpha':0.5})
*# Set a nice title, get rid of x labels*
subplot.set_title(platform, fontsize=18)
subplot.set_xlabel('')
fig.suptitle('Plot of log(Popularity) by Title Sentiment', fontsize=24)
plt.show()
与我们可能预期的相反(来自我们对高度情绪化、点击量大的标题的想法),在这个数据集中,我们发现标题情绪和文章受欢迎程度(通过分享数量来衡量)之间没有关系。
为了更清楚地了解流行度本身是什么样子,让我们按平台绘制一个最终的 log(流行度)图。
fig, ax = plt.subplots(3, 1, figsize=(15, 10))
subplots = [a **for** a **in** ax]
**for** platform, subplot, color **in** zip(platforms, subplots, colors):
sns.distplot(np.log(main_data[platform] + 1), ax=subplot, color=color, kde_kws={'shade':**True**})
*# Set a nice title, get rid of x labels*
subplot.set_title(platform, fontsize=18)
subplot.set_xlabel('')
fig.suptitle('Plot of Popularity by Platform', fontsize=24)
plt.show()
作为我们探索的最后一部分,让我们看看情绪本身。出版商之间似乎有所不同吗?
*# Get the list of top 12 sources by number of articles*
source_names = list(main_data['Source'].value_counts()[:12].index)
source_colors = list(sns.husl_palette(12, h=.5))
fig, ax = plt.subplots(4, 3, figsize=(20, 15), sharex=**True**, sharey=**True**)
ax = ax.flatten()
**for** ax, source, color **in** zip(ax, source_names, source_colors):
sns.distplot(main_data.loc[main_data['Source'] == source]['SentimentTitle'],
ax=ax, color=color, kde_kws={'shade':**True**})
ax.set_title(source, fontsize=14)
ax.set_xlabel('')
plt.xlim(-0.75, 0.75)
plt.show()
这些分布看起来相当相似,但是当它们都在不同的地块上时,很难说出和有多相似。让我们试着把它们都叠加在一个图上。
*# Overlay each density curve on the same plot for closer comparison*
fig, ax = plt.subplots(figsize=(12, 8))
**for** source, color **in** zip(source_names, source_colors):
sns.distplot(main_data.loc[main_data['Source'] == source]['SentimentTitle'],
ax=ax, hist=**False**, label=source, color=color)
ax.set_xlabel('')
plt.xlim(-0.75, 0.75)
plt.show()
我们看到,来源对文章标题的情感分布非常相似——就正面或负面标题而言,似乎没有任何一个来源是异常的。相反,所有 12 个最常见的来源都以 0 为中心分布,尾部大小适中。但这能说明全部情况吗?让我们再来看看这些数字:
# Group by Source, then get descriptive statistics for title sentiment
source_info = main_data.groupby('Source')['SentimentTitle'].describe()# Recall that `source_names` contains the top 12 sources
# We'll also sort by highest standard deviation
source_info.loc[source_names].sort_values('std', ascending=False)[['std', 'min', 'max']]
WSJ has both the highest standard deviation and the largest range.
我们可以一眼看出,与其他任何顶级来源相比,《华尔街日报》的标准差最高,范围最大,最低情绪最低。这表明《华尔街日报》的文章标题可能异常负面。为了严格验证这一点,需要进行假设检验,这超出了本文的范围,但这是一个有趣的潜在发现和未来方向。
流行预测
我们为建模准备数据的第一个任务是用各自的标题重新连接文档向量。幸运的是,当我们预处理语料库时,我们同时处理了corpus
和titles_list
,所以向量和它们所代表的标题仍然匹配。同时,在main_df
中,我们已经删除了所有流行度为-1 的文章,所以我们需要删除代表这些文章标题的向量。
在这台计算机上,按原样在这些巨大的向量上训练一个模型是不可能的,但我们会看看我们可以做些什么来降低维度。我还将从发布日开始设计一个新特性:“DaysSinceEpoch”,它基于 Unix 时间(在这里阅读更多)。
**import** **datetime**
*# Convert publish date column to make it compatible with other datetime objects*
main_data['PublishDate'] = pd.to_datetime(main_data['PublishDate'])
*# Time since Linux Epoch*
t = datetime.datetime(1970, 1, 1)
*# Subtract this time from each article's publish date*
main_data['TimeSinceEpoch'] = main_data['PublishDate'] - t
*# Create another column for just the days from the timedelta objects*
main_data['DaysSinceEpoch'] = main_data['TimeSinceEpoch'].astype('timedelta64[D]')
main_data['TimeSinceEpoch'].describe()
正如我们所看到的,所有这些文章都是在 250 天之内发表的。
**from** **sklearn.decomposition** **import** PCA
pca = PCA(n_components=15, random_state=10)
*# as a reminder, x is the array with our 300-dimensional vectors*
reduced_vecs = pca.fit_transform(x)df_w_vectors = pd.DataFrame(reduced_vecs)
df_w_vectors['Title'] = titles_list# Use pd.concat to match original titles with their vectors
main_w_vectors = pd.concat((df_w_vectors, main_data), axis=1)
*# Get rid of vectors that couldn't be matched with the main_df*
main_w_vectors.dropna(axis=0, inplace=**True**)
现在,我们需要删除非数字和非虚拟列,以便将数据输入到模型中。我们还将对DaysSinceEpoch
特性应用缩放,因为与减少的词向量、情感等相比,它在数量上要大得多。
*# Drop all non-numeric, non-dummy columns, for feeding into the models*
cols_to_drop = ['IDLink', 'Title', 'TimeSinceEpoch', 'Headline', 'PublishDate', 'Source']
data_only_df = pd.get_dummies(main_w_vectors, columns = ['Topic']).drop(columns=cols_to_drop)
*# Standardize DaysSinceEpoch since the raw numbers are larger in magnitude*
**from** **sklearn.preprocessing** **import** StandardScaler
scaler = StandardScaler()
*# Reshape so we can feed the column to the scaler*
standardized_days = np.array(data_only_df['DaysSinceEpoch']).reshape(-1, 1)
data_only_df['StandardizedDays'] = scaler.fit_transform(standardized_days)
*# Drop the raw column; we don't need it anymore*
data_only_df.drop(columns=['DaysSinceEpoch'], inplace=**True**)
*# Look at the new range*
data_only_df['StandardizedDays'].describe()
# Get Facebook data only
fb_data_only_df = data_only_df.drop(columns=['GooglePlus', 'LinkedIn'])# Separate the features and the response
X = fb_data_only_df.drop('Facebook', axis=1)
y = fb_data_only_df['Facebook']
*# 80% of data goes to training*
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 10)
让我们对数据运行一个非优化的XGBoost
,看看它是如何开箱即用的。
**from** **sklearn.metrics** **import** mean_squared_error
*# Instantiate an XGBRegressor*
xgr = xgb.XGBRegressor(random_state=2)
*# Fit the classifier to the training set*
xgr.fit(X_train, y_train)
y_pred = xgr.predict(X_test)
mean_squared_error(y_test, y_pred)
至少可以说,结果平平。我们可以通过超参数调整来提高这种性能吗?我从这篇 Kaggle 文章中提取并重新调整了一个超参数调整网格。
**from** **sklearn.model_selection** **import** GridSearchCV
*# Various hyper-parameters to tune*
xgb1 = xgb.XGBRegressor()
parameters = {'nthread':[4],
'objective':['reg:linear'],
'learning_rate': [.03, 0.05, .07],
'max_depth': [5, 6, 7],
'min_child_weight': [4],
'silent': [1],
'subsample': [0.7],
'colsample_bytree': [0.7],
'n_estimators': [250]}
xgb_grid = GridSearchCV(xgb1,
parameters,
cv = 2,
n_jobs = 5,
verbose=**True**)
xgb_grid.fit(X_train, y_train)
根据xgb_grid
,我们的最佳参数如下:
{'colsample_bytree': 0.7, 'learning_rate': 0.03, 'max_depth': 5, 'min_child_weight': 4, 'n_estimators': 250, 'nthread': 4, 'objective': 'reg:linear', 'silent': 1, 'subsample': 0.7}
用新参数再试一次:
params = {'colsample_bytree': 0.7, 'learning_rate': 0.03, 'max_depth': 5, 'min_child_weight': 4,
'n_estimators': 250, 'nthread': 4, 'objective': 'reg:linear', 'silent': 1, 'subsample': 0.7}
*# Try again with new params*
xgr = xgb.XGBRegressor(random_state=2, **params)
*# Fit the classifier to the training set*
xgr.fit(X_train, y_train)
y_pred = xgr.predict(X_test)
mean_squared_error(y_test, y_pred)
大约好了 35,000,但我不确定这说明了很多。在这一点上,我们可以推断,当前状态的数据似乎不足以让这个模型运行。让我们看看我们是否可以用更多的功能工程来改进它:我们将训练一些分类器来区分两个主要的文章组:哑弹(0 或 1 份额)与非哑弹。
这个想法是,如果我们可以给回归变量一个新的特征(文章将具有极低份额的概率),它可能会在预测高度共享的文章方面表现得更好,从而降低这些文章的残值并减少均方误差。
迂回:检测无用的文章
从我们之前制作的对数转换图中,我们可以注意到,一般来说,有 2 个文章块:1 个簇在 0,另一个簇(长尾)从 1 开始。我们可以训练一些分类器来识别文章是否是“无用的”(在 0-1 股票箱中),然后使用这些模型的预测作为最终回归的特征,这将预测概率。这叫做模型叠加。
# Define a quick function that will return 1 (true) if the article has 0-1 share(s)
def dud_finder(popularity):
if popularity <= 1:
return 1
else:
return 0# Create target column using the function
fb_data_only_df['is_dud'] = fb_data_only_df['Facebook'].apply(dud_finder)
fb_data_only_df[['Facebook', 'is_dud']].head()
# 28% of articles can be classified as "duds"
fb_data_only_df['is_dud'].sum() / len(fb_data_only_df)
现在我们已经有了无用的特征,我们将初始化分类器。我们将使用一个随机森林、一个优化的 xgb 分类器和一个 K-最近邻分类器。我将省去调优 XGB 的部分,因为它看起来与我们之前进行的调优基本相同。
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_splitX = fb_data_only_df.drop(['is_dud', 'Facebook'], axis=1)
y = fb_data_only_df['is_dud']# 80% of data goes to training
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 10)# Best params, produced by HP tuning
params = {'colsample_bytree': 0.7, 'learning_rate': 0.03, 'max_depth': 5, 'min_child_weight': 4,
'n_estimators': 200, 'nthread': 4, 'silent': 1, 'subsample': 0.7}# Try xgc again with new params
xgc = xgb.XGBClassifier(random_state=10, **params)
rfc = RandomForestClassifier(n_estimators=100, random_state=10)
knn = KNeighborsClassifier()preds = {}
for model_name, model in zip(['XGClassifier', 'RandomForestClassifier', 'KNearestNeighbors'], [xgc, rfc, knn]):
model.fit(X_train, y_train)
preds[model_name] = model.predict(X_test)
测试模型,获得分类报告:
from sklearn.metrics import classification_report, roc_curve, roc_auc_scorefor k in preds:
print("{} performance:".format(k))
print()
print(classification_report(y_test, preds[k]), sep='\n')
f1 成绩最好的是 XGC,其次是 RF,最后是 KNN。然而,我们也可以注意到,在召回(成功识别哑弹)方面,KNN 实际上做得最好*。这就是为什么模型堆叠是有价值的——有时,即使是 XGBoost 这样优秀的模型也可能在像这样的任务中表现不佳,显然要识别的函数可以进行局部近似。包括 KNN 的预测应该会增加一些急需的多样性。*
*# Plot ROC curves
for model in [xgc, rfc, knn]:
fpr, tpr, thresholds = roc_curve(y_test, model.predict_proba(X_test)[:,1])
plt.plot([0, 1], [0, 1], 'k--')
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curves')
plt.show()*
人气预测:第二轮
现在,我们可以对三个分类器的概率预测进行平均,并将其用作回归变量的一个特征。
*averaged_probs = (xgc.predict_proba(X)[:, 1] +
knn.predict_proba(X)[:, 1] +
rfc.predict_proba(X)[:, 1]) / 3X['prob_dud'] = averaged_probs
y = fb_data_only_df['Facebook']*
接下来是另一轮惠普调整,包括新的特性,我将不再赘述。让我们看看我们的表现如何:
*xgr = xgb.XGBRegressor(random_state=2, **params)# Fit the classifier to the training set
xgr.fit(X_train, y_train)y_pred = xgr.predict(X_test)mean_squared_error(y_test, y_pred)*
啊哦!这种性能本质上与我们进行任何模型堆叠之前是一样的。也就是说,我们可以记住,MSE 作为一种误差度量,往往会加重异常值。事实上,我们还可以计算平均绝对误差(MAE ),它用于评估具有显著异常值的数据的性能。在数学术语中,MAE 计算残差的 l1 范数,本质上是绝对值,而不是 MSE 使用的 l2 范数。我们可以将 MAE 与 MSE 的平方根进行比较,后者也称为均方根误差(RMSE)。
*mean_absolute_error(y_test, y_pred), np.sqrt(mean_squared_error(y_test, y_pred))*
平均绝对误差只有 RMSE 的 1/3 左右!也许我们的模型没有我们最初想象的那么糟糕。
作为最后一步,让我们根据 XGRegressor 来看看每个特性的重要性:
*for feature, importance in zip(list(X.columns), xgr.feature_importances_):
print('Model weight for feature {}: {}'.format(feature, importance))*
Aha! prob_dud was found to be the most important feature.
整洁!我们的模型发现prob_dud
是最重要的特性,我们的定制StandardizedDays
特性是第二重要的特性。(特征 0 到 14 对应于简化的标题嵌入向量。)
尽管通过这一轮的模型堆叠,整体性能并没有得到改善,但是我们可以看到,我们确实成功地捕获了数据中可变性的一个重要来源,而模型正是利用了这个来源。
如果我继续扩展这个项目以使模型更加准确,我可能会考虑用外部数据增加数据,包括通过宁滨或哈希将 Source 作为变量,在原始的 300 维向量上运行模型,并使用每篇文章在不同时间点的流行度的“时间切片”数据(该数据的配套数据集)来预测最终的流行度。
如果您觉得这个分析很有趣,请随意使用代码,并对其进行进一步扩展!笔记本在这里是(注意,一些单元格的顺序可能与这里显示的略有不同),这个项目使用的原始数据在这里是。
使用包装器登录 Python
使用 Python 进行日志记录可能会很乏味,尤其是在使用它进行调试的时候。我本人并不喜欢 Conda 或 Pycharm(或任何其他花哨的 IDE),但对于那些喜欢的人来说,当你必须将代码投入生产时,你总是会遇到调试/控制的问题。添加大量代码来查看发生了什么,浪费了大量宝贵的时间,而 Python 调试器(pdb)至少提供了很少的帮助。
但更重要的是,大多数时候,作为开发人员,我们需要向代码中添加日志,所以日志记录很可能不是我们可以选择退出的选项。
出于这个原因,我决定发表这篇文章,在这篇文章中,我将向你展示一个非常简单、省时和强大的方法来记录你的 Python 脚本。您可以将细节推断到其他语言,只要它们有包装器和记录器(我可能会在将来的另一篇文章中讨论这些)。
主要概念相当简单:您希望在每次进入或退出函数时进行记录。您希望大多数函数都是这样,至少上层函数是这样,这样,如果代码在某个点中断,您就知道它在哪里中断以及中断的原因。每当您想要记录函数的进入或退出(或任何其他重要事件)时,问题就来了。但是每个问题都有一个解决方案,在这种情况下,解决方案是包装。
首先我将展示包装在 Python 中是如何工作的,然后是日志记录,然后我将把两者结合起来展示一个简单的例子。最后,我将展示一个更复杂的例子来描述这个相当简单的概念的威力。
包装材料
Photo by freestocks.org on Unsplash
对于那些不知道什么是包装的人。包装一个函数意味着无论什么时候调用这个函数,都要做一些事情。这就是你在包装器中定义的东西。包装器的示例:
从这里得到。
在这种情况下,作为 wrap 函数中的参数接收的 pre 和 post 变量是您将在被包装的函数之前和之后调用的函数。例如,如果您正在包装函数 bake_pie(),并将函数 before_baking 和 after_baking 作为参数传递给包装器,代码将执行函数 before_baking(),然后是 bake_pie(),最后是 after_baking()。
包装器函数的通常形式是这样的:
如您所见,函数进入和退出的参数是另一个函数(您正在包装的函数)及其参数。
让我们继续日志记录!
记录
日志记录就像打印一样,只是打印到一个文件中,有许多控制选项和时间显示。它主要用于了解服务器上的应用程序正在发生什么,或者在部署时进行调试。Python 中的基本日志配置如下所示:
如您所见,您可以声明想要写入的文件名、想要的调试级别(以便只将某些消息写入文件)以及关于消息格式的一些其他配置。我不会详细讨论日志,因为已经有很多关于日志的文章了,说实话这并不有趣!
使用包装器记录日志
所以现在我们有了包装器和记录器,只是把它们加起来的问题。我们需要做的是在进入()和退出()函数中加入日志记录功能,以显示当我们遍历代码的不同函数时,日志文件中发生了什么。一个基本的例子可能是这样的:
我们在进入和退出函数中添加了日志消息。
剩下的最后一件事是将包装器“标签”添加到我们想要包装的函数中。这个标签通常被称为 anotation,它只是一个“@”符号,后面跟一个包装器的名字,就在你的函数上面:
如果我们把所有的部分放在一起,看起来会是这样的:
Logging with wrappers 101
例如,如果您使用 bake_pie(3)执行函数 bake_pie,您将得到下一个日志文件:
2019–03–08 09:38:47800 调试进入 bake_pie
2019–03–08 09:38:47800 调试退出 bake _ pie
你可以添加注释@wrap(进入,退出)到任何其他函数,它也会这样做,这就是它的强大之处,所有的功能只需添加一行简单的代码。
使用包装器的奇特日志记录
Photo by Jordane Mathieu on Unsplash
当然,你还可以做更有趣的事情。为了展示其中的一些,这里还有一个例子:
我已经改变了“pre”函数中的参数,所以它现在通过*args 接收它所包装的函数的参数。
现在,我们更改重要的部分,pre 函数本身,以便它给出关于它正在记录的函数的更详细的信息:
如您所见,我们现在记录了以下内容:
- 函数名
- 函数文档字符串
- 它在文件中的位置(行号)和文件名
- 传递给函数的第一个参数(如果有)
所有具有不同日志级别(调试、信息和警告)的日志
这是运行 bake_pie(3)将写入日志文件的内容:
2019–03–08 10:15:44919 DEBUG 进入 bake _ pie
2019–03–08 10:15:44919 INFO 烘烤一定量的馅饼
2019–03–08 10:15:44919 INFO 函数在 log gin _ with _ wrappers . py
2019–03–08 10:15:44919 警告
要检查一些很酷的内置你可以在这里显示 go 。你肯定会为包装器添加大量逻辑而疯狂,以便获得必要的最佳日志记录信息…
我希望这篇文章能帮助你减少花在日志记录上的时间和质量。
快乐日志:)
利用你自己设定的截止日期|今天就开始吧
为自己设定最后期限的艺术至关重要,不仅是为了超越要求,也是为了让我们在实现大大小小目标的过程中更加顺利。爱他们或者恨他们;它们是令人难以置信的激励期限!然而,在处理截止日期时,有两件事我们应该尽量避免,完美主义或在截止日期前死去,这两件事都会增加压力。
即使是一个项目、一个目标、一次会议等,自我安排的技术也可以实现。没有实际的截止日期。它帮助我们组织我们处理每一个必须完成的任务或我们想要完成的目标的方式。这些自我设定的截止日期应该根据每项工作的优先级进行战略上的**。**
为了让未来激励当前的行动,它必须让人感觉迫在眉睫。为了创造这种迫在眉睫的感觉,我们操纵了时间度量——考虑时间的单位(例如,天、年)。——小尼尔
目标是在几个月后取得重大胜利,这很好;然而,我们应该建立小的里程碑,小的成功!在几天内而不是几周或几个月内设定最后期限会在潜意识里激发一种更严肃和优先的意识。
无论我们是要写一篇文章,做一个项目,会见一个客户,计划一个营销活动,计划一个重大的变化,还是开始一项新的业务,我们都可以利用一些技巧和工具来避免淹没在焦虑中,因为延长的截止日期会对我们的健康造成严重破坏。
内部强加的期限减少了拖延。所以,自己设定最后期限可能比别人为你设定更好。—psychreg.com
技术
在过去的五年里,我每天都在使用的三个技巧是实现许多大大小小的里程碑的关键因素。他们让我明白了如何闯入数据科学和数字营销的世界。
ⓐ专注,提高生产力!
Photo by Patrick Tomasso at Unsplash
**为了获得高质量的结果,每天专注于一项任务是至关重要的。记住,**如果你想同时做所有的事情,你最终会一事无成!自我设定的期限是衡量你的行动是成功还是失败的重要标准。因此,优先考虑什么是最重要的,每天工作 3-4 小时,然后庆祝你的小里程碑!保持动力。
ⓑ建立短期里程碑,并庆祝!
Photo by Estée Janssens at Unsplash
处理大任务或大项目的一个很好的技巧是把它们分解成小的、小的里程碑。因此,这会让事情变得更加可行,这有助于开始工作并朝着最后期限努力。
完成任何一个里程碑后,犒劳或欺骗自己!设定最后期限,利用奖励和结果。
例如,作为我职业发展计划的一部分,我设定了一个目标,通过参加由 AJ & Smart 担任辅导员的设计冲刺大师班,在两周内阅读、学习和应用 设计冲刺 的力量。我决定,一旦我完成了这个项目,拿到了证书,我就再看一遍《指环王》三部曲!我做到了。
ⓒ 早起,今天又打脸了!
Photo by Johnson Wang at Unsplash
不管你是不是一个早起的人,在早上完成尽可能多的任务会提高你的生产力水平,鼓励你实现短期的里程碑。不过,提前计划是至关重要的!知道你早上要做什么,第二天早上要做什么,等等,将帮助你尽早实现每天的目标,然后,你就可以享受一天的剩余时间。然而,不要超出你的日常任务,除非你还在 3 到 4 个小时的范围内,或者你想为第二天节省一些时间。坚持每天的最后期限,保持专注,不断激励自己。
工具
他们不是必须的,但是,有时候你需要他们被组织起来,被激励着继续前进。你需要记录你的进展,记录你在每项任务上花费的时间。以下是我经常用来帮助我完成每个项目或任务的工具。
ⓐ时间追踪,用番茄工作法!
- Klokki for Mac :自动计时,记录我在一项任务或整个项目上花了多少时间。
Photo Courtesy by Klokki.com
- Toggl :另一个伟大的工具,我用它在我所有的设备上追踪每一个任务的时间。
Photo Courtesy by Klokki.com
番茄工作法:一种时间管理技巧,用来提高你的注意力和工作效率。这项技术应用一个计时器将一项任务分解成多个间隔,传统上是 25 分钟,中间间隔 5 分钟。
ⓑ工作管理
- 体位法:它有助于专注于你的工作目标、项目和日常任务。
Photo Courtesy by asana.com
你利用什么动机、工具、提示和奖励来满足自己设定的期限?
使用 CNN 来理解我们基因组的复杂性和预测未来的疾病
在过去的几年里,机器和深度学习领域的指数级进展已经为解决医疗保健的一些最困扰的问题提供了一种新的方法:深度学习。事实上,医疗保健领域的人工智能市场预计到 2025 年将超过360 亿美元!从比放射科医生更准确地诊断各种形式的癌症患者,到了解 cfDNA 甲基化模式如何对应癌症诊断,使用 AI 和深度学习的应用层出不穷。我们可以想象这样一个世界,人工智能已经成功地让我们实际上绘制了我们的整个基因组,并且**在致病突变发生前几年就预测它们!**像 Deep Genomics 和 Freenome 这样的初创公司在这个行业处于领先地位,而像 Verily 和 Calico 这样的大型生物技术初创公司正在得到谷歌的资助,并开始开发使用人工智能的应用程序。但为什么人工智能在医疗保健领域的应用市场发展如此迅速?
基因组数据量和可访问性的增加
2003 年,人类基因组计划(HGB)花费了 30 亿美元成功测序了第一个人类基因组。现在,领先的基因测序公司之一 Illumina 已经提供了迄今为止最便宜的测序测试,仅售 47 美元。随着 23andMe DNA 测试等服务的普及,以及对个性化医疗的进一步研究,这有助于大幅增加可用数据量,这是训练人工智能模型的必要条件。尽管如此,我们理解基因组的能力几乎只是它实际意义的一小部分。正如来自 Deep Genomics 的 Brendan Frey 所说,我们使用基因测序和基因编辑工具来测量和改变生物学的能力远远超过了我们实际理解生物学的能力。人工智能正在改变这一切。
我发现 Deep Genomics 正在做的工作绝对是疯狂的,我想亲自尝试一下,了解一下这两个快速发展的学科的交集。我决定从事一个涉及生物功能的项目,这个项目已经在许多实验室进行过,从斯坦福到 Deep Genomics 等公司。我想了解DNA-蛋白质结合相互作用是如何工作的以及基因变异如何影响转录因子蛋白质在转录过程中的作用。
但是等等!等等,这些词是什么意思?让我们退一步,了解什么是转录因子蛋白质,以及它们如何影响转录。是时候上一点生物学 101 课了!
转录因子是如何工作的,为什么会与 DNA 结合?
我们基因组中的每个基因都由三个主要部分组成:启动子、内含子和外显子。启动子本质上是基因中负责转录的部分,也就是将 DNA 转录成 RNA 的过程。接下来的部分是内含子,将近 10000 个核苷酸长,包含基因的逻辑。生物学家把它比作计算机程序,或者基因背后的大脑。内含子有助于组织绑定的工作方式。另一方面,外显子只有 100 个核苷酸长,并且负责执行内含子的逻辑**,或者使用计算机程序模拟的打印语句。**
这个过程是如何工作的,DNA 被转录成 RNA,RNA 被翻译成蛋白质。蛋白质对于身体组织和器官的结构、功能和调节是必不可少的,因此这一过程是必不可少的。这个过程通过转录因子结合来调节,转录因子结合控制转录和翻译发生的频率。这听起来可能很简单,但这三个组成部分之间的关系有许多复杂之处,通常情况下,我们的基因突变不会导致结合。影响一个核苷酸的小突变会导致疾病和病症,如家族性高胆固醇血症,并可能导致某些形式的癌症!
为了解决理解这一过程如何工作以及检测基因变异的问题,我一直在致力于一个项目,以在 PyTorch 和 Tensorflow 等现代机器学习框架上实现由 UofT 的研究人员在 2015 年创建的工具【Deep bind】,。这个模型是用 Matlab 编写的,我想看看我是否可以借助现在用于开发模型的更好的软件包和工具来提高或达到类似的精度。
deep bind 如何工作
DeepBind 是一种卷积神经网络架构,它接受有噪声的实验数据并输出结合亲和力,即转录因子蛋白质结合或粘附到序列上的可能性。虽然 CNN 通常用于图像数据,但该网络在基因组数据上工作得非常好,随机选择输入序列通过网络输出得分预测。根据我从 ENCODE 获得的实验数据,序列可以有不同的长度,从大约 15-100 个核苷酸。对于任何序列 s,该模型使用四个阶段计算结合分数 f(s)。
卷积阶段在整个序列中用参数 M 扫描一组模体检测器(4 x m 矩阵)。这使得系数不必是概率或对数奇数比(这是表达概率的另一种方式),不像位置权重矩阵(PWMs),其通常用于理解这些相互作用的序列特异性。
接下来,整流级将通过移动 motif 检测器的响应并使用整流线性单位函数(ReLU)将任何负值箝位至零来隔离任何模式。然后,它经过**汇集阶段,**其中模型计算每个基序检测器的最大值和平均值, M-k. 通过最大化,模型可以识别任何较长基序或模式的存在,而平均有助于增加或累积较短模式的效果。这两种汇集方法的贡献是由学习决定的。
Neural Network Produces Binding Score
最后,将神经网络输入到一个非线性神经网络中,权重为 W,结合基序检测器的响应产生一个分数。它采用维度为 d 的特征向量 z ,这是汇集到该输出分数中的输出,简单地使用可调权重的 (d+1) 维度向量,其中权重基于其对输出的贡献应用于向量中的每个值,并最终使用附加的偏置项来获得输出。然而,根据不同的网络配置,这是不同的。例如,如果我们实现 dropout,我们偶尔会忽略向量 z 的中间值,这具有很强的正则化效果。要了解这方面的更多信息,我建议查看他们发表在《自然》杂志上的论文的补充说明,这在我实现这个模型时对我非常有用。
然后,该模型将使用损失函数来比较模型的输出与结合相互作用的目标值,然后使用反向传播和随机梯度下降(sgd)来更新不同的参数,例如学习率。
DeepBind 运行良好的一个独特特性是自动训练管道。深度学习的最大障碍之一是模型对**校准参数或超参数非常敏感。**这些参数包括与训练算法相关的参数,如辍学、学习率、批量,而其他参数则与模型架构相关(层数和隐藏单元数),甚至更多!熟练地校准这些参数是提高模型准确性的关键。DeepBind 通过评估超参数的随机校准来自动化这一点,其中精度最高的模型根据训练数据进行训练。基于具有最佳准确度的候选,在新数据上测试超参数的校准,并且保存超参数校准用于在新数据上的进一步训练和测试。PyTorch 实现中保存超参数的代码如下所示:
deep bind 在基因组学研究中的应用
虽然这真的很酷,很迷人,但我们如何应用它来帮助解决医学和基因组学领域的问题呢?使用 DeepBind,我们可以通过计算机模拟来改变基因中某些结合位点的核苷酸,并确定它在结合上是积极还是消极的相互作用。例如,看看胆固醇基因的突变,我们可以看到某些突变可以通过影响结合亲和力来破坏结合位点。有时,这些突变对基因有积极的影响或没有影响,而其他突变会导致消极的原因,如胆固醇水平异常。
Source: NIPS 2017 Talk by Brendan Frey, CEO of Deep Genomics
结论
总之,人工智能在医疗保健领域的应用和可能性是无限的。从早期诊断,到了解疾病机制以开发治疗方法,人工智能以如此多的方式让我们以如此多的不同方式进一步解释基因组。使用 DeepBind,我们可以了解 DNA-蛋白质相互作用是如何工作的,并识别遗传变异和突变的影响。使用人工智能和深度学习,我们有机会了解隐藏在基因组内的许多秘密,并了解更多有关基本过程的信息。让我们确保我们理解生物学的能力与我们测量和改变生物学的能力相匹配,这样我们就能在治疗和研究方面做出最好的决定。
关键要点
- 人工智能和基因组学是两个快速发展的学科;将它们结合起来给了我们很多机会来改善医疗保健治疗和我们对基因组的理解。
- 使用 DeepBind,我们可以了解转录因子(TF)结合是如何工作的,并预测蛋白质是否会与基因结合。
- 通过计算机模拟,我们可以测试突变对基因的影响,以及它们是导致正突变还是负突变。
- 人工智能为我们提供了最好的机会,让我们理解生物学的能力与我们目前改变(想想 CRISPR-CAS9 和基因编辑)和测量生物学的能力相提并论。
后续步骤
如果您喜欢这篇文章,请务必遵循这些步骤,与我未来的项目和文章保持联系!
- 看看我在这个项目上发表的演讲!
- 在 Linkedin上与我联系,了解我未来的发展和项目。我目前正在研究 NVIDIA 在 2018 年 12 月创建的 StyleGAN,每天都在阅读更多的论文!
- 请务必订阅我的每月简讯,以查看我参加的新项目、会议和发表的文章!
- 随时给我发电子邮件在 seyonec@gmail.com 谈论这个项目和更多!
利用免费图像工具实现家庭安全
为 2019 年开发者周黑客马拉松创建的 Webapp
在之前的一篇文章中,我展示了开箱即用的图像识别软件如何让面部检测变得几乎微不足道,但在这篇博客中,我将分享其他免费使用的 API 与图像应用的不同应用。我最近和丹尼·门多萨、本杰明·梁和史蒂文·欧洋一起参加了三藩市的开发者周黑客马拉松,在那里我们制作了一个名为 HomeView 的家庭安全网络应用的演示。这款应用背后的前提是,我们将使用 Clariai 的图像分类 API 来实现家庭安全目的,1)检测家庭入侵,2)更智能地监控婴儿。在最高级别上,我们的家庭入侵探测器拍摄图像(来自生产环境中的实时视频),并对人脸进行计数,以确保其中至少有一个人住在房子里。婴儿监视器检测图片中是否有婴儿,或者婴儿是否处于危险状态,即图片中有刀或火。在任何危险情况下,我们都会向用户发送短信,提醒他们家中存在不安全情况。如果你想使用 Flask 构建一个类似的 webapp,这个项目的代码在 my GitHub 上。
该项目的家庭入侵部分利用了 Clarifai 的人脸嵌入和人脸检测模型。人脸嵌入模型将图片作为输入,并输出描述该人脸的 1024 维向量。使用我和队友的照片,我们将我们的面部向量存储为与任何新面孔进行比较的向量。为了比较我们的脸,我们使用了余弦相似度,一种与两个向量的角度而不是大小相关的距离度量。这是稀疏向量的常见比较度量,因为当许多维度通常为 0 时,它们会删除可以测量角度的自由度,从而限制我们的比较空间。因此,我们可以用一种比评估欧几里得距离稍微更敏感的方法来测量人脸之间的距离。在评估高维稀疏向量时,这种更大的粒度使我们在断言新面孔是或不是项目成员时更有信心。下面的代码显示了我们使用的函数:
一旦我们存储了地面真实人脸向量,我们将运行人脸检测模型来计算新图片中的人脸数量。然后,我们将新图片中的每张脸与我们的地面真实脸进行比较,并确保至少有一个余弦相似度高于设定的阈值。如果没有一个比较高于这个阈值,我们可以断言没有一个面部足够接近我们的地面真实面部来被认为是“安全的”,因此,存在入侵者。
我们 webapp 的婴儿监视器部分使用了不同的 Clarifai 产品:通用模型。Clarifai 的通用模型是一个卷积神经网络,经过训练,可以对具有数千个标签的图片中的对象进行分类。给定左边的图片,模型将分配标签“婴儿”和“狗”,估计图片中既有婴儿也有狗。知道我们可以把图像标签看作一个二元分类问题,我们简单地从一个视频中输入一系列图片给模型,并问它“图片中有没有婴儿?”。如果没有,我们会发短信给父母或任何安装 webapp 的人。由于通用模型被训练的标签过多,我们可以增加婴儿监视器的“智能”,也可以检查危险情况。我们添加了一个危险阈值来确定婴儿是否在玩玩具(这是不应该的),房间里是否有火,或者婴儿是否有刀。如果根据框架中的项目,婴儿被认为处于危险之中,我们将向父母发送短信。
我们使用 Twilio API 来发送短信。在安装、获得 API 密钥并导入包之后,我们将他们的 create message 函数插入到我们的逻辑中。下面的代码显示了一个示例:
from twilio.rest import Clientbody = "Text for your message"
client.messages.create(to="YOUR PHONE NUMBER",
from_="ORIGIN PHONE NUMBER",
body=body)
使用 if/else 逻辑,我们可以为不同的情况创建定制的文本消息,使用独特的文本和图像来描述情况,这可以在我们的存储库中的 app.py 文件中找到。
为了构建这项技术的演示,我们需要创建一个用户界面。Flask 是一个很好的工具,允许我们使用 Python 函数来影响网页,以显示我们编写的函数的效果。它太棒了,以至于有必要再写一篇博文来介绍所有这些伟大的特性。因为我是个老好人,我就把你联系到三个:烧瓶 是 伟大的。
在许多层面上都有大量优秀的图像识别工具——从为图片中的对象调用 API 到整个训练好的神经网络架构。像大多数编码领域一样(尤其是在 Python 中),您通常不需要重新创建轮子来创建优秀的图像处理应用程序。由于这些可用的工具,可能需要几个小时、几天或几周训练的东西现在可以成为黑客马拉松挑战中进展最快的部分之一,所以使用它们吧!
联合国会议数据,以更好地了解全球趋势
探索文本分类的应用
介绍
第二次世界大战后成立的联合国,是建立和维护全球社会的最重要步骤之一。自 1945 年成立以来,联合国年度会议一直是解决紧迫全球问题的平台,因此记录了一段时间以来的主要问题和趋势。
通过这个项目,我想利用一个名为“联合国一般性辩论”的 Kaggle 数据集来探索这些全球趋势。
了解数据集
这个数据集有一些有意义的特征。每个实例都包含年份、会议编号、发言国家和会议记录。该数据集包含 1970 年至 2015 年的会话数据,时间范围为 46 年。我的第一步是汇总每年的会议,并为每年生成一个文本文件。然后,我使用 Sklearn 的 CountVectorizer 类来执行单词包,并输出每年排名前 10 的单词。有了这些信息,我用 Illustrator 生成了每年更常见单词的可视化描述。
生成数据可视化的思维过程
对于视觉效果,我心中有几个要点
- 可读的时间线— 观众应该能够直观地理解时间年表
- 关注趋势— 数据可视化的主要收获是快速流畅地理解数据中存在的主要趋势和异常。
- 访问数据— 虽然我想关注趋势,但我仍然希望浏览者能够看到数据(每年最常出现的词),并可能根据世界历史的先验知识或通过数据中有趣实例引发的研究得出自己的结论。
我想出了两个模型:
- 一种是按十年来划分数据——更容易理解,允许观众挑选他们想关注的细节
- 一个包含 1970 年至 2015 年间每年的数据,虽然需要考虑更多内容,但不会直观地将趋势划分为任意类别,而实际上,每年的数据趋势在本质上是连续的。
下面是第二个数据可视化,它记录了 1970 年到 2015 年之间的每年实例。
设计和数据表示
用色彩传达趋势
有些术语多年来一直出现,而有些只出现一两次。某些术语出现在数据集的中间,并且一直持续到最后。为了突出这些主要趋势和异常值,我给每个术语分配了颜色来标记它们。这样,观众可以在视觉上跟踪一个术语的存在和随时间变化的流行度。在整个数据集中一致的术语被分配较深的颜色,这提供了足够的但与背景(社区、权利、发展)几乎没有对比。被认为值得注意但不太重要的术语也被赋予较深的颜色(reform,2015)。在数据集时间线中间出现的术语,然后仍然是一个流行词,被赋予稍微明亮的颜色值(全球,气候)。此外,与世界危机和人类苦难原因相关的术语被赋予了明亮和不和谐的色彩(恐怖主义、核)。最后,那些只被提及几次的强有力的词被赋予了明亮柔和的颜色(千禧年,希望)。最后两个类别被指定为上述颜色类型,以便它们在浏览者看来最为突出。
关于主观数据分析的注记
我想简要说明一下我在这个数据表示中所做的主观选择。
清理文字稿:在清理文字稿时,我首先删除了一般的英语停用词。然而,在计算每年的前十个词时,我发现前十个词中的大多数词在过去的 46 年中保持一致。这些术语都是特定领域的术语。为了能够更深入地挖掘会议的内容,我删除了许多特定领域的术语。我想指出的是,我这样做是基于哪些术语出现得非常频繁,但设置了一个任意的阈值,即哪些术语出现得足够频繁,可以删除,哪些可以保留。改变阈值无疑会改变来自单词袋的结果。回顾已完成的工作,也许较低的去除单词的阈值会给出更具体和独特的逐年数据集。较低的门槛将消除诸如“社区”、“权利”和“发展”等术语。
删除了一些词语:国际、国家、联合、我们、世界、和平、国家、人民、组织、会议、安全、经济、政府
**类别分配:**我分配术语类别的过程本质上是非常定性的。像决定“合作”是相关的和有意义的,“支持”这样的选择是经过深思熟虑的,但仍然是主观的决定。
**词根和词类:**在我当前的项目实现中,为了简单和直接,像“开发”和“发展”这样的术语被视为同一术语。但是,需要注意的是,两者的区别中有加密的有意义的信息。有了语言学背景,人们可以根据单词的名词或动词形式所暗示的句子结构,潜在地得出关于时间段的结论(即,动词形式的频率可能暗示更有可能采取行动)。
有趣的数据发现
- 1989 年— **环境:**第一次提到前 15 名中的环境。
- 1990-1991—**希望:**当我们在 1988 年看到“希望”的时候,这个词在 1990 年和 1991 年的前 15 名中再次出现。
- 1991 年— **民主党:‘**民主党’出现在前 15 名。
- 1996 — **武器:‘**武器’出现在前 15 名。
- 2001—**9 月:**这个词出现在 2001 年的前 15 名中,表明 9/11 和恐怖主义是主要话题之一
- 2004 年— 今天:“今天”一词进入了 2004 年的前十名。在那之后,“今天”这个词开始频繁出现在前 15 名中,这可能暗示了观点的转变
- 气候和可持续性— 这些术语在 2000 年代开始频繁出现
- 2015—“2015”在 2013 年和 2014 年出现的次数比 2015 年多。这可能意味着 2015 年将出台一项政策或在 2015 年实现一个目标。2015 年可能讨论了 2015 年议程的影响或发现。
- 社区— 历年来使用频率最高的词,其次是“权利”
虽然我将这一部分作为有趣的数据发现包括在内,但看到许多有趣的收获都在前 15 名中,这表明也许删除一些更多的流行语会每年显示一个更独特的故事。与此同时,有趣的是,人权和社区等永恒的讨论仍然非常重要,但在优先级别上有所波动。
反思项目
我使用 Sklearn 的计数矢量器来生成每年的热门词汇。TF-IDF(术语频率-逆文档频率)可能会提供关于逐年趋势的更有见地的信息,因为它会突出显示逐年的异常,而不是强调所有会话数据中常见的术语。
有趣的扩展
我对年复一年的会议数据运行了一个主题生成算法(潜在的狄利克雷分配),只是为了看看该算法每年输出的头号主题是什么。以下是一些亮点:
1977: new rights africa south nuclear relations time situation independence east struggle that disarmament great israel
— — — — — — — — —
1990: new south africa rights region europe war time hope state end crisis relations kuwait east
— — — — — — — — —
1995: new rights nuclear social cooperation war time work process many important member region year weapons
— — — — — — — — —
2000: new millennium rights summit cooperation process global state globalization time work first role poverty social
— — — — — — — — —
2001: terrorism new global cooperation year poverty terrorist secretary september many process work africa state rights
— — — — — — — — —
2009: global change crisis climate new financial that president challenges cooperation nuclear 09 time year rights
— — — — — — — — —
2014: global new that climate sustainable agenda 2015 rights change state year today goals post many
维斯。使用 Tensorflow 生成图像
更新 25/01/2021:我会很快更新这些帖子,在 Twitter 上关注我以获得更多信息https://twitter.com/mmeendez8
在我的前一篇文章中,我介绍了可变自动编码器背后的理论。现在是时候动手开发一些代码来引导我们更好地理解这项技术了。我决定使用 Tensorflow,因为我想用它来提高我的技能,并适应被推向 2.0 版本 … 阅读更多信息
VAEsemane——一种用于音乐人机交互的可变自动编码器
类人机器人解决越来越困难的任务,因为它们稳步提高了与环境智能互动的技能。这个项目的目标是用软件合成器或人形机器人【Roboy】**交互式播放音乐。**音乐即兴创作是对当前呈现的音乐序列产生自发反应的行为,要求对乐器和呈现的音乐序列在音调、节奏和和声方面有很高的理解,这使得将这一系统付诸实践尤为困难。
Google Magenta(music vae)和ETH Zurich(MIDI-VAE)的研究人员最近一直在研究用软件生成音乐的可变自动编码器(VAEs) 。乔治亚理工大学展示了一个软硬件结合的系统,名为“西蒙机器人】。
Fig. 1: Shimon robot developed at Georgia Tech University [Source: https://www.shimonrobot.com/]
对于这个项目,VAEs 被选为即兴创作的基础。VAEs 有一个很大的好处,那就是它们产生了一个连续的潜在空间,允许重建和解释数据。在 VAE 被训练之后,VAE 的解码器可以用来随机生成数据,该数据类似于它通过从单位高斯采样而被训练的数据。这种随机生成过程显示在下面的一个视频示例中。
该系统
Fig. 2: A full framework for robotic improvisation in real time
系统等待音乐序列的输入,以即兴序列来响应。它被分成所示的模块(见图 2)。任何 MIDI 控制器、键盘或合成器都可以用来播放音乐序列,为系统提供现场输入。该序列由 VAE 的编码器处理,将其嵌入潜在空间。音乐序列的潜在表示也称为嵌入,可以使用称为潜在空间修改器的图形用户界面(GUI)来重建或修改。GUI 允许修改 100 维潜在向量的值,创建由 VAE 解码器解码的新潜在向量,以形成新的音乐序列。可选地,序列可以被音符平滑器模块平滑,该模块将短 MIDI 音符视为噪声,并根据用户定义的阈值删除它们。即兴序列可以由软件合成器演奏,或者通过机器人操作系统(ROS)发送给模拟的机器人 Roboy** ,以便机器人在木琴上演奏。**
该系统使用卷积 VAE,而不是使用递归 VAE(如 Google Magenta 和 ETH Zurich 所示)。图 3 显示了 VAE 的**编码器。**解码器由编码器的逆映射组成。
Fig. 3: Architecture of the VAE encoder (adapted from Bretan et al. 2017). The decoder consists of the inverse mapping without the reparametrization step. The figure was created using NN-SVG.
使用 PyTorch 实现 VAE,并用 MAESTRO 数据集 进行训练。图 3 显示了所有的卷积运算。在一个音乐序列被嵌入到一个 **100 维潜在向量之前有 4 个密集层。**解码器由编码器的逆映射组成,没有重新参数化步骤。此外,批处理标准化和 ELU 激活函数适用于每一层。描述这个框架核心的 VAE 模型的代码如下所示。你可以在这里 找到 项目的完整源代码。****
模拟使用 CARDSFlow 框架(cards flow 的源代码这里,论文这里)这是 Roboy 项目(与香港中文大学合作)开发的肌肉骨骼机器人的设计、模拟和控制的工作流。图 4 显示了从 Autodesk Fusion 360 中的机器人设计到实际硬件控制的流程。
Fig. 4: CARDSFlow pipeline. It consists of (from left to right): 1) Robot design in Autodesk Fusion 360, 2) Simulation in Gazebo, 3) Muscle control through CASPR in Gazebo and 4) Control of the real robot.
下图(图 5)展示了在 ROS 的可视化工具 RVIZ 中模拟 Roboy 机器人的设置。
Fig. 5: Setup of Simulation in RVIZ.
例子
有五个典型的视频。其中三个展示了 VAE 模型在软件中生成音乐**,而两个视频展示了机器人进行即兴创作。GUI,也称为潜在空间修改器,有 100 个数字电位计来修改当前嵌入序列的潜在向量。修改潜在向量导致解释或即兴创作,因为它略微改变了当前嵌入序列的高斯分布。在包括模拟 Roboy 机器人的示例中,绿色轮廓显示了机器人击打木琴球杆时的目标姿势。注:模拟机器人在演奏木琴时会跳过 MIDI 音符。这就是为什么它播放的音符比软件中生成的音符少的原因。**
生成模式
第一个示例显示了 VAE 模型在“生成模式”下的性能。在这种模式下,从单位高斯分布中随机采样一个潜在向量**,然后由 VAE 解码器解码以生成看不见的音乐序列。**
Variational Autoencoder — “Generate Mode” (Software Generation)
交互模式
下面的例子使用了“交互模式”,它允许人机交互。软件/机器人等待人类输入,并基于当前输入序列产生音乐响应。
Variational Autoencoder — “Interact Mode” (Software Improvisation)
Variational Autoencoder and Roboy robot — “Interact Mode” (Robotic Improvisation)
无尽模式
下面的例子显示了**“无休止模式”**,它等待人工输入,然后根据顺序开始播放音乐,直到你停止它。当前生成的序列(从 VAE 解码器输出)被馈送到输入端以产生解释。除了为软件/机器人即兴创作提供指导的第一个序列之外,没有其他互动。通过改变数字电位计的值,您可以遍历已学习的潜在空间,从而听到 VAE 模型学习了什么。
Variational Autoencoder — “Endless Mode” (Software Improvisation)
Variational Autoencoder and Roboy robot — “Endless Mode” (Robotic Improvisation)
机器人项目
Roboy 项目是一个用于肌肉骨骼机器人开发的开源平台,其目标是将人形机器人推进到机器人和人体一样好的状态。 Roboy 从其他机器人中脱颖而出,因为它是由模仿人类肌肉和肌腱的电机和肌腱驱动的,而不是每个关节中的电机。查看机器人项目网站或 Github 账户以获得更多信息。
Chest of Roboy 2.0 [Source: https://roboy.org]
Vaex:具有超级字符串的数据帧
Vaex’ strings are super fast, not related to M-theory yet
字符串操作是数据科学的重要组成部分。Vaex 的最新版本为所有常见的字符串操作增加了令人难以置信的速度和内存效率支持。与 Pandas(Python 生态系统中最受欢迎的数据帧库)相比,字符串操作在四核笔记本电脑上快 30-100 倍,在 32 核计算机上快 1000 倍。
虽然 Pandas 对 Python 在数据科学中的流行负有很大责任,但它渴望内存。随着数据变得越来越大,你必须小心不要有记忆或者毁了你的一天。切换到更强大的机器可能会解决一些内存问题,但现在您的 31 个核心处于闲置状态。熊猫只会用你花里胡哨的机器 32 个核心中的一个。有了 Vaex,所有的字符串操作都在核心之外,并行执行,延迟评估,使您可以毫不费力地处理十亿行数据集。
“字符串处理速度几乎快了 1000 倍,相当于 1 分钟对 15 个小时!”
Vaex 和超弦
Vaex 现在正在超越快速数字处理,扩展到(超级)字符串领域。最新发布的包括了几乎所有熊猫的串串操作。现在,您可以轻松地执行所有的字符串操作,通过计算包含一个 googol (1 后跟 100 个零)行的数据帧中的字符串长度就可以证明这一点。
一个 googol 长度的数据帧展示了惰性评估的优势。当在严重畸形的输入数据上试验正则表达式时,您不必等一分钟就能看到您的所有操作是否正常。相反,您应用您的操作,打印出数据帧,并直接看到预览(头部和尾部),没有任何延迟。仅评估您看到的值。
性能基准
最终,你必须处理所有的数据。惰性评估不会加速操作,只会推迟操作。如果你需要导出数据或者把它传递给机器学习库,这需要最终发生,对吗?那么 vaex 表现如何呢?让我们拿一个有 1 亿行的人工数据集(详见附录),用 Pandas 和 Vaex (Spark 随后)进行同样的操作:
NOTE: Larger is better, x is logarithmic. Speedup of Vaex compared to Pandas on a quadcore laptop or 32 core machine. On your laptop you may expect 30–100x, on an AWS h1.8xlarge (32 core) we measured close to a 1000x speedup!
Vaex 在我的四核笔记本电脑上的运行速度提高了约 190 倍,在 AWS h1 . x8 大型计算机上甚至提高了约 1000 倍!最慢的操作是正则表达式,这是意料之中的。正则表达式是 CPU 密集型的,这意味着大部分时间花在运算上,而不是所有的簿记工作。简而言之,Python 的开销很低,而且 Python 的正则表达式引擎已经很快了,所以我们“仅仅”获得了 10-60 倍的加速。
如何:GIL、C++和 ApacheArrow
这怎么可能呢?涉及到三个要素:C++、 Apache Arrow 和全局解释器 Lock GIL (GIL)。在 Python 中,多线程受到 GIL 的阻碍,使得所有纯 Python 指令实际上都是单线程的。当迁移到 C++时,GIL 可以被释放,机器的所有内核都将被使用。为了利用这一优势,Vaex 在 C++中执行所有的字符串操作。
下一个要素是定义一个内存和磁盘上的数据结构,该数据结构能够有效地使用内存,这就是 Apache Arrow 发挥作用的地方。Apache Arrow 定义了一个经过深思熟虑的 StringArray,可以存储在磁盘上,对 CPU 友好,甚至支持屏蔽/空值。最重要的是,这意味着所有支持 Apache Arrow 格式的项目将能够使用相同的数据结构,而无需任何内存复制。
达斯克怎么办?
人们经常问 Dask 和 Vaex 相比如何。 Dask 是一个神奇的库,允许 Python 并行计算。事实上,我们希望将来在 dask 的基础上构建 Vaex,但是它们不能相提并论。然而,Vaex 可以与 dask.dataframe 相比较,dask . data frame 是一个使用 Dask 并行熊猫的库。对于我们运行的基准测试,dask.dataframe 实际上比纯熊猫慢(~ 2 倍)。由于 Pandas 字符串操作不释放 GIL,Dask 不能有效地使用多线程,因为它使用 numpy 进行计算时会释放 GIL。绕过 GIL 的一个方法是使用 Dask 中的进程。然而,与 Pandas 相比,它的运行速度慢了 40 倍,Pandas 慢了 1300 倍。)相比 Vaex。大部分时间都花在酸洗和拆线上。
虽然 Dask 是一个神奇的库,但 dask.dataframe 无法在字符串领域施展魔法。它继承了 Pandas 的一些问题,并且由于酸洗,使用进程会产生很大的开销。尽管可能有方法可以加快速度,但开箱即用的性能对于字符串来说并不太好。
火花呢?
Apache Spark 是 JVM/Java 生态系统中处理数据科学的大型数据集的库。如果 Pandas 不能处理特定的数据集,人们通常会求助于 PySpark,即 Spark 的 Python 包装器/绑定。如果你的工作是产生结果,而不是在本地或甚至在一个集群中产生火花,这是一个额外的障碍。因此,我们还针对相同的操作对 Spark 进行了基准测试:
NOTE: Larger is better, x is logarithmic. Comparing Vaex, Pandas and Spark.
Spark 的表现比熊猫更好,这是多线程的缘故。我们惊讶地看到 vaex 比 Spark 做得好得多。总的来说,如果你想在笔记本电脑上进行交互式工作:
- 熊猫每秒可以处理数百万条字符串(并且不可扩展)
- Spark 每秒可以处理 1000 万个字符串(并且会随着内核数量和机器数量的增加而增加)。
- Vaex 每秒可以处理 1 亿个字符串,并且会随着内核数量的增加而增加。在一台 32 核的机器上,我们每秒可以处理十亿个字符串。
注意:有些操作会随字符串长度缩放,因此根据问题的不同,绝对数可能会有所不同。
今后
熊猫将永远存在,它的灵活性是无与伦比的,这在很大程度上是 Python 在数据科学中流行的原因。然而,当数据集变得太大而无法处理时,Python 社区应该有很好的答案。达斯克。dataframe 试图通过在熊猫的基础上构建来攻击大型数据集,但继承了它的问题。或者,nVidia 的 cuDF(RAPIDS 的一部分)通过使用 GPU 来解决性能问题,但需要现代 nVidia 显卡,内存限制更多。
Vaex 不仅试图通过使用更多的 CPU 内核和高效的 C++代码进行扩展,而且还通过其表达式系统/惰性评估采取了不同的方法。计算和操作仅在需要时进行,并以块的形式执行,因此不会浪费内存。更有趣的是,导致您的结果的表达式被存储。这是 vaex-ml 的基础,vaex-ml 是一种进行机器学习的新方法,其中管道成为您探索的人工产物。敬请关注。
结论
Vaex 使用 ApacheArrow 数据结构和 C++将字符串操作的速度在四核笔记本电脑上提高了大约 30-100 倍,在 32 核计算机上提高了 1000 倍。Pandas 几乎支持所有的字符串操作,内存使用几乎为零,因为惰性计算是分块进行的。
- 为这篇文章鼓掌或者一个⭐on GitHub 被赞赏。
- Vaex 拥有和熊猫一样的 API。
- 的用法参见教程。
- 提交问题如果你发现了一个缺失的特性或者 bug。
- pip install vaex/conda install-c conda-forge vaex 或阅读文档
附录
基准测试从来都不公平,有时可能是人为的,并且与真实世界的性能不完全相同。每个人都知道或者应该知道这一点。基准测试给你一个预期的印象,但是特别是对于像正则表达式这样的操作,比较就变得很棘手。有基准总比没有好。在任何情况下,如果您想要重现这些结果,您可以通过使用这个脚本通过来实现。火花基准可以在这个位置找到。
关于作者
Maarten Breddels 是一名企业家 和自由职业的开发人员/顾问/数据科学家,主要在 Jupyter 生态系统中使用 Python、C++和 Javascript。vaex . io创始人。他的专业领域从快速数值计算、API 设计到 3d 可视化。他拥有 ICT 学士学位,天文学硕士和博士学位,喜欢编码和解决问题。
这项工作是在约万·韦利亚诺斯基*帕特里克·博斯 和 布拉特·亚米诺夫 的帮助下完成的*
验证你的机器学习模型
机器学习
超越 k 倍交叉验证
Photo by NeONBRAND on Unsplash
我认为创建你的机器学习模型最被低估的一个方面是彻底的验证。使用适当的验证技术有助于您理解您的模型,但最重要的是,估计一个无偏的泛化性能。
没有适用于所有场景的单一验证方法。了解您是在处理组、时间索引数据,还是在验证过程中泄漏数据是很重要的。
哪种验证方法适合我的用例?
在研究这些方面时,我发现了大量描述评估技术的文章,但是验证技术通常停留在 k 倍交叉验证。
我将向您展示使用 k-Fold CV 的世界,并进一步深入到嵌套 CV 、 LOOCV ,以及模型选择技术。
将演示以下验证方法:
- 训练/测试分割
- k 倍交叉验证
- 留一交叉验证
- 留一组交叉验证
- 嵌套交叉验证
- 时间序列交叉验证
- Wilcoxon 符号秩检验
- 麦克内马试验
- 5x2CV 配对 t 检验
- 5x2CV 组合 F 测试
1.拆分您的数据
所有验证技术的基础是在训练模型时拆分数据。这样做的原因是为了理解如果你的模型面对之前没有见过的数据会发生什么。
训练/测试分割
最基本的方法是训练/测试分离。原理很简单,您只需将数据随机分成大约 70%用于训练模型,30%用于测试模型。
Creating a train/test split with X being your features and y the target
这种方法的好处是,我们可以看到模型如何对以前看不到的数据做出反应。
然而,如果我们数据的一个子集只有特定年龄或收入水平的人呢?这通常被称为采样偏差:
抽样偏倚是由于人口中的非随机样本引起的系统误差,导致人口中的一些成员比其他成员更不可能被包括在内,从而导致有偏倚的样本。
A great illustration of sampling bias by http://www.jondornart.com/
在讨论有助于解决采样偏差的方法(如 k 倍交叉验证)之前,我想先讨论一下额外的维持集。
维持集
当优化您的模型的超参数时,如果您使用训练/测试分割进行优化,您可能会过度拟合您的模型。
为什么?因为模型会搜索符合您所做的特定训练/测试的超参数。
要解决这个问题,您可以创建一个额外的保持集。这通常是您在任何处理/验证步骤中没有使用的数据的 10%。
在训练/测试分割上优化您的模型之后,您可以通过验证维持集来检查您是否没有过度拟合。
提示:如果只使用训练/测试分割,那么我建议比较你的训练和测试集的分布。如果它们差别很大,那么你可能会遇到泛化的问题。使用刻面轻松比较它们的分布。
2.k 倍交叉验证(k 倍 CV)
为了最小化抽样偏差,我们可以考虑稍微不同的方法验证。如果我们不是进行一次拆分,而是进行多次拆分,并对这些拆分的所有组合进行验证,会怎么样呢?
这就是 k 折叠交叉验证的用武之地。它将数据分成 k 个折叠,然后在 k -1 个折叠上训练数据,并在被遗漏的一个折叠上进行测试。它对所有组合执行此操作,并对每个实例的结果进行平均。
5-Fold Cross-Validation
优点是所有的观察值都用于训练和验证,并且每个观察值只用于一次验证。我们通常选择 i=5 或 k =10,因为它们在计算复杂性和验证准确性之间找到了一个很好的平衡:
提示:交叉验证技术得出的每个折叠的分数比人们想象的更有洞察力。它们主要用于简单地提取平均性能。然而,人们也可以查看结果折叠的方差或标准偏差,因为它将给出关于不同数据输入的模型稳定性的信息。
3.留一法交叉验证(LOOCV)
k 折叠 CV 的一个变体是留一交叉验证(LOOCV)。LOOCV 使用数据中的每个样本作为单独的测试集,而所有剩余的样本形成训练集。此变体与 k 相同——当 k = n (观察次数)时折叠 CV。
Leave-one-out Cross-Validation
使用 sklearn 可以轻松实现:
Leave-one-out Cross-Validation
**注意:**由于模型需要训练 n 次,LOOCV 的计算成本非常高。只有当数据很小或者你能处理那么多计算时才这样做。
留一组交叉验证
k 文件夹 CV 的问题是,你可能希望每个文件夹只包含一个组。例如,假设您有一个包含 20 家公司及其客户的数据集,您希望预测这些公司的成功。
Leave-one-group-out Cross-Validation
为了保持文件夹的“纯粹性”并且只包含一个公司,您可以为每个公司创建一个文件夹。这样,你就创建了一个 k 倍简历和 LOOCV 的版本,其中你漏掉了一家公司/集团。
同样,可以使用 sklearn 实现:
Leave-one-group Out Cross-Validation
4.嵌套交叉验证
当您优化模型的超参数,并使用相同的 k-Fold CV 策略来调整模型和评估性能时,您会面临过度拟合的风险。您不希望在找到最佳超参数的同一分割上评估模型的准确性。
相反,我们使用嵌套交叉验证策略,允许将超参数调整步骤与误差估计步骤分开。为此,我们嵌套了两个 k 重交叉验证循环:
- 超参数调谐的内循环和
- 估算精确度的外环。
Nested Cross-Validation (Outer loop: 5-Fold CV, Inner loop: 2-Fold CV)
下面的示例显示了一个对内部和外部循环都使用 k-Fold CV 的实现。
您可以自由选择在内部和外部循环中使用的交叉验证方法。例如,如果要按特定的组进行分割,可以对内部循环和外部循环都使用 Leave-one-group-out。
5.时间序列 CV
现在,如果你对时间序列数据使用 k -Fold CV 会发生什么?过度拟合将是一个主要问题,因为你的训练数据可能包含来自未来的信息。重要的是,所有的训练数据都发生在测试数据之前。
验证时间序列数据的一种方法是使用 k -fold CV,并确保在每个 fold 中,训练数据发生在测试数据之前。
5-Fold Time Series CV
幸运的是,sklearn 再次伸出了援手,它有一个内置的时间序列 CV:
注意:确保根据您使用的时间索引对数据进行排序,因为您没有为时间序列片段提供时间索引。因此,它将简单地根据记录出现的顺序创建拆分。
6.比较模型
什么时候你认为一个模型比另一个更好?如果一个模型的准确性比另一个高得不明显,这是选择最佳模型的充分理由吗?
作为一名数据科学家,我想确保我了解一个模型是否真的比另一个模型更准确。幸运的是,有许多方法将统计学应用于机器学习模型的选择。
Wilcoxon 符号秩检验
其中一种方法是 Wilcoxon 符号等级测试,这是配对学生的 t 测试的非参数版本。当样本量很小并且数据不符合正态分布时,可以使用它。
我们可以应用这个显著性测试来比较两个机器学习模型。使用 k 折叠交叉验证,我们可以为每个模型创建 k 个准确度分数。这将产生两个样本,每个模型一个。
然后,我们可以使用 Wilcoxon 符号秩检验来检验这两个样本是否存在显著差异。如果是的话,那么一个比另一个更准确。
Wilcoxon signed-rank test procedure for comparing two Machine Learning models
下面,您可以看到这个过程的实现。
Application of the Wilcoxon signed-rank test
结果将是一个 p- 值。如果该值低于 0.05,我们可以拒绝模型之间没有显著差异的无效假设。
注意:在模型之间保持相同的折叠是很重要的,以确保样本来自相同的人群。这可以通过在交叉验证过程中简单地设置相同的 random_state 来实现。
麦克内马试验
McNemar 检验用于检查一个模型和另一个模型之间的预测匹配程度。这被称为列联表的同质性。从该表中,我们可以计算出 x ,该值可用于计算p-值:
McNemar’s test for comparing two Machine Learning models
同样,如果p-值低于 0.05,我们可以拒绝零假设,并看到一个模型明显优于另一个。
我们可以使用[mlxtend](http://rasbt.github.io/mlxtend/installation/)
包创建表格并计算相应的p-值:
McNemar’s test
5x2CV 成对t-测试
5x2CV 配对t-测试由于其强大的统计学基础,是一种常用于比较机器学习模型的方法。
该方法工作如下。假设我们有两个分类器,A 和 b。我们随机地将数据分成 50%的训练和 50%的测试。然后,我们根据训练数据训练每个模型,并计算来自测试集的模型之间的精确度差异,称为*。然后,在 DiffB 中反转训练和测试分割并再次计算差异。*
这重复五次,之后计算差异的平均方差( S )。然后,用于计算t*-统计量:*
其中 DiffA₁ 为第一次迭代的均值方差。
5x2CV paired t-test procedure for comparing two Machine Learning models
同样,我们可以使用[mlxtend](http://rasbt.github.io/mlxtend/installation/)
包来计算相应的p*-值:*
注:你可以使用组合的 5x2CV F 检验来代替,它被证明是稍微更稳健的( Alpaydin,1999 )。该方法在mlxtend
中实现为
from mlxtend.evluate import combined_ftest_5x2cv
。
结论
验证可能是一个棘手的问题,因为它需要对数据有深刻的理解,以便选择正确的程序。希望这能帮助你对经常用于验证的方法有所了解。
所有的代码都可以在这里找到:
这个报告包含了验证博客的代码。
github.com](https://github.com/MaartenGr/validation)*
感谢您的阅读!
如果你像我一样,对人工智能、数据科学或心理学充满热情,请随时在 LinkedIn 上添加我,或者在 Twitter 上关注我。
验证方法
在本帖中,我们将讨论以下概念,它们都旨在评估分类模型的性能:
- 模型的交叉验证。
- 混乱矩阵。
- ROC 曲线。
- 科恩的 κ 分数。
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import warningswarnings.filterwarnings('ignore')
我们首先创建一些具有三个特征和二进制标签的简单数据集。
from sklearn.model_selection import train_test_split# Creating the dataset
N = 1000 # number of samples
data = {'A': np.random.normal(100, 8, N),
'B': np.random.normal(60, 5, N),
'C': np.random.choice([1, 2, 3], size=N, p=[0.2, 0.3, 0.5])}
df = pd.DataFrame(data=data)# Labeling
def get_label(A, B, C):
if A < 95:
return 1
elif C == 1:
return 1
elif B > 68 or B < 52:
return 1
return 0df['label'] = df.apply(lambda row: get_label(row['A'],row['B'],row['C']),axis=1)# Dividing to train and test set
X = np.asarray(df[['A', 'B', 'C']])
y = np.asarray(df['label'])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
为了演示的目的,让我们尝试使用一个简单的逻辑回归。
from sklearn import linear_model
from sklearn.model_selection import cross_val_scoreclf = linear_model.LogisticRegression()
clf.fit(X_train, y_train)print(">> Score of the classifier on the train set is: ", round(clf.score(X_test, y_test),2))>> Score of the classifier on the train set is: 0.74
交叉验证
交叉验证背后的想法很简单——我们选择某个数字 k ,通常是 k =5 或者 k =10 (5 是 sklearn 中的默认值,参见[1])。我们将数据分成 k 个大小相等的部分,在这些部分的k1 上训练模型,并在剩余部分上检查其性能。我们这样做 k 次,我们可以对分数进行平均以获得一个 CV 分数。
优点:使用交叉验证可以给你一个暗示,告诉你你的模型做得有多好,它的优点是非常健壮(与简单的训练-测试分割相反)。它还可以用于参数的超调:对于给定的参数,使用 CV 分数以稳健的方式优化其值。
让我们看看我们的例子的 CV 分数:
scores = cross_val_score(clf, X_train, y_train, cv=10)
print('>> Mean CV score is: ', round(np.mean(scores),3))
pltt = sns.distplot(pd.Series(scores,name='CV scores distribution'), color='r')>> Mean CV score is: 0.729
还可以使用 CV 分数的值来导出置信区间,在该置信区间中,我们可以确保找到实际分数的概率很高。
混淆矩阵
这个想法相当简单。我们希望显示真阳性(TP),真阴性(TN),假阳性(FP)和假阴性(FN)。更一般地,当有几个标签时,我们显示属于标签 i 但被归类为 j 的数据点的数量。这个数字被定义为混淆矩阵的( i , j )条目。
from sklearn.metrics import confusion_matrix
C = confusion_matrix(clf.predict(X_test),y_test)
df_cm = pd.DataFrame(C, range(2),range(2))
sns.set(font_scale=1.4)
pltt = sns.heatmap(df_cm, annot=True,annot_kws={"size": 16}, cmap="YlGnBu", fmt='g')
ROC 曲线
让我们仔细看看混淆矩阵。我们讨论了真阳性(TP)和假阳性(FP)的概念。很明显,如果我们允许 FP 为 1,那么 TP 也将等于 1;一般来说,如果 TP 和 FP 相等,我们的预测和随机猜测一样好。
ROC 曲线被定义为 TP 作为 FP 的函数的图。因此,根据以上讨论,ROC 曲线将位于直线 y = x 上方。
ROC 曲线的构建来自我们的分类器分配给每个点的概率;对于用标签 li ∈{0,1}预测的每个数据点 xi ,我们有一个概率 pi ∈[0,1】使得 yi = li 。
from sklearn.metrics import confusion_matrix, accuracy_score, roc_auc_score, roc_curve
pltt = plot_ROC(y_train, clf.predict_proba(X_train)[:,1], y_test, clf.predict_proba(X_test)[:,1])
考虑到 ROC 曲线,有几个重要的概念:
(ROC 曲线下面积(AUC),是分类器质量的重要度量。对于一个随机的猜测,我们有 AUC=∫ x d x =1/2,所以我们排除了一个知情分类器的分数> 1/2。概率解释如下:随机正数比均匀抽取的随机负数排在前面(根据模型的概率)的概率。ROC AUC 是机器学习中常用的一种([3])。
(2)图上标记的点是 TP 和 FP 的比率,正如我们前面在混淆矩阵中看到的。
(3)如果 ROC 曲线位于线 y = x 之下,这意味着通过反演分类器的结果,我们可以得到一个信息性的分类器。拥有一个总是给出错误答案的算法和拥有一个好的算法一样好!下面是绘制 ROC 曲线的代码(摘自[2])。
def plot_ROC(y_train_true, y_train_prob, y_test_true, y_test_prob):
'''
a funciton to plot the ROC curve for train labels and test labels.
Use the best threshold found in train set to classify items in test set.
'''
fpr_train, tpr_train, thresholds_train = roc_curve(y_train_true, y_train_prob, pos_label =True)
sum_sensitivity_specificity_train = tpr_train + (1-fpr_train)
best_threshold_id_train = np.argmax(sum_sensitivity_specificity_train)
best_threshold = thresholds_train[best_threshold_id_train]
best_fpr_train = fpr_train[best_threshold_id_train]
best_tpr_train = tpr_train[best_threshold_id_train]
y_train = y_train_prob > best_threshold cm_train = confusion_matrix(y_train_true, y_train)
acc_train = accuracy_score(y_train_true, y_train)
auc_train = roc_auc_score(y_train_true, y_train) fig = plt.figure(figsize=(10,5))
ax = fig.add_subplot(121)
curve1 = ax.plot(fpr_train, tpr_train)
curve2 = ax.plot([0, 1], [0, 1], color='navy', linestyle='--')
dot = ax.plot(best_fpr_train, best_tpr_train, marker='o', color='black')
ax.text(best_fpr_train, best_tpr_train, s = '(%.3f,%.3f)' %(best_fpr_train, best_tpr_train))
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve (Train), AUC = %.4f'%auc_train) fpr_test, tpr_test, thresholds_test = roc_curve(y_test_true, y_test_prob, pos_label =True) y_test = y_test_prob > best_threshold cm_test = confusion_matrix(y_test_true, y_test)
acc_test = accuracy_score(y_test_true, y_test)
auc_test = roc_auc_score(y_test_true, y_test) tpr_score = float(cm_test[1][1])/(cm_test[1][1] + cm_test[1][0])
fpr_score = float(cm_test[0][1])/(cm_test[0][0]+ cm_test[0][1]) ax2 = fig.add_subplot(122)
curve1 = ax2.plot(fpr_test, tpr_test)
curve2 = ax2.plot([0, 1], [0, 1], color='navy', linestyle='--')
dot = ax2.plot(fpr_score, tpr_score, marker='o', color='black')
ax2.text(fpr_score, tpr_score, s = '(%.3f,%.3f)' %(fpr_score, tpr_score))
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC curve (Test), AUC = %.4f'%auc_test)
plt.savefig('ROC', dpi = 500)
plt.show() return best_threshold
科恩的 κ 得分
Cohen 的 κ 分数给出了两个分类器对相同数据的一致性。定义为κ= 1(1-po)/(1-PE),其中 po 为观察到的符合概率, pe 为符合的随机概率。
让我们看一个例子。我们需要再使用一个分类器。
from sklearn import svmclf2 = svm.SVC()
clf2.fit(X_train, y_train)print(">> Score of the classifier on the train set is: ", round(clf2.score(X_test, y_test),2))>> Score of the classifier on the train set is: 0.74
我们计算列车组上的 κ 。
y = clf.predict(X_test)
y2 = clf2.predict(X_test)
n = len(y)p_o = sum(y==y2)/n # observed agreementp_e = sum(y)*sum(y2)/(n**2)+sum(1-y)*sum(1-y2)/(n**2) # random agreement: both 1 or both 0kappa = 1-(1-p_o)/(1-p_e)print(">> Cohen's Kappa score is: ", round(kappa,2))>> Cohen's Kappa score is: 0.4
这表明两个分类器之间存在某种一致性。 κ =0 表示不一致,而 κ < 0 也可以发生在两个分类器不一致的时候。
结论
我们讨论了对您的模型进行评分并将其与其他模型进行比较的几种基本策略。在应用机器学习算法和比较它们的性能时,记住这些概念很重要。
参考文献
[1]https://sci kit-learn . org/stable/modules/cross _ validation . html
[2]此处提供评估 ROC 曲线的函数:https://github.com/bc123456/ROC
[3]https://en . Wikipedia . org/wiki/Receiver _ operating _ character istic
https://en.wikipedia.org/wiki/Cohen%27s_kappa
价值投资仪表盘,配有 Python Beautiful Soup 和 Dash Python
价值投资的 Web 抓取与快速 Dash 可视化概述
Creating Python Value Investing Dashboard for data extractions
问题陈述
所以我通常在 SGX 或雅虎财经等交易网站上搜索股票,并将相关数据一个一个复制粘贴到我的电子表格中
“应该可以快速访问最相关的股票信息,以便我做出买入/卖出决定”
我仍然记得我的朋友如何吹嘘他从 SGX(新加坡证券交易所)复制粘贴的不同股票比率的辛苦工作的工作表。出于纯粹的决心,他一个接一个地复制数据,通过数百次查看和点击来检索股票信息,并将其转储到 excelsheet,在那里他手动保存所有公式。
整个过程看起来很滑稽,因为有很多手动滚动和点击来提取看起来很大的数字,以做出买/卖决定。这个问题启发我构建自己的工具来自动提取和快速处理相关的财务比率。
免责声明:本免责声明告知读者,文中表达的观点、想法和意见仅属于作者,不一定属于作者的雇主、组织、委员会或其他团体或个人。参考文献是从列表中挑选的,与其他作品的任何相似之处纯属巧合
这篇文章纯粹是作者的个人项目,绝无任何其他不可告人的目的。
解决方案:Web 抓取和仪表板可视化
在这个项目中,我将向您展示一个仪表板,您可以使用它快速获得重要的财务反馈。用户只需输入股票代码(如谷歌或 MSFT),应用程序将处理所有必要的关键比率和未来价格的计算。从 MarketWatch 检索到信息后,应用程序会将数字处理成预定义的值子集。最终结果将显示用户是否应该根据用户定义的边际价值和市场价格来购买/出售某些股票
该应用程序旨在消除用户访问股票市场网站的需求,如 SGX,雅虎/谷歌金融,他们可以使用我们的应用程序作为所有关键股票信息,基本分析和警告信号的一站式用户学习。
下面是应用程序演示,请注意屏幕将如何根据用户输入更新股票代码:
Value Investing Application Dashboard. This will help you screen and extract relevant financial ratio quickly (from Google to GameStop Stocks)
更新:6 月 27 日
我已经清理并部署了应用程序。请在这里尝试一下!
[## 破折号
编辑描述
value-investing.herokuapp.com](https://value-investing.herokuapp.com)
用途和 Github 代码
本概念证明(POC)是作为我目前管理的投资方项目的一部分而创建的。毕业后不久,肖恩·西的书《和沃伦·巴菲特一起去钓鱼》启发了我投资的想法。这本书启发我创造了自己的价值投资工具。这个应用程序的目标是帮助您快速检索和显示关于某个公司股票的正确的财务信息。
在 POC 中,我使用 Beautiful Soup 作为 Web 抓取工具,使用 Pandas data-reader API 获取金融股票价格,最后使用 Python 和 Flask/Dask 作为 Web 应用程序框架。Github 代码位于下面。
价值投资仪表板。通过在 GitHub 上创建帐户,为 VincentTatan/ValueInvesting 的发展做出贡献。
github.com](https://github.com/VincentTatan/ValueInvesting)
随时克隆回购,有空随时贡献。
项目范围
对于这一应用,我想强调 5 个过程:
Workflows on the Python Stocks Dashboard
让我们试着一个一个地分解它
股票输入刮削
在这个列表中,我们将提取股票列表及其代码,例如:谷歌(Google)或微软(MSFT)。我们将从 3 个来源提取这些信息:
从维基百科获取 SP500 股票信息
由 S & P 道琼斯指数维护的 S & P 500 股票市场指数,由 500 大盘股公司发行的 505 普通股组成,并在美国证券交易所交易(包括构成道琼斯工业平均指数的 30 家公司),按市值计算覆盖了美国股票市场的 80%左右。—维基百科
为了提取这些信息,我们将使用股票指数的链接。
[## 标准普尔 500 公司列表-维基百科
由 S&P 道琼斯指数维护的标准普尔 500 股票市场指数由 500 家公司发行的 505 种普通股组成
en.wikipedia.org](https://en.wikipedia.org/wiki/List_of_S%26P_500_companies)
SP500 Stocks Table from Wikipedia
可以用美汤 4 之类的网页抓取库提取这个表。请随意参考这里的文章。
[## 美丽的汤 4 蟒蛇
概述本文是对 Python 中 BeautifulSoup 4 的介绍。如果你想知道更多,我推荐你…
www.pythonforbeginners.com](https://www.pythonforbeginners.com/beautifulsoup/beautifulsoup-4-python)
首先,我们将创建到美丽的汤传递 URL 链接。这将提取一些值作为汤
import requestsresp = requests.get('http://en.wikipedia.org/wiki/List_of_S%26P_500_companies')
soup = BeautifulSoup(resp.text, 'lxml')
这个 soup 对象将保存 HTML 文本,您可以通过运行以下命令提取这些文本。
for row in table.findAll('tr')[1:]:
ticker = row.findAll('td')[0].text
security = row.findAll('td')[1].text
gics_industry = row.findAll('td')[3].text
gics_sub_industry = row.findAll('td')[4].text
tickers.append(ticker.lower().replace(r"\n", " "))
securities.append(security)
gics_industries.append(gics_industry.lower())
gics_sub_industries.append(gics_sub_industry.lower())
该命令将查找表,然后迭代每一行以检索每一列的数据。提取出来的内容将被放入一个列表中,这个列表稍后将被转储到一个键和值对的字典列表中。
# Create a list of dict based on tickers and labels
dictlist = []
for index, row in stocks_info_df.iterrows():
dictlist.append({'value':row['tickers'], 'label':row['labels']})
return dictlist
获取罗素股票信息
获取罗素股票信息甚至更简单,因为数据是公开的。请随意参考现有的 Russel 股票库。我们可以使用 pandas readcsv 方法来读取它。
dfrussel=pd.read_csv('C:/Users/vintatan/Desktop/Investment/RussellandData.csv',index_col='Symbol')
添加自己的股票信息列表
对于 SP200 或 Russell 列表中不存在的任何报价器,我们可以手动将我们的股票价值和标签传递到字典列表中。
# self append
def save_self_stocks_info():
print("Adding own list of stocks info")
dictlist = []
dictlist.append({'value':'sq', 'label':'SQ Square SA'})
dictlist.append({'value':'kbsty', 'label':'Kobe steel'})
dictlist.append({'value':'NESN', 'label':'Nestle'})
dictlist.append({'value':'BN', 'label':'Danone'})
结论
从这些提取 3 个不同来源的方法中,你可能意识到我正在传递一个字典对象的列表。这是因为破折号组合框输入需要格式化。请参考此处的 Dash 可视化工具
dcc.Dropdown(
id='my-dropdown',
options=save_sp500_stocks_info()+save_self_stocks_info(),
value='coke'
),
Stock Ticker Dash Combo Box Inputs
雅虎股票价格与熊猫数据阅读器刮
我们将使用熊猫-数据阅读器生成基于雅虎的股票价格。在这里,我们向 web 传递了 4 个参数。DataReader
自动收报机,在这种情况下,它会把 MSFT,谷歌等
数据来源是雅虎
开始时间,从 2013 年 1 月 1 日开始。
结束时间,也就是现在。
一旦我们生成了 stockpricedf,我们就返回一个带有关键字“data”的字典,并返回 x 轴上的日期和 y 轴上的收盘价。
stockpricedf = web.DataReader(
selected_dropdown_value.strip(), data_source='yahoo',
start=dt(2013, 1, 1), end=dt.now())
This is the Stocks Price DataFrame Retrieved from Web.DataReader
这将转化为你在这里看到的价格图表
return {
'data': [{
'x': stockpricedf.index,
'y': stockpricedf.Close
}]
}
Price Chart over 5 years
资产负债表和损益表摘录与美丽的汤
在这个子主题中,我们将尝试提取重要的比率,并将其显示为 Dash 表。以下是我们感兴趣的比率:
每股收益是公司利润分配给每股普通股的部分
ROE(股本回报率)是对财务绩效的一种衡量,计算方法是将净收入除以股东权益
ROA(资产回报率)是一个公司相对于其总资产盈利程度的指标
长期债务将包括公司债券发行或长期租赁,它们已经在公司的资产负债表上资本化
总收入象征着公司的收入
债转股用于评估公司的财务杠杆
利息保障率用于确定公司支付未偿债务利息支出的难易程度
这些定义来自 Investopedia。请在下面找到更多详细信息
股市基础想知道股市到底是怎么运作的?这本指南将教你一些基本知识。最佳经纪人…
www.investopedia.com](https://www.investopedia.com/)
我们将使用市场观察资产负债表和损益表链接,并将它们分配给变量。注意这里的股票代号指的是公司的股票代号。因此,苹果损益表的链接是https://www.marketwatch.com/investing/stock/AAPL/financials,苹果资产负债表的链接是https://www.marketwatch.com/investing/stock/AAPL/financials/资产负债表
urlfinancials = 'https://www.marketwatch.com/investing/stock/'+ticker+'/financials'
urlbalancesheet = 'https://www.marketwatch.com/investing/stock/'+ticker+'/financials/balance-sheet'text_soup_financials = BeautifulSoup(requests.get(urlfinancials).text,"lxml")
text_soup_balancesheet = BeautifulSoup(requests.get(urlbalancesheet).text,"lxml")
类似于提取公司代码,我们还使用 Beautiful Soup 从财务和资产负债表 url 中识别比率。我们将通过使用标签文本作为指示符遍历所有的同级属性来提取它们。
# Income Statement
for title in titlesfinancials:
if 'EPS (Basic)' in title.text:
epslist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
if 'Net Income' in title.text:
netincomelist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
if 'Interest Expense' in title.text:
interestexpenselist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
if 'EBITDA' in title.text:
ebitdalist.append ([td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
# Balance sheet
titlesbalancesheet = text_soup_balancesheet.findAll('td', {'class': 'rowTitle'})
equitylist=[]
for title in titlesbalancesheet:
if 'Total Shareholders\' Equity' in title.text:
equitylist.append( [td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
if 'Long-Term Debt' in title.text:
longtermdebtlist.append( [td.text for td in title.findNextSiblings(attrs={'class': 'valueCell'}) if td.text])
我们将提取的值填充到单独的数据框中。
df= pd.DataFrame({'eps': eps,'epsgrowth': epsgrowth,'netincome': netincome,'shareholderequity': shareholderequity,'roa':
roa,'longtermdebt': longtermdebt,'interestexpense': interestexpense,'ebitda': ebitda},index=[2013,2014,2015,2016,2017])
Result of the extractions
该数据帧将被转储到 dash 表对象中,如下所示
Critical Variables and Ratios Table
基于价值投资逻辑的警示信号列表
然后,我们将创建 eligibilitycheck.py 来遍历这些规则,并根据提取的比率识别一些可能的风险。
给定公司列表,找出投资的可行性
进入市场至少 10 年
有跟踪记录(每年 EPS)
有效率(ROE > 15%) —净收入/股东权益
确定操纵(ROA > 7%) —净收入/总资产
有小额长期债务(长期债务< 5*总收入)
低负债权益比
支付利息的能力:(利息保障比率> 3) — EBIT /利息支出
使用上面生成的数据帧,我们将检索一个警告列表
Warning Flags
基于股票每股收益边际价格的决策机
然后,我们将通过从用户定义的参数中推导出用户是否应该从预期未来值和边际值中购买来创建我们的最后一个步骤。以下是在 futurepricing.py 中实施的步骤
根据给定的价值投资方法,每家公司根据回报率做出决策
找出每股收益的年复合增长率
估计 10 年后的每股收益
估计 10 年后的股价(股价每股收益*平均每股收益)
根据回报率确定今天的目标价格(贴现率 15%/20%)
增加安全边际(安全网 15%)
如果市场价格低于边际价格,则买入
如果市场价格高于边际价格,则卖出
从这里,我们将从 Sean Seah 的书的逻辑中生成以下参数。
在此功能中,我们将允许用户输入诸如折扣率和边际率。贴现率表示 5 年期间的预测通货膨胀率,差额计算率是误差容限。在计算错误的情况下,你增加了额外的安全网。保证金计算率越高,你越厌恶风险,反之亦然。
Discount and Margin Calculation Rate at 15% for both
dfprice['peratio'] = findMinimumEPS(stockpricedf,financialreportingdf)
dfprice['FV'] = dfprice['futureeps']*dfprice['peratio']
dfprice['PV'] = abs(np.pv(discountrate,years,0,fv=dfprice['FV']))
dfprice['marginprice'] = dfprice['PV']*(1-marginrate)
dfprice['lastshareprice']=stockpricedf.Close.tail(1).values[0]
dfprice['decision'] = np.where((dfprice['lastshareprice']<dfprice['marginprice']),'BUY','SELL')
这将生成包含以下数据和决策(买入/卖出)的数据框架
Future Price and Decision Making Calculation
在这种情况下,基于每股收益增长和市盈率,你可以找到未来价格和当前价格的估值。加上折扣率和利润率,你会得到边际价格。由于保证金价格低于上一次股价,我们可以假设股票目前被高估,即使给定容许误差率。因此做出了卖出的决定。相反的还为购买的决定效力
这是一个非常简单的逻辑,但却是你购买股票的有力杠杆。当然,需要注意的是,在购买股票之前,你应该对定性分析进行尽职调查。
结果
开发完这个工具后,我觉得有必要测试一下。因此,在 2017 年,我决定利用这个工具的筛选来购买一些股票。
购买斯凯奇
Skechers View from Value Investing Dashboard
正如您在此处看到的,该应用程序将 Skechers 标记为异常高的边缘化价格。这意味着给定 10%的贴现率假设(来自经济不稳定或通货膨胀)和 50%的边际利率假设(来自潜在误差程度),我们仍然认为边际股价非常高——我们的估价。
对每股收益增长的进一步了解显示了斯凯奇从 2012 年到 2016 年的快速增长。然而,与此同时,如果你查看长期债务比率,斯凯奇的债务已经减少或稳定。总的来说,增加收入、高增长和低长期债务是我购买斯凯奇的最大原因之一。在一年半的时间里,我的股票价格上涨了 34.55%
购买高通
2017 年,我收到了高通与苹果公司发生纠纷的消息。这使得股票下跌到 44。因此,我尝试使用这个工具来看看我是否能快速提取信息并进行定量分析。快速看了一眼后,我意识到,考虑到市盈率和年增长率,高通给了我很高的未来价值 115 美元。即使我把 50%作为利润率(我是一个非常厌恶风险的人),我可以看到边际价格仍然远远高于目前的股价。由于除了一年的负增长,没有太多的预警信号和长期债务的增加,我买了高通。在一年半的时间里,我的股票价格上涨了 62.87%。
购买 Gamestop
Gamestop 是我用价值投资仪表板做的最新投资。这被认为是一种烟头投资,因为这是一种没有投资者想要的增长下降的股票,因此,烟头(明白吗?!哈哈)。在警告信号中,出现了三个警告:负增长,长期债务高,净资产收益率低。然而,如果你看一看底部的决定:应用程序将它标注为购买。原因是尽管股票随着负增长而下跌,但市场对股票的估价太低:人们太害怕投资 GameStop。生意下降的速度低于市场情绪下降的速度。正如你所看到的,即使当我把利润率设为 50%时,我仍然看到利润价格(13 美元)高于股价(8 美元)。出于这个原因,我买了 Gamestop,希望投资者能意识到这一差距,同时也希望收购。到现在为止,我亏了 7.58%。
持有 18%的投资组合回报
使用这个应用程序,我首先筛选、购买和持有股票。目前,我成功购买的公司包括:DC 吉宝房地产投资信托公司、CSE 全球有限公司、高通和斯凯奇。一些经过筛选的股票,如斯凯奇和高通是迄今为止表现最好的股票。
Results: Stocks Portfolio Gain by 18.53% since 2017
正如你所看到的,我目前管理的工作投资组合在持有一年半后产生了 18%的最新回报率。如果包括股息,那么回报率估计为 22%。虽然这是一年后的巨大回报,但这仍然不足以证明这款应用的有用性。请随意尝试,并在下面发表评论。
此外,我想进一步强调重要的警告:做你的尽职调查。
你仍然应该通过询问以下定性评估来评估你的股票:
业务优势(产品差异化、品牌、低价生产商、高转换成本、法律准入壁垒)
有勇无谋的管理能力(即使傻瓜也会跑)
避免价格竞争的业务。了解企业如何创收。
最后,我希望这个应用程序或者至少是我投资旅程中的一小段能激发你的创新。请随意查阅这些代码,以便更好地理解我是如何处理这些数字来得出买入/卖出行为的。然后,如果您想进一步改进,请随意发表意见。
一切都是免费的!!请做出贡献,使其成为最好的开源价值投资工具。
结论和未来工作
这个项目给了我解决一个实际相关问题的机会,我的许多金融朋友似乎都面临着这个问题。我们可以添加许多功能来改善用户体验,但目前,该应用程序已经成功地处理了前面提到的核心问题,即提取相关的财务比率和信息以进行初步的股票筛选。
从这个项目中,我还学到了许多基本的金融理论,我可以用这些理论来评估股票。我不是金融专家,我打赌你可能比我更清楚。因此,请随意改进您认为合适的解决方案。如果你想打个招呼或者进行一次轻松的讨论,我的联系方式如下:)
感谢
我想感谢我的会计和金融同行朋友们,是他们启发我开发了这个工具。我真的很喜欢从他们那里学到一堆金融术语,并用它们来解决他们遇到的现实生活中的问题。
最后…
咻…就是这样,关于我的想法,我把它写成了文字。我真的希望这对你们来说是一个伟大的阅读。因此,我希望我的想法可以成为你发展和创新的灵感来源。
请通过我的 LinkedIn 联系我,并订阅我的 Youtube 频道
请在下面留言,寻求建议和反馈。
快乐编码:)
温哥华的数据科学家市场
在温哥华做一名数据科学家需要什么?
Credit: David G Gordon (2015)
我最近读了哈尼夫·萨马德的一篇文章,他在文章中颠倒了他的招聘问题。他想知道新加坡的数据科学家在被聘用到目前的职位之前做了什么,而不是寻找公司在招聘信息中想要的内容?作为一个希望进入这一领域的人,我有兴趣回到我居住的城市温哥华的公司今天正在寻找他们的数据科学家的基本情况。
我有两个原因:1)我将很快在温哥华寻找数据科学家的职位(自私的原因);2)我目前是 UBC 数据科学硕士项目(利他主义原因)的助教。因此,我想看看哪些职位最符合我目前的知识和技能,以及基于平均水平的数据科学家工作,我目前的差距是什么?而且,我想帮助这些学生准备他们的项目,为他们毕业时找到一份好工作做好准备。
为此,我求助于 LinkedIn。我想查看温哥华的所有职位,而不是单独查看每个职位或其中的一个样本。所以,我转向了 LinkedIn 的网页抓取。
网页抓取 LinkedIn
正如 Hanif 提到的,LinkedIn 抓取网页的合法性目前还没有得到证实(尽管这可能只是改变了!).招聘启事都是公开的(毕竟他们正在试图雇佣某人),但是在他们的网站上使用抓取程序会让你违反他们的服务条款。如果您试图修改或复制此代码,请谨慎操作。为此,我同时使用了硒和 BeautifulSoup。完整代码见 Github 库。
1。编制所有相关公告的列表
截至发稿时,有 133 个帖子符合我的标准。LinkedIn 实际上会根据浏览器显示不同的网页设置。Chrome 有一个无限滚动的按钮,可以显示更多帖子。加载页面后,我设置它多次点击那个按钮,直到它不出现。然后,所有的链接都在边上
2。刮掉每张帖子
这一部分包括检查一个示例工作发布的 html,以获得正确的 HTML 标签。职位存储在 h1 下,公司存储在 class _ nametop card _ _ org-name-link下,大部分信息存储在 class _ name“description下。我将这些都存储在一个字典中,并在访问下一页之前将其添加到一个列表中。
3。一起清理和编译数据
这是一个痛苦的部分,需要大量的试验和错误。最后,我通过搜索下一个文本元素是列表开头的字符串,让它工作起来,这在招聘信息中很常见。大多数都有 1-3 个部分,我将其归类为“需求”、“资产”和“责任”。需求和资产之间的分离对于填补您需要的空白以及看到什么可以让您与众不同是很重要的。
然后,我在每个职位描述部分搜索关键词。我基于我以前的知识会很重要,或者通过浏览一些帖子(例如,我最初不打算包括 C++,但它出现在亚马逊的一份工作的摘录中,所以我想知道这有多普遍)。我还必须对一些关键词进行创新,以获得正确的用法(例如,“MS”通常被用作科学硕士的简写,但也是许多复数词的结尾,如“programs”、“aims”和“teams”)。).
Example of Amazon job posting with two sections (‘requirements’ and ‘assets’).
现在数据已经清理完毕,我们可以看看我们发现了什么。
发现 1:研究生教育很普遍
在近 50 个帖子中出现了某种形式的大学教育,其中 33 个提到了研究生教育的要求(硕士或博士)。这些教育要求中的大部分都列在“要求”部分,专业或专业通常作为资产包括在内。
这些数字确实显示了这种教育在数据科学这样一个新领域的负面影响。大学和学院中的数据科学学位课程开始越来越多,显然有大量涵盖类似内容的训练营和在线课程。许多工作甚至没有将学士学位列为要求,这可能表明他们对你在这个特定领域的知识更感兴趣,而不需要学位来支持。
发现 2: SQL 至高无上
SQL 是所有招聘信息中最常被提及的语言(64;需求和资产一起)。Python 紧随其后(54),R 远远落后(19)。其他编程语言也出现了,但可能是在需要高性能 C++代码的更特殊的位置。
Jim Halpert obviously saw the dominance of SQL coming.
除了一些主要的编程语言,一些软件和服务也出现在很多帖子中。Spark 位居榜首,Tableau 紧随其后,两者都出现了两次以上。
发现 3:利基工作的利基知识
数据科学家训练营和课程强调的一些事情只出现在少数帖子中。神经网络(包括 CNN 和 RNN)只在 4 篇文章中明确列出。自然语言处理(NLP)只在 9 中列出。如果这些是你真正想进入的领域,这些专业的数据科学家职位显然需要它们,但似乎大多数职位招聘的是更“通才”的数据科学家职位。(有关这方面的更多信息,请查看我喜欢的关于数据科学中专家与通才辩论主题的播客片段。
Definitions: RNN: NLP: Natural language processing; Recurrent neural network; CNN: Convolutional neural network.
虽然这并不是贬低这些方法的有用性,也不是说它们可能会在面试中出现,但这并不是公司在发布大部分帖子时的首选。
发现 4:不仅仅是技术
知识就是力量。数据科学家的工作也不例外。虽然你可能需要进行分析,但很多工作也希望你了解分析背后的理论,以确保你在适当的时候应用了正确的方法和技术。
整体
我很有兴趣看看数据科学工作(在温哥华,BC)的总体情况。这些发现可能并不太令人惊讶,但它确实展示了整体情况,以及你可能需要填补知识空白的地方,以便为就业市场做好准备。
我错过了什么你感兴趣的吗?下面评论,给我发消息或者随意自己探索这里。
注意事项
- 代码可以在另一个城市复制,或者在这里深入研究。
使用套索的可变选择
Photo by Priscilla Du Preez on Unsplash
这是套索;它被用来挑选和捕捉动物。作为一个非英语母语的人,我第一次接触这个词是在监督学习中。在本 Lasso 数据科学教程中,我们将通过逐步介绍如何将这种有用的统计方法应用于 R 中的分类问题,以及 Lasso 如何“类似地”用于挑选和选择与当前分类问题相关的输入变量,来讨论 LASSO 逻辑回归的优势。
数据分析师和数据科学家针对不同类型的分析问题使用不同的回归方法。从最简单的到最复杂的。人们谈论最多的方法之一是套索。Lasso 经常被描述为最有用的线性回归工具之一,我们即将找到原因。
Lasso 其实是“最小绝对收缩与选择算子”的缩写,基本概括了 LASSO 回归的工作原理。Lasso 使用收缩参数“数据收缩到某个中心点”1进行回归分析,并通过惩罚强制“不太重要”变量的系数变为零来执行变量选择。
现在,为了更好地了解这个强大的工具,我们将把这个例子应用到一个现实世界的问题中。
我们从 Kaggle.com[2获得了一些乳腺癌诊断病例的数据。这将用于整个演示过程。该数据集包含乳腺肿块的细针抽吸(FNA)的数字化图像中存在的细胞核的特征。我们正在解决的问题是确定乳房肿块的物理特征,这些特征显著地告诉我们它是良性的还是恶性的。
准备数据
我们将数据分为训练集和测试集。
训练模型
在训练训练集之后,我们使用交叉验证来确定最佳的 lambda。
预测
我们预测测试集的响应变量,然后,查看混淆矩阵。
检查性能
我们比较了响应集的实际值和预测值。
为了比较,我们也将使用普通的最小二乘法来解决相同的问题,然后比较它们的结果。
训练模型
预测
检查性能
现在,比较两种方法的准确性,Lasso 得到 166/171 的正确预测,给出 97.01%的准确性,而普通最小二乘法得到 162/171 的正确预测,给出 94.74%。然而,由于良性到恶性病例的分布,我们期待这种性能,让我们看看两个模型的 F1。这是为了同等重视假阳性(或非恶性病例被归类为恶性)和假阴性(或恶性病例被归类为非恶性)的数量,因为它们在我们的癌症问题中都很重要。我们希望尽可能地减少错误分类,因为分类决定了应该为患者提供什么样的具体护理或健康措施。看看 F1,Lasso 给出了 97.70%,而普通最小二乘法给出了 95.90%。同样,套索优于最小二乘法。
看起来这两者的性能几乎相同,我们可以使用其中任何一个来解决这个特定的问题。然而,如果我们深入研究模型的样子以及它们是如何形成的,我们可以很容易地看出这两种方法之间的显著差异。
检查 OLS 模型时,数据集中的所有输入变量都在模型中考虑。系数请参考下图。
现在,看看套索模型,我们会注意到模型中考虑的变量很少(只有 11/30 的自变量)。其余的被忽略或被模型视为在因变量的结果中不重要。然而,该模型的准确性在 97%左右,高于考虑所有自变量的模型。请参考该型号的下图。
我们发现,平均纹理、平均凹点、平均分形维数、半径的标准误差、分形维数的标准误差、最差半径、最差纹理、最差平滑度、最差凹度、最差凹点和最差对称性共同强烈地识别乳房块中的细胞核是良性还是恶性。
以上告诉我们的是,有时,有必要放弃使模型不稳定的其他变量。因为这些有噪声的/不相关的变量促使模型去适应噪声,也称为过适应。
让我们看看套索的显著特征,为什么它在这个特定的案例中比 OLS 更好。正如一开始提到的,LASSO 的一个重要特征是可变选择。Lasso 只选择模型中的重要变量。如果我们仔细观察现有的数据,我们会注意到有很多预测因素,一些独立变量实际上是相互关联的,或者我们可以将它们分组。这实际上已经给了我们一个暗示,可能有必要删除一些变量。
因此,获得预测更容易,因为我们在推断过程中需要准备的特征更少。不像在 OLS,我们必须输入数据集中的所有值才能获得响应值。
最后,让我们概括一下套索的重要特征。Lasso 是一种监督算法,其中该过程识别与响应变量密切相关的变量。这叫做变量选择。然后,Lasso 迫使变量的系数趋向于零。这就是现在收缩的过程。这是为了使模型对新数据集不那么敏感。由于选择的输入变量较少,这些过程有助于缓解人类认知的局限性。
如果你想了解更多关于 Lasso 回归的知识,我推荐你参加 Coursera [ 3 ]的课程,或者通读一下这篇[ 4 。
帖子到此为止。我们很想听听你对这些文章和其他相关数据的看法。SpectData 是一家精品数据科学咨询公司,擅长人工智能和自然语言处理。本文由我们的数据科学家 Marriane M。
原载于 2019 年 8 月 7 日http://www.spectdata.com。
变量类型和示例
通过具体的例子学习定量(连续和离散)和定性(顺序和名义)变量之间的区别
Photo by Mika Baumeister
介绍
如果你碰巧经常使用数据集,你可能知道数据集的每一行代表一个不同的实验单元(也称为观察),每一列代表一个不同的特征(称为变量)。
例如,如果您对您所在大学的 100 名学生的体重和身高进行研究,您很可能会有一个包含 100 行和 3 列的数据集:
- 一个用于学生的身份识别(可以匿名也可以不匿名),
- 一个代表重量,
- 一个是身高。
这三列代表了 100 名学生的三个特征。它们被称为变量。
在本文中,我们将关注变量,尤其是统计中存在的不同类型的变量。
不同类型的变量用于不同类型的统计分析
首先,有人可能想知道为什么我们对定义我们感兴趣的变量的类型感兴趣。
我们经常将变量分为不同类型的原因是因为不是所有的统计分析都可以在所有的变量类型上进行。例如,不可能计算变量“头发颜色”的平均值,因为你不能将棕色和金色头发相加。
另一方面,寻找连续变量的模式实际上没有任何意义,因为大多数时候不会有两个完全相同的值,所以不会有模式。即使在有一个模式的情况下,这个值的观测值也很少。举个例子,试着找出你们班学生身高的模式。如果你幸运的话,几个学生会有同样的尺寸。然而,大多数时候,每个学生都有不同的尺寸(特别是如果身高是以毫米为单位的话),因此没有模式。要查看每种类型变量的可能分析,请参阅文章“手动描述性统计”和“R 中的描述性统计”中的更多详细信息。
类似地,一些统计测试只能在特定类型的变量上进行。例如,皮尔逊相关性通常是根据定量变量计算的,而独立性卡方检验是根据定性变量进行的,而学生 t 检验或方差分析需要混合定量和定性变量。
特种宽银幕电影
在统计学中,变量分为 4 种不同的类型:
Image by author
数量的
一个数量变量是一个反映数量概念的变量,也就是说,如果它可以取的值是数字。因此,数量变量代表一种度量,并且是数字的。
定量变量分为两种:离散型和连续型。这种差异将在以下两节中解释。
分离的
定量离散变量是其取值为可数且有有限个可能性的变量。这些值通常(但不总是)是整数。以下是一些离散变量的例子:
- 每个家庭的孩子数量
- 一个班的学生人数
- 一个国家的公民人数
即使统计一个大国的公民人数需要很长时间,但在技术上还是可行的。而且,对于所有的例子,可能性的数量都是有限的。无论一个家庭有多少个孩子,都不会是 3.58 或 7.912,所以可能性的数量是有限的,因此是可数的。
连续的
另一方面,定量连续变量是其值不可数的变量,并且具有无限多种可能性。例如:
- 年龄
- 重量
- 高度
为了简单起见,我们通常用年、千克(或磅)和厘米(或英尺和英寸)分别代表年龄、体重和身高。然而,一个 28 岁的男人实际上可能是 28 岁 7 个月 16 天 3 小时 4 分 5 秒 31 毫秒 9 纳秒。
对于所有的测量,我们通常在一个标准的粒度级别停止,但是没有什么(除了我们的测量工具)阻止我们更深入,导致无限数量的潜在值。事实上,值可以采取无限多的可能性,使它不可数。
定性的
与定量变量相反,定性变量(也称为分类变量或 R 中的因子)是而非数值的变量,其值属于类别。
换句话说,定性变量是一个以模态、类别或甚至水平为其取值的变量,与测量每个个体的数量的定量变量相反。
定性变量分为两种:名义和序数。
名义上的
定性标称变量是一个定性变量,其中没有排序是可能的或隐含在级别中。
例如,变量性别是名义上的,因为在级别中没有顺序(无论你为性别考虑多少级别——只有两个是女性/男性,或者两个以上是女性/男性/其他,级别都是 un ordered)。眼睛颜色是名义变量的另一个例子,因为蓝色、棕色或绿色眼睛之间没有顺序。
名义变量可以有:
- 两个层次(例如,你吸烟吗?是/不是,还是你怀孕了?是/否),或者
- 大量的水平(你的大学专业是什么?每个专业在那种情况下都是一个级别)。
请注意,正好具有两个级别的定性变量也被称为二元或二元变量。
序数
另一方面,一个定性序数变量是一个具有隐含在等级中的顺序的定性变量。例如,如果道路交通事故的严重程度是按轻度、中度和致命事故的等级来衡量的,那么这个变量就是一个定性的顺序变量,因为在等级中有一个明确的顺序。
另一个很好的例子是健康,它可以取值为差、合理、好或优秀。同样,这些级别有明确的顺序,所以在这种情况下,健康是一个定性的序数变量。
变量转换
有两种主要的变量转换:
- 从连续变量到离散变量
- 从量变到质变
从连续到离散
假设我们对婴儿的年龄感兴趣。收集的数据是婴儿的年龄,因此是一个定量的连续变量。然而,我们可能只处理出生后的周数,从而将年龄转换为离散变量。年龄变量仍然是一个定量的连续变量,但我们正在研究的变量(即出生后的周数)是一个定量的离散变量。
从量变到质变
假设我们对身体质量指数(身体质量指数)感兴趣。为此,研究人员收集了个人身高和体重的数据,并计算出身体质量指数。身体质量指数是一个定量的连续变量,但研究人员可能希望将其转化为定性变量,方法是将低于某个阈值的人归类为体重不足,高于某个阈值的人归类为超重,其余的人归类为正常体重。原始身体质量指数是一个定量的连续变量,但身体质量指数的分类使转换后的变量成为一个定性(顺序)变量,在这种情况下,其水平是权重不足的< normal < overweighted.
Same goes for age when age is transformed to a qualitative ordinal variable with levels such as minors, adults and seniors. It is also often the case (especially in surveys) that the variable salary (quantitative continuous) is transformed into a qualitative ordinal variable with different range of salaries (e.g., < 1000€, 1000–2000€, > 2000€)。
关于误导性数据编码的附加说明
最后但并非最不重要的是,在数据集中,数字经常用于定性变量。例如,研究人员可能会将数字“1”分配给女性,将数字“2”分配给男性(或者将答案“否”分配为“0”,将答案“是”分配为“1”)。尽管进行了数字分类,性别变量仍然是一个定性变量,而不是看上去的离散变量。数字分类仅用于方便数据收集和数据管理。写数字“1”或“2”确实比写“女性”或“男性”更容易,因此不容易出现编码错误。
这同样适用于每个观察的识别。假设你收集了 100 名学生的信息。您可以使用他们的学生证在数据集中识别他们(以便您可以追溯他们)。大多数情况下,学生的 ID(或一般的 ID)被编码为数值。乍一看,它可能看起来像一个数量变量。然而,ID 显然不是一个数量变量,因为它实际上对应于学生的名字和姓氏的匿名版本。仔细想想,在 IDs 上计算平均值或中值是没有意义的,因为它确实代表了一种度量(而只是一种识别学生的简单方法)。
如果您面临这种设置,不要忘记在执行任何统计分析之前将变量转换成正确的类型。通常,在主要统计分析之前,一个基本的描述性分析(以及关于已测量变量的知识)足以检查所有变量类型是否正确。
感谢阅读。我希望这篇文章能帮助你理解不同类型的变量。如果您想了解 R 中不同数据类型的更多信息,请阅读文章“R中的数据类型”。
和往常一样,如果您有与本文主题相关的问题或建议,请将其添加为评论,以便其他读者可以从讨论中受益。
相关文章
原载于 2019 年 12 月 30 日https://statsandr.com。