在 Python 中探索网飞数据
网飞数据的探索性数据分析
Flixable 是一个视频流媒体服务搜索引擎,提供网飞电影和节目的完整列表。搜索引擎发布了网飞电影和电视节目数据集,其中包括 2019 年可用的电影和节目的完整列表。
在本帖中,我们将对网飞电影和电视节目数据集进行探索性数据分析。数据可以在这里找到。
我们开始吧!
首先,让我们导入 Pandas 并将数据读入数据框:
import pandas as pd
df = pd.read_csv("netflix_titles.csv")
接下来,让我们打印列的列表:
print(list(df.columns))
我们还可以看看数据中的行数:
print("Number of rows: ", len(df))
让我们打印前五行数据:
print(df.head())
我们可以看到有几个分类列。让我们定义一个将数据框、列名和限制作为输入的函数。当被调用时,它打印分类值的字典以及它们出现的频率:
def return_counter(data_frame, column_name, limit):
from collections import Counter print(dict(Counter(data_frame[column_name].values).most_common(limit)))
让我们将函数应用于“国家”列,并将结果限制为五个最常见的值:
return_counter(df, 'country', 5)
如我们所见,美国有 2,032 个标题,印度有 777 个,缺少 476 个国家值,英国有 348 个,日本有 176 个。
让我们将函数应用于“director”列,删除缺失的值:
df['director'].dropna(inplace = True)
return_counter(df, 'director', 5)
现在,让我们看看最常见的导演“劳尔·坎波斯”和“扬·苏特”的片名:
df_d1 = df[df['director'] =='Raúl Campos, Jan Suter']
print(set(df_d1['title']))
和国家:
print(set(df_d1['country']))
我们看到这些头衔来自哥伦比亚、智利、阿根廷和墨西哥。让我们为马库斯·雷波依做同样的事情:
df_d2 = df[df['director'] =='Marcus Raboy']
print(set(df_d2['title']))
现在我们来分析电影时长。首先,我们需要过滤数据集,只包括电影标题:
df = df[df['type'] =='Movie']
接下来,让我们打印一组电影时长:
print(set(df['duration']))
我们看到所有的值都以字符串的形式报告,持续时间以分钟为单位。让我们从字符串值中删除“min ”,并将结果转换为整数:
df['duration'] = df['duration'].map(lambda x: x.rstrip('min')).astype(int)
print(set(df['duration']))
接下来,从像“持续时间”这样的数字列中生成汇总统计数据会很有用。让我们定义一个采用数据框、分类列和数字列的函数。每个类别的数字列的平均值和标准偏差存储在数据框中,并且数据框根据平均值以降序排序。如果您想要快速查看特定类别对于特定数字列是否具有更高或更低的平均值和/或标准偏差值,这将非常有用。
def return_statistics(data_frame, categorical_column, numerical_column):
mean = []
std = []
field = []
for i in set(list(data_frame[categorical_column].values)):
new_data = data_frame[data_frame[categorical_column] == i]
field.append(i)
mean.append(new_data[numerical_column].mean())
std.append(new_data[numerical_column].std())
df = pd.DataFrame({'{}'.format(categorical_column): field, 'mean {}'.format(numerical_column): mean, 'std in {}'.format(numerical_column): std})
df.sort_values('mean {}'.format(numerical_column), inplace = True, ascending = False)
df.dropna(inplace = True)
return df
让我们用分类列‘listed _ in’和数字列‘duration’来调用我们的函数:
stats = return_statistics(df, 'listed_in', 'duration')
print(stats.head(15))
接下来,我们将使用箱线图来显示基于最小值、最大值、中值、第一个四分位数和第三个四分位数的数值分布。如果您对它们不熟悉,可以看看文章了解 Boxplots 。
与汇总统计函数类似,此函数采用数据框、分类列和数值列,并根据限制显示最常见类别的箱线图:
def get_boxplot_of_categories(data_frame, categorical_column, numerical_column, limit):
import seaborn as sns
from collections import Counter
keys = []
for i in dict(Counter(df[categorical_column].values).most_common(limit)):
keys.append(i)
print(keys)
df_new = df[df[categorical_column].isin(keys)]
sns.set()
sns.boxplot(x = df_new[categorical_column], y = df_new[numerical_column])
让我们为 5 个最常见的“列出”类别中的“持续时间”生成箱线图:
get_boxplot_of_categories(df, 'listed_in', 'duration', 5)
最后,让我们定义一个函数,它将一个数据框和一个数字列作为输入,并显示一个直方图:
def get_histogram(data_frame, numerical_column):
df_new = data_frame
df_new[numerical_column].hist(bins=100)
让我们用数据框调用函数,并从“持续时间”生成一个直方图:
get_histogram(df, 'duration')
我就讲到这里,但是请随意处理数据并自己编码。
概括地说,我回顾了几种分析网飞电影和电视节目数据集的方法。这包括定义生成汇总统计数据的函数,比如平均值、标准差和分类值的计数。我们还定义了用箱线图和直方图可视化数据的函数。我希望这篇文章有趣。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
理解神经网络的近似能力
里面的艾
探索神经网络有效性的基本概念。
一切开始的地方。
这一切都始于理解大脑实际上是如何工作的想法。早在 20 世纪 40 年代,麦卡洛克和皮茨就引入了神经元1,20 世纪 50 年代,弗兰克·罗森博尔特推出了第一台感知机2。自 20 世纪 40 年代以来,神经网络就伴随着我们,但是,由于缺乏实际的实施,该领域面临着起伏。最近涉及各种神经网络架构的深度学习技术实践的增长是因为两个主要进步,第一,(高性能 CPU 和 GPU),第二, 可用的数据量 。
Geoff Hinton 和他的两个研究生展示了如何使用深度学习将一个名为 ImageNet 的非常大的数据集,包含 10000 个类别和 1000 万张图像,并将分类错误减少 20%。这发生在 2012 年的 NIPS 会议上,正如 Terrence Sejnowski 所说,
传统上,在数据集(ImageNet)上,误差在一年内减少不到 1%。一年时间,绕过了 20 年的研究。这真的打开了闸门。——在《The Verge》的采访中。
这就是“深度学习——嗡嗡声”开始的时刻。人工智能就是从这一点发展起来的。
神经网络有多神奇?
人工神经网络由大量简单的相互连接的处理元件组成。这些元件并行操作,其功能由网络结构、连接强度以及在计算元件或节点处执行的处理决定。对深度学习兴趣的增长部分是由于传统编程技术在“硬”任务中的失败,如机器视觉、连续语音识别和机器学习。
神经网络在视觉、语音、信号处理和机器人方面的能力已经得到了显著的证明。神经网络解决的各种问题令人印象深刻。最近在诸如图像分类、对象检测、文本生成、图像字幕、语言翻译、GANs 等任务中有了突破。
由于神经网络的有效性和高性能处理器(GPU、TPU)的可用性,神经网络的热门研究领域正在快速发展,并且范围很广。AWS、Google Cloud 等云技术的最新进展。也有助于更好的研究。但是深度学习往往面临缩放、和现实世界问题。(关于这些问题的讨论超出了本文的范围)
函数逼近
函数逼近是通过简单函数的集合来描述复杂函数的行为。这些方法包括通过高斯*、级数展开的多项式逼近,以计算工作点附近函数的近似值,如*泰勒级数、等等。
神经网络是在统计上实现泛化的函数逼近机器。
功能😋
神经网络是通用逼近器
前馈神经网络提供了一个通用逼近框架,即通用逼近定理,
通用逼近定理在其最一般的版本之一中说,如果我们仅考虑连续激活函数 σ ,那么具有一个隐藏层的标准前馈神经网络能够将任何连续多元函数 f 逼近到任何给定的逼近阈值 ε ,当且仅当 σ 是非多项式。3
前馈网络提供了一个表示函数的通用系统,在这个意义上,给定一个函数,存在一个逼近该函数的前馈网络。这表明存在一个接近所考虑的函数的大网络,但它没有回答,到底有多大?
简而言之,具有单个层的前馈神经网络是代表任何函数的 sufficient,但是该层可能相当大,并且可能不能正确概括。
近似的例子
作为函数逼近的例子,我采用了众所周知的正弦、余弦函数和一个自定义函数。数据点的范围[-3,3]使得函数图看起来如下:
- 余弦函数
余弦图(来源:笔记本)
2.正弦函数
正弦图(来源:笔记本)
用建筑的神经网络进一步逼近这些功能,
图层:输入(1)-隐藏(100)-输出(1)
神经网络体系结构[in-hidden-out,1–100–1]
基于神经网络优化的近似函数的结果在函数图下面,
- 余弦
2.正弦
问题
上图显示,通过一组正确的参数,神经网络几乎符合原始函数。一切看起来都很完美,那么还会有什么地方出错呢?
过度拟合
是的,我们的神经网络过度拟合了!训练集上的误差被驱动到非常小的值,但是当新数据呈现给网络时,误差很大。网络已经记住了训练的例子,但是还没有学会推广到新的情况。这必须避免。我们可以看看另一个具有相同神经网络结构的自定义函数。
功能,
10(a )*sin(a)cos(s)
关于函数逼近,
接近
结论
这些是理解神经网络通用逼近能力的基础的一些尝试,这使得深度学习领域在广泛的任务上有效成为可能。最后,我们将上述内容总结如下:
- 根据数据训练神经网络近似于从输入到输出的未知的基本映射函数。
- 在训练神经网络时,过拟合等问题会阻碍新数据的结果(看不见)。
人们可以通过在笔记本上用代码进行实验来观察改变神经架构和参数对结果的影响,如上图所示。
参考
1麦卡洛克,W. S .和皮茨,W. 1943。神经活动中固有观念的逻辑演算。数学生物物理学通报5:115–133。
2罗森布拉特,1957 年。感知机——一种感知和识别自动机。康奈尔航空实验室报告 85-460-1。
3进一步了解神经网络的近似能力,Kai Fong Ernest Chong。
要签出的资源
- *【http://neuralnetworksanddeeplearning.com/chap4.html *
- https://towards data science . com/the-approximation-power-of-neural-networks-with-python-codes-ddfc 250 BDB 58
- https://machine learning mastery . com/neural-networks-are-function-approximators/
谢谢你!在 LinkedIn 和我联系,
* [## Pratik K. -作家-走向数据科学| LinkedIn
我是一名刚从泰国国立理工学院电子和通信工程专业毕业的学生
www.linkedin.com](https://www.linkedin.com/in/pratik-kumar04/)
查看我的投资组合网页了解更多关于我的详细信息在这里。*
探索印度媒体中关于新冠肺炎的新闻| NLP| Wordcloud |新冠肺炎文章 1
新冠肺炎文字分析
编者注: 走向数据科学 是一份以研究数据科学和机器学习为主的中型刊物。我们不是健康专家或流行病学家,本文的观点不应被解释为专业建议。想了解更多关于疫情冠状病毒的信息,可以点击 这里 。
马库斯·斯皮斯克在 Unsplash 上拍摄的照片
C 现在全球的流行词是冠状病毒、死亡、隔离和封锁。因此,在这篇博客中,我试图挖掘来自印度媒体的新闻文章,并使用词云可视化哪些词出现得最多。
对 wordcloud 的结果感兴趣吗?
滚动到底部!
关于我的新冠肺炎新闻文章数据集:
我用过的新闻文章都是用 NewsAPI 的 开发者计划刮出来的。因为,我几天前才决定这个用例,我的数据集的日期范围是2020 年 3 月 10 日到 4 月 10 日。因此,数据集将每月增长。此外,新闻文章的内容被限制在260 个字符以内,但是你知道他们说什么——如果读者对引言不感兴趣,他们可能不会读到第二段。所以我们只有很少但重要的信息。
**使用的新闻来源:**谷歌印度新闻、印度时报和印度教徒报
照片由 Doran Erickson 在 Unsplash 上拍摄
数据集预处理:
我使用传统的 NLP 清洗流程:
- 标记化、停用词删除、标点符号删除
- 词性标注和生成词条
我使用 lambda 函数来遍历这些行,并将最终数据集存储到 pickle 文件中以备后用。
这很大程度上源于我之前的一篇博客,所以我将跳过细节。
数据转换的一个例子:
**Actual Content:**The spectre of COVID-19 has made its appearance in one of Indias most storied tiger reserves. The death of a 10-year-old ailing male tiger, in the Pench Tiger Reserve (PTR) the countrys most munificent reserve that succumbed to a respiratory illness last Satu… [+3272 chars]**Cleaned and Normalized Content:**[[number, covid-19, case, continue, rise, 6, 33, new, case, report, 12-hour, span, take, tally, positive, case, 781], [witness, 19, fresh, case, 11, report, fro]]
Github 链接笔记本进行数据清理:
[## royn5618/Medium_Blog_Codes
permalink dissolve GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码,管理…
github.com](https://github.com/royn5618/Medium_Blog_Codes/blob/master/Covid-Blog-Codes/Cleaning-Covid-Dataset-NLP.ipynb)
生成词频& Wordcloud:
我使用了独一无二的 Wordcloud Python 库来创建这个 word-cloud。我自己生成了术语频率词典,并在下面一步一步地记录了这个过程:
第一步: 我创建了一个令牌列表,如下所示:
temp_list = [k **for** i **in** list(df[col]) **if** i **for** j **in** i **for** k **in** j]
在笔记本中,我还根据结果单词云中出现的不需要的单词做了一些清理。
步骤 2: 我将唯一的单词作为键存储到字典中,并将它们的频率分配到各自的值中。
# Use *set* to get the unique elements of the list
unique_words = set(terms_list)# Iterate through the terms and store count of the indexed words to
dict_terms_count = {}
**for** word **in** unique_words:
dict_terms_count[word] = terms_list.count(word)
**第三步:**现在,我从前面的字典中得到最大的词频,并根据最高的词频调整其他的词频。
max_tf = max(dict_term_count.values())
dict_tf_scaled = {}
**for** word, count **in** dict_term_count.items():
dict_tf_scaled[word] = count/max_tf
sorted_dict_term_count = dict(sorted(dict_tf_scaled.items(),
key=**lambda** kv: kv[1], reverse=**True**))
在这种情况下,“新冠肺炎”一词的出现频率最高,为 7536 次。看看下面的情节。很明显,Covid 和冠状病毒占据了新闻,因为刮擦集中在具有这两个关键词的文章上。
第四步:生成词云。我在评论中加入了一些关于在单词云中生成颜色的解释。我使用了许多图片进行试验,并选择了最适合的一个。我用过的那个在我的 GitHub 回购上。说真的,很好玩!下载随机图像,使用 ImageColorGenerator 生成本地化的彩色像素,并尝试匹配您的文字云。
# imports
from PIL import Image
import PIL.ImageOps
from wordcloud import ImageColorGenerator# Load the mask image
image_mask = np.array(Image.open(mask_image))# Generate the wc colours from the image pixels
# This method takes the average of a region of pixels and assigns
# that colour to the texts in that regionimage_colors = ImageColorGenerator(image_mask)# Generate the Wordcloud object using the mask. 'mask' is to
# generate the outline of the image you have chosen.
# For me it it rectangular - so no visible change
# Since I have passed custom frequencies, I have used
# 'generate_from_frequencies' methodstopwords = set(STOPWORDS)
wordcloud = WordCloud(width = 2000, height = 1200,
max_words = 500, normalize_plurals = True,
**mask=image_mask**, background_color =’black’,
font_step = 1, relative_scaling = 0.5,
collocations = False, include_numbers = False,
stopwords =stopwords)
.generate_from_frequencies(dict_term_freq)# Some matplotlib settings plt.figure(figsize = (80, 50), facecolor = None)
plt.style.use(‘dark_background’)
plt.imshow(wordcloud.recolor(color_func=image_colors))
plt.text(xpos, ypos, custom_text, fontsize=font_size)
plt.axis(“off”)
plt.show()
云这个词在这里:
意见和结论:
在所有的词语中,正面和战斗比较有意思。这是因为“战斗”通常被认为是消极情绪*,而“积极”正如其名称所示,是积极情绪*。然而,形势显然已经发生了逆转。“拼”是正面情绪,“正面”是负面情绪在 2020 年疫情新冠肺炎的语境中。这清楚地表明了单词袋& tf-idf 作为文本表示模型的缺点、情感分析中的挑战以及我们为什么需要基于上下文/顺序的模型。**
“说”的出现表明已经说了很多,众所周知,还有很多工作要做。这些话让我好奇,在下一次刮擦中,wordcloud 会有什么不同。我在云中找不到疫苗、解毒剂或治疗之类的词。
就像在 wordcloud 中一样,很自然地,许多负面情绪被表达了出来。这个数据集可能有助于发现与种群和社会经济因素的相互关系。但那是另一个博客讨论的问题!
关于新冠肺炎文章系列:
我将会写更多关于探索和操作这个数据集的博客,这个数据集将会越来越大。如果您有兴趣了解这个数据集是如何形成的,请跟我来!
Github 链接到此数据集上的所有笔记本:
** [## royn5618/Medium_Blog_Codes
此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…
github.com](https://github.com/royn5618/Medium_Blog_Codes/tree/master/Covid-Blog-Codes)**
感谢来访。我希望你喜欢阅读这篇博客。
用 Jupyter 笔记本探索正态分布
统计数字
使用 scipy 和 matplotlib 的正态分布初学者指南
卡洛斯·穆扎在 Unsplash 上的照片
**Table of Contents**[**Introduction**](#f050)1\. [Normal Distribution Probability Density Function](#053b)
2\. [Using random normal distribution values](#47c4)
3\. [A cumulative normal distribution function](#b23b)
4\. [Calculating the probability of normal distribution](#c5a1)
5\. [Interval between variables](#15d2)
6\. [Finding quantiles](#0adf)
7\. [Multivariate Normal Distribution](#cc27)
8\. [Standard normal distribution](#6f46)
9\. [Standardized normal variable](#dcf5)
10\. [Finding the standard normal value](#0921)[**Conclusion**](#72c4)
介绍
正态分布在自然科学和社会科学中常用来表示分布未知的实值随机变量。正态分布是一种连续的理论概率分布。在这篇文章中,我将使用 Jupyter 笔记本来探索正态分布。
让我们导入所有必需的库。
from scipy.stats import norm
import numpy as np
import matplotlib.pyplot as plt
正态分布概率密度函数
正态分布的概率密度函数(PDF)为:
PDF 描述的随机变量 𝑋 是一个正态变量,服从具有均值和方差的正态分布。
正态分布符号是:
曲线下的面积等于 1。
norm.pdf
值
norm.pdf
返回一个 PDF 值。以下是 𝑥 =1、 𝜇 =0、 𝜎 =1 时的 PDF 值。
norm.pdf(x=1.0, loc=0, scale=1)
如果你想看上图的代码,请看这个。
由于norm.pdf
返回一个 PDF 值,我们可以用这个函数来绘制正态分布函数。我们使用scipy
、numpy
和matplotlib
绘制正态分布的 PDF。我们使用的域为 4 < 𝑥 < 4,范围为 0<𝑓(𝑥)<0.45,默认值为 𝜇 =0 和 𝜎 =1。plot(x-values,y-values)
生成图表。
fig, ax = plt.subplots()
x= np.arange(-4,4,0.001)
ax.set_title('N(0,$1^2$)')
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.plot(x, norm.pdf(x))
ax.set_ylim(0,0.45)plt.show()
正常曲线是平滑的钟形。关于 𝑥 = 𝜇 对称,并且在 𝑥 = 𝜇 处具有最大点。
具有不同标准差的正态分布 PDF
让我们画出一个正态分布的概率分布函数,其中平均值有不同的标准差。
scipy.norm.pdf
有关键字,loc
和scale
。location (loc)关键字指定平均值,scale (scale)关键字指定标准差。
fig, ax = plt.subplots()
x = np.linspace(-10,10,100)
stdvs = [1.0, 2.0, 3.0, 4.0]for s in stdvs:
ax.plot(x, norm.pdf(x,scale=s), label='stdv=%.1f' % s)
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.set_title('Normal Distribution')
ax.legend(loc='best', frameon=True)
ax.set_ylim(0,0.45)
ax.grid(True)
不同均值的正态分布 PDF
让我们画出标准偏差为 1 的正态分布和不同均值的概率分布函数。
fig, ax = plt.subplots()
x = np.linspace(-10,10,100)
means = [0.0, 1.0, 2.0, 5.0]for mean in means:
ax.plot(x, norm.pdf(x,loc=mean), label='mean=%.1f' % mean)
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.set_title('Normal Distribution')
ax.legend(loc='best', frameon=True)
ax.set_ylim(0,0.45)
ax.grid(True)
分布的平均值决定了图形中心的位置。正如你在上面的图表中看到的,图表的形状并没有因为改变平均值而改变,而是水平平移了图表。
从线性回归到逻辑回归
towardsdatascience.com](/modeling-functions-78704936477a)
使用随机正态分布值
norm.rvs
根据标准差scale
、均值loc
和大小生成随机正态分布数。我们为生成的数字创建一个直方图,并添加 PDF。
fig, ax = plt.subplots()
xs = norm.rvs(scale=2,size=1000)
x = np.linspace(-10,10,100)
p = norm.pdf(x,scale=2)
v = np.var(xs)
m = np.mean(xs)ax = fig.add_subplot(111)
ax.hist(xs, bins=10, alpha=0.5, density=True)
ax.plot(x,p, 'r-', lw=2)
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.set_title(f'mean={m:.2f}, var={v:.2f}')
ax.grid(True)
累积正态分布函数
随机变量 X 的累积分布函数(在 X 处计算)是 X 取值小于或等于 X 的概率。由于正态分布是连续分布,因此曲线的阴影区域表示 X 小于或等于 X 的概率。
使用fill_between(x, y1, y2=0)
,它将填充两条曲线y1
和y2
之间的区域,默认值为 0。
fig, ax = plt.subplots()
# for distribution curve
x= np.arange(-4,4,0.001)
ax.plot(x, norm.pdf(x))
ax.set_title("Cumulative normal distribution")
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.grid(True)# for fill_between
px=np.arange(-4,1,0.01)
ax.set_ylim(0,0.5)
ax.fill_between(px,norm.pdf(px),alpha=0.5, color='g')
# for text
ax.text(-1,0.1,"cdf(x)", fontsize=20)
plt.show()
计算正态分布的概率
给定 3 的均值和 2 的标准差,我们可以求出 𝑃 ( 𝑋 < 2)的概率。
在norm.cdf
中,location (loc)关键字指定平均值,scale (scale)关键字指定标准差。
from scipy.stats import normlessthan2=norm.cdf(x=2, loc=3, scale=2)
print(lessthan2)
让我们画一张图表。
fig, ax = plt.subplots()# for distribution curve
x= np.arange(-4,10,0.001)
ax.plot(x, norm.pdf(x,loc=3,scale=2))
ax.set_title("N(3,$2^2$)")
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.grid(True)# for fill_between
px=np.arange(-4,2,0.01)
ax.set_ylim(0,0.25)
ax.fill_between(px,norm.pdf(px,loc=3,scale=2),alpha=0.5, color='g')# for text
ax.text(-0.5,0.02,round(lessthan2,2), fontsize=20)
plt.show()
变量之间的间隔
要找出某些变量之间的间隔概率,需要从另一个cdf
中减去cdf
。我们来找𝑃(0.5<𝑋<2)均值为 1,标准差为 2。
norm(1, 2).cdf(2) - norm(1,2).cdf(0.5)
这是图表。
fig, ax = plt.subplots()# for distribution curve
x= np.arange(-6,8,0.001)
ax.plot(x, norm.pdf(x,loc=1,scale=2))
ax.set_title("N(1,$2^2$)")
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.grid(True)px=np.arange(0.5,2,0.01)
ax.set_ylim(0,0.25)
ax.fill_between(px,norm.pdf(px,loc=1,scale=2),alpha=0.5, color='g')pro=norm(1, 2).cdf(2) - norm(1,2).cdf(0.5)
ax.text(0.2,0.02,round(pro,2), fontsize=20)
plt.show()
要找到 𝑃 ( 𝑋 > 4)的概率,我们可以使用sf
,它被称为生存函数,它返回1-cdf
。例如,norm.sf(x=4, loc=3, scale=2
返回当 𝜇 =4, 𝜎 =2 时,大于 𝑥 =4, 𝑃 ( 𝑋 > 4)的概率。
gr4sf=norm.sf(x=4, loc=3, scale=2)
gr4sf
让我们画一张图表。
fig, ax = plt.subplots()
x= np.arange(-4,10,0.001)
ax.plot(x, norm.pdf(x,loc=3,scale=2))
ax.set_title("N(3,$2^2$)")
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.grid(True)px=np.arange(4,10,0.01)
ax.set_ylim(0,0.25)
ax.fill_between(px,norm.pdf(px,loc=3,scale=2),alpha=0.5, color='g')ax.text(4.5,0.02,"sf(x) %.2f" %(gr4sf), fontsize=20)
plt.show()
上图同 1𝑃(𝑋t51】4)。
gr4=norm.cdf(x=4, loc=3, scale=2)
gr14=1-gr4fig, ax = plt.subplots()
x= np.arange(-4,10,0.001)
ax.plot(x, norm.pdf(x,loc=3,scale=2))
ax.set_title("N(3,$2^2$)")
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.grid(True)px=np.arange(4,10,0.01)
ax.set_ylim(0,0.25)
ax.fill_between(px,norm.pdf(px,loc=3,scale=2),alpha=0.5, color='g')
px1=np.arange(-4,4,0.01)
ax.fill_between(px1,norm.pdf(px1,loc=3,scale=2),alpha=0.5, color='r')
ax.text(4.5,0.02,round(gr14,2), fontsize=20)
ax.text(1,0.02,round(gr4,2), fontsize=20)
plt.show()
皮尔逊与 Jupyter 笔记本的积矩相关性
towardsdatascience.com](/a-measure-of-linear-relationship-5dd4a995ee7e)
寻找分位数
𝑘 在𝑃(𝑋≤𝑘)= 0.95
被称为分位数,在这种情况下,95%的分位数。
百分点函数
ppf
是cdf
的倒数,称为百分点函数。给定均值 1,标准差 3,我们可以用ppf
求出𝑃(𝑋<𝑎)= 0.506 的分位数a
。
norm.ppf(q=0.506, loc=1, scale=3)
让我们画一张图表。
fig, ax = plt.subplots()
x= np.arange(-10,10,0.001)
ax.plot(x, norm.pdf(x,loc=1,scale=3))
ax.set_title("N(1,$3^2$)")
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.grid(True)xpoint=norm.ppf(q=0.506, loc=1, scale=3)
px=np.arange(-10,xpoint,0.01)
ax.set_ylim(0,0.15)
ax.fill_between(px,norm.pdf(px,loc=1,scale=3),alpha=0.5, color='g')ax.text(.8,0.02,"x= %.2f" %xpoint, fontsize=20)
ax.text(-5,0.05,"P(X)=0.506", fontsize=20)
plt.show()
逆生存函数
同样的均值和标准差,我们可以利用逆生存函数isf
求出𝑃(𝑋>𝑏)中的分位数b
= 0.198。这与使用ppf
和𝑞=(10.198)是一样的。
norm.isf(q=0.198, loc=1, scale=3)
norm.ppf(q=(1-0.198), loc=1, scale=3)
平均值附近的区间
norm.interval
返回包含分布的 alpha 百分比的范围的端点。例如,如果平均值为 0,标准差为 1,则求 95%的概率,norm.interval
返回平均值周围的 x 值,在本例中, 𝜇 =0。
a,b = norm.interval(alpha=0.95, loc=0, scale=1)
print(a,b)
fig, ax = plt.subplots()
x= np.arange(-4,4,0.001)
ax.plot(x, norm.pdf(x))
ax.set_title("Interval")
ax.set_xlabel('x')
ax.set_ylabel('pdf(x)')
ax.grid(True)px=np.arange(a,b,0.01)
ax.set_ylim(0,0.5)
ax.fill_between(px,norm.pdf(px),alpha=0.5, color='g')ax.text(-0.5,0.1,"0.95", fontsize=20)
plt.show()
多元正态分布
多元正态分布通常用于描述任何一组相关的实值随机变量。
我们使用multivariate_normal
,它需要均值和协方差矩阵的数组。为了简单起见,我们使用一个对角矩阵,其中所有非对角元素为零。
from scipy.stats import multivariate_normalx,y = np.meshgrid(np.linspace(-10,10,100),np.linspace(-10,10,100))
pos = np.dstack((x,y))
mean = np.array([1, 2])
cov = np.array([[3,0],[0,15]])
rv = multivariate_normal(mean,cov)
z = rv.pdf(pos)fig = plt.figure()
ax = fig.add_subplot(111,aspect='equal')
ax.contourf(x,y,z)
ax.set_xlim(-10,10)
ax.set_ylim(-10,10)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('pdf')
我们可以使用 matplotlib 的[mpl_toolkits.mplot3d.Axes3D](https://matplotlib.org/api/_as_gen/mpl_toolkits.mplot3d.axes3d.Axes3D.html)
创建一个 3D 图形。我们也使用 Scipy 冷冻 RV 对象。
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
from mpl_toolkits.mplot3d import Axes3D# Create grid and multivariate normal
x = np.linspace(-10,10,500)
y = np.linspace(-10,10,500)
X, Y = np.meshgrid(x,y)
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y# Create a frozen RV object
mean = np.array([1, 2])
cov = np.array([[3,0],[0,15]])
rv = multivariate_normal(mean,cov)# Make a 3D plot
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, rv.pdf(pos),cmap='viridis',linewidth=0)
ax.set_xlabel('X axis')
ax.set_ylabel('Y axis')
ax.set_zlabel('Z axis')
plt.show()
标准正态分布
当 𝜇 =0,方差=1 时,称为标准正态分布。上述概率函数简化为:
所有的正态曲线都与标准正态分布相关。
标准化正态变量
为了将随机变量标准化为标准化正态变量𝑍∽𝑁(0,1)我们使用变换:
标准化值 Z 表示原始值低于或高于平均值多少个标准偏差。
寻找标准正常值
例如,当平均值为 2,标准偏差为 3 时,求 𝑥 =1 的标准化值。
我们可以用norm.cdf
求概率,用norm.ppf
配 𝜇 =0, 𝜎 =1 求标准化值。
norm.cdf(1, loc=2, scale=3)
norm.ppf(q=norm.cdf(1, loc=2, scale=3))
结论
scipy.stats.norm 为我们提供了参数loc
和scale
来指定标准偏差。它也有多种方法,本文中我们探讨了rvs
、cdf
、sf
、ppf
、interval
、isf
。
Matplotlib 为我们提供了简单而广泛的工具来改变包括 3D 在内的图形的微小细节。
通过 成为 会员,可以完全访问媒体上的每个故事。
关于 Jupyter 的更多文章
[## 如何在 Docker 上运行 Jupyter 笔记本
不再有 Python 环境和包更新
towardsdatascience.com](/how-to-run-jupyter-notebook-on-docker-7c9748ed209f) [## 维恩图 Python 包:Vennfig
在 Jupyter 或 Terminal 上用一行代码画一个维恩图
towardsdatascience.com](/introducing-basic-venn-diagram-python-package-vennfig-fa3f8e4dcb36) [## 线性关系的度量
皮尔逊与 Jupyter 笔记本的积矩相关性
towardsdatascience.com](/a-measure-of-linear-relationship-5dd4a995ee7e) [## 轻松创建统计数据的 Python 包
Statsfig 可以用一行代码创建分布图和盒须图
towardsdatascience.com](/a-python-package-to-create-stats-figures-with-ease-503cf6ec0b26)
使用 Optuna 获得精确的 Scikit 学习模型:一个超参数框架
在过去的几个月里,超参数框架一直是讨论的热点。有几个软件包已经开发并仍在开发中,选择一个已经成为一个艰难的选择。这种框架不仅有助于拟合精确的模型,还可以帮助数据科学家将效率提高到一个新的水平。在这里,我展示了如何使用最近流行的 Optuna 框架来获得任何 Scikit-learn 模型的最佳参数。我只实现了随机森林和逻辑回归作为例子,但是其他算法也可以以这里所示的类似方式实现。
为什么是 Optuna?
如果整合到日常实验中,Optuna 可以成为工作马工具之一。当我使用 Optuna 以如此小的努力实现逻辑回归时,我被深深地打动了。以下是我喜欢 Optuna 的几个原因:
- API 的易用性
- 出色的文档
- 适应任何算法的灵活性
- 像修剪和内置可视化模块这样的功能
文件:https://optuna.readthedocs.io/en/stable/index.html
Github:https://github.com/optuna/optuna
在我们开始查看功能之前,我们需要确保我们已经安装了必备的软件包:
- 奥普图纳
- Plotly
- 熊猫
- sci kit-学习
基本参数和定义:
建立基本框架非常简单明了。它可以大致分为 4 个步骤:
- 定义一个目标函数(步骤 1)
- 定义一组超参数进行尝试(步骤 2)
- 定义您想要优化的变量/指标(步骤 3)
- 最后,运行功能。这里需要提一下:
- 您试图优化的得分函数/变量 将被最大化或最小化
- 您想要进行的试验次数。超参数的数量越多,定义的试验次数越多,计算成本就越高(除非你有一台强大的机器或 GPU!)
在 Optuna 世界中,术语试验是目标函数的单个调用,多个这样的试验一起被称为研究。
以下是 scikit-learn 包中随机森林和逻辑回归的基本实现:
当您运行上面的代码时,输出如下所示:
终端或笔记本电脑中的输出
正如我们在上面看到的,逻辑回归和随机森林的选择以及它们各自的参数在每次运行中都有所不同。每次试验可以是具有不同参数的不同算法。研究对象存储各种输出,可以按如下方式检索:
更详细的结果
正如我们在这里看到的, 21 的随机森林和n _ 估计量为 153 和最大深度最适合这个数据集。
定义参数空间:
如果我们在步骤 2 (basic_optuna.py)中查看,我们将超参数 C 定义为具有浮点值的日志。类似地,对于随机森林,我们定义了 max_depth 和 n_estimators 作为要优化的参数。Optuna 支持五种定义参数的方式:
定义参数
历史研究:
我觉得,数据科学家的一个基本需求是,他们希望跟踪所有的实验。这不仅有助于比较它们中的任意两个、三个或多个,而且有助于理解模型在超参数变化、添加新特征等情况下的行为。Optuna 内置了记录所有实验的功能。在访问旧实验之前,我们需要存储它们。下面的代码显示了如何执行这两个命令:
- 您可以选择一个名称来创建实验
- 存储为关系数据库(RDB) 形式。我这里用的是 sqlite 。其他选项是使用 PostgreSQL,MySQL 。您也可以使用 joblib 作为本地 pkl 文件来存储和加载**。**
- 之后继续进行研究
这里的存储是一个额外的参数,如果您想使用 RDB 存储选项,需要在 create_study 函数中传递。此外,设置*load _ if _ exists =*True将加载一个已经存在的检查。对于 joblib,它类似于如何存储和加载一个训练好的模型。再次运行将根据上次存储的试验开始优化试验次数。
如果我们使用以下方法,可以获得研究中所有试验的详细概览:
所有试验的结果
从上面的结果中可以看出,对于不适用于该算法的列/参数,有一个 NaN 值。除此之外,我们还可以计算每次试验所花费的总时间。有时,时间考虑是至关重要的,因为它提供了一种思路,即与其他参数相比,特定的参数集是否需要更长的时间来拟合。
分布式优化:
您可以在您的机器上运行多个作业,以实现超参数优化。使用 Optuna 运行分布式超参数优化非常简单。我认为使用 Optuna 作为超参数优化框架是有益的。考虑我们定义并存储为名为 optimize.py 的 python 文件的相同目标函数。参数建议将基于试验的历史,并在我们在多个终端中运行时进行更新:
在两个独立的终端中运行,输出如下所示:
端子 1 输出
端子 2 输出
比较终端 1 的输出和终端 2 的输出,我们可以看到随机森林和逻辑回归选择了不同的参数。在终端 1 中,我们看到所有试验都只选择了随机森林。在终端 2 中,仅选择了 1 个逻辑回归试验。您可以看到两个输出的试验号不同。此外,如果您使用 n_jobs 参数获得多个可用内核,您还可以增加作业数量,使其速度更快。
添加属性:
帕特里克·帕金斯在 Unsplash 上拍摄的照片
在评估历史实验时,为实验做一些笔记或属性会有很大帮助。用户可以使用 set_user_attr 方法为试验和研究添加键值对,如下所示:
用户可以在研究对象上使用 user_attrs 方法访问属性,如上面的代码所示。我认为这是使用 Optuna 时可用的附件。
修剪:
https://Cornell farms . com/blogs/resources/pruning-fruit-trees
如图所示,修剪会删除树中不需要的或多余的分支。类似地,在机器学习算法的世界中,修剪是移除对分类器提供很少能力的部分的过程,并且有助于减少分类器的过度拟合,反过来提供更好的准确性。机器学习从业者必须精通术语“提前停止”,这类似于 Optuna 中修剪的工作方式。
运行 pruning.py 后的输出(上面的代码)
如上所示,对于特定的试验,如果结果不优于中间结果,试验被删除(这里是试验 7 和试验 10)。Optuna 中还提供其他类型的修剪程序,如 MedianPruner、NopPruner、PercentilePruner 、 SuccessiveHalvingPruner 等。你可以试着在这里得到更多的信息。
可视化:
除了上面显示的功能,Optuna 还提供了一些预先编写的可视化代码。这个可视化模块就像蛋糕上的樱桃,让我们更好地理解算法的适用性。我把其中的一些画在下面:
优化历史图:
优化历史图显示每次试验获得的目标值,并绘制最佳值。最佳值是一条直线,直到达到下一个最佳值,如下图所示:
优化历史图
平行坐标图:
平行坐标图有助于理解研究中的高维参数关系。这里我们只选择随机森林,我们将 x 轴视为参数 max_depth 和n _ estimatorsv/s y 轴上的目标值。我们可以看到,最佳优化值的试验是 max_depth ~ 23 和 n_estimators ~ 200。
平行坐标图
切片图:
该图有助于绘制传递给优化的所有参数之间的关系。切片图类似于上面显示的平行坐标图。
切片图
这里显示的所有可视化只是针对两个参数。如果使用多个参数,会发现它非常有用。这些图变得更加密集,可以提供参数之间关系的清晰图像。还有许多其他实现的可视化可以在这里找到。
结论:
Optuna 不仅限于用于 scikit-learn 算法。或许,TensorFlow、Keras 之类的神经网络,XGBoost、LightGBM 之类的梯度增强算法以及许多其他算法也可以使用这个奇妙的框架进行优化。Optuna 贡献者的一些例子已经可以在这里找到了。Optuna 是我遇到的最好的通用框架之一。正如我之前提到的,与众不同的是优秀的文档,支持几乎所有的算法,根据需要修改的灵活性等等。除此之外,Optuna 社区已经在框架的顶部构建了许多包装器,并且还在增长,负责许多繁重的工作。总的来说,Optuna 是一个巨大的超参数框架,可以作为数据科学工具包的一部分,我强烈推荐给任何数据科学家。
探索 Python 范围函数
了解 Python Range()函数及其功能
介绍
range()
是 Python 中的内置函数。默认情况下,它返回一个从零开始递增 1 的数字序列,并在给定的数字之前停止。
现在我们知道了范围的定义,让我们看看语法:
**range***(start, stop, step*)
它有三个参数,其中两个是可选的:
**start:**
可选参数,用于定义序列的起点。默认情况下是零。**stop:**
这是一个强制参数,用来定义序列的停止点**step:**
它也是一个可选参数,用于指定每次迭代的增量;默认情况下,该值为 1。
一般用法
由于它返回一个数字序列,大多数开发人员使用这个范围来编写循环。当您没有列表或元组,而只有实现循环的特定值时,这很方便。
变奏一
这里,我们将实现一个只有一个参数— stop
值的 for 循环。
这里x
是我们用来实现循环的范围,n
是每次迭代中的值。观察到输出在stop
值之前结束;它绝不是类似于list.size()
的范围迭代的一部分。
变奏二
这里我们将使用 start 和 stop 作为参数来实现 for 循环。
变奏三
现在,我们将使用所有三个参数:start
、stop
和step
。看一看:
当步长值为 2 时,循环在每次迭代时增加 2,而不是增加 1。我们需要记住的一件重要事情是步长值永远不应该为零;否则,它将抛出一个ValueError
异常。
列表类型上的迭代
除了循环之外,range()
还用于使用len
函数遍历列表类型,并通过index
访问值。看一看:
反向范围
对于该范围内的任何参数,我们可以给出正数或负数。这个特性提供了实现反向循环的机会。我们可以通过传递一个更高的索引作为start
和一个负的step
值来实现。看一看:
使用范围创建列表、集合和元组
range()在很多情况下都很方便,而不仅仅是用来写循环。例如,我们使用范围函数创建列表、集合和元组,而不是使用循环来避免样板代码。看一看:
为了更有趣一点,我们可以在 step 中传递负值来创建升序列表。看一看:
索引范围
就像我们使用索引访问列表中的值一样,我们可以对 range 做同样的事情。语法也类似于列表索引访问。
浮动范围内的参数
默认情况下,range()
函数只允许整数作为参数。如果您传递流值,那么它会抛出以下错误:
TypeError: 'float' object cannot be interpreted as an integer
但是有一个解决方法;我们可以编写一个类似下面的自定义 Python 函数。它将允许您为步长参数指定一个浮点值。
奖金
要了解更多关于 Python 从基础到高级的知识,请阅读以下文章
就这些了,希望你能学到一些有用的东西,感谢阅读。
你可以在 Medium 、 Twitter 、 Quora 和 LinkedIn 上找到我。
探索 Excel 和 Python 中的工资数据趋势
最近有人告诉我关于自我报告的匿名工资信息,所以我很想分析这些数据,看看会出现什么样的模式。
公开分享这些信息提高了透明度,有利于理解和避免妇女和有色人种经历的薪酬不平等。通过这些数据可以找到一个人的年龄组,经验水平和类似的角色,看看他们可以期望什么样的薪酬水平。人们可以利用这些信息来确定他们是否报酬过低,或者选择最值得从事的职业。
在本文中,我将完成数据科学管道的第一步,即数据清理,并以几个可视化的例子来结束,以便更好地理解这些数据。最后,我将介绍这些数据的未来发展方向。
数据采集和数据清理
数据集
该数据集通过谷歌表格填充,并在互联网上各种关于女性和少数族裔在工作场所薪酬不平等的博客帖子中被引用。你可以在这里阅读这份自报工资的趋势,在这里查看原始数据集。
数据清理
虽然到目前为止已经记录了如此多的回复(在撰写本文时有 34,000 个),但该表单没有针对薪水的数据验证。这意味着是时候着手数据清理工作了。
要清理的正则表达式
正则表达式(Regex)是描述文本中要匹配的模式,然后执行某些操作(如匹配、替换或提取匹配的文本)的方法。Excel/Google 工作表有正则表达式函数(REGEXMATCH
、REGEXREPLACE
和REGEXEXTRACT
),它们执行上述功能。
打扫卫生时,你首先要找出你最大的问题是什么,从你能看到/想到的更一般的问题到更具体的问题。一旦你知道要修复什么,你就实现它,测试它的准确性,然后在必要的时候改进它。在这种情况下,我看到有些工资含有文字。这不是我们所有的工资只是数字。我们希望最终将它们转换为整数数据类型。
不干净工资的例子
我的下一个问题是,有多少薪水不仅仅是数字。我创建了一个新列来创建一个二进制标志,如果annual_salary
中的单元格包含字母 A-Z(不区分大小写),则该标志返回 TRUE。如果是,打印 TRUE,否则打印 FALSE。
=IF(REGEXMATCH(E34166, “[A-Za-z]+”), TRUE, FALSE)
我在一个名为how many salaries have just numbers?
的新列中为每个薪水单元格运行了这个,在该列中,我看到 96%的薪水只是数字,这是个好消息。我注意到,在这 4%的脏数据中,50%只是因为人们用“K”或“K”缩写了千位,例如:62K 或 51k。
看到这一点,我添加了另一个 flag 列,以便只匹配 salary 中只有一个大写或小写“k”的情况,我还添加了另一个列,以便能够对此进行筛选:
=IF(REGEXMATCH(E2, "[Kk]{1}"), TRUE, FALSE)
作为所有可能问题中最大的一个,我创建了一个修复程序来检查has_a_k_bool
列中的 1。如果那一列有一个 1,这意味着薪水是用 k 缩写的,所以我只提取了数字,然后乘以 1000,否则,我只提取了数字,因为它们被认为是干净的。这是我用的公式:
=IF( G209=1, VALUE(REGEXEXTRACT(E209,"[0-9]+"))*1000, VALUE(REGEXEXTRACT(E209,"[0-9]+")))
我还注意到,那些自称“18 岁以下”的人报告的大部分工资要么是时薪,要么低得多(异常值)。因为这个数据集主要是为大学以外的人准备的,所以我添加了一个标志来将他们从最终的数据集中移除。
=IF(B197="Under 18", 1, 0)
为了执行我的数据清理,我遵循了一个具有循环依赖的过程。第一步是观察原始数据中的错误。其次,我实现了一个标志,通过这个标志进行过滤来找出问题的大小。然后,我测试了一个问题的修复,看我能在多大程度上减少原来的问题。然后,如果需要,我改进了我的方法,并再次测试了实现的性能。
在一个新的选项卡上,我使用 FILTER 函数用一些附加的标准查询了原始的 raw data 选项卡。这将接受一个数据范围和一些标准,返回该范围的过滤视图。
=FILTER('Raw Data'!B:P,'Raw Data'!G:G = 1)
G 栏是我检查他们是否在 18 岁以下的标志。
原始数据格式
虽然我们可以而且应该进一步清理,因为工资取决于位置和其他因素,但这超出了本文的范围。
以下是我的数据的最终格式:
干净的数据集
一些可视化
此时,由于内存的使用,建议退出 Google Sheets。我下载了 CSV 并开始用 Python 在 Jupyter 笔记本上工作。
我将分享我所做的一些高层次的探索。当然,还有很多值得探索的地方!
不幸的是,Excel 数据类型不是很合适,我们的薪水本应该是类型number
的,但当它们进入 Python 时就不合适了。在将数据集从 CSV 加载到 Pandas 数据框架后,我的第一步是将每一列强制转换为它们应有的数据类型:
数据类型强制
为了便于参考和节省输入,我为我查看的每一列分配了一个变量:
列分配
我怀疑这些数据可能偏向于中级专业人士(25-34 岁年龄段),所以我通过计数图验证了这一点。这是为该信息生成绘图的代码:
年龄分布图
和结果图:
年龄分布
这证实了我的假设,即数据集中的大多数值都在 25-34 岁的年龄范围内,高级专业人员占了剩余部分(35-44 岁)的大部分。
然后,我观察了大学毕业后经历的年数分布,以了解人们的经历程度:
经验分布图代码
下面是由上面的代码生成的图:
经验分布图
上图显示了大致相同的信息,就是大部分人 22 岁毕业开始工作。这意味着 25-34 岁年龄组中的大多数人将有 2 到 12 年的工作经验。这看起来就在上图的右边。
结论
结果
在 Google Sheets 的数据清理步骤之后,人们可以简单地过滤数据集,以显示他们的年龄组、经验水平组和位置。然后他们会开始大致了解你应该得到多少报酬。另一个有价值的结果可能是通过职位看到你期望得到什么,这可以帮助你决定你潜在的职业道路!
未来的步骤
薪资信息是相对的,并且各不相同,取决于地点、行业和职位/类型。因此,需要 NLP 来标准化这些字段。这是因为,在工业的拼写上,即使看似很小的差异也会使电脑失灵。例如:“高等教育”、“高等教育”、“edu”、“教育”和“教育”对人类来说显然都是教育行业,但对计算机来说是不同的行业,因为这些值是不等价的!这就是我们今后将这篇文章引向的地方。
感谢阅读和快乐编码!我也很乐意与人交流。在 GitHub 和 LinkedIn 上找到我。
奢侈的生活
探索 SimCLR:视觉表征对比学习的简单框架
从头开始用一个 PyTorch 实现 SimCLR
介绍
很长一段时间以来,我们知道迁移学习在计算机视觉(CV)应用中的好处。如今,预训练的深度卷积神经网络(DCNNs)是学习新任务的第一个首选预解决方案。这些大型模型是在巨大的监督语料库上训练的,比如 ImageNet。最重要的是,它们的特点是能很好地适应新问题。
当缺少带注释的训练数据时,这一点尤其有趣。在这种情况下,我们采用模型的预训练权重,在其上添加一个新的分类器层,并重新训练网络。这被称为迁移学习,是 CV 中使用最多的技术之一。除了在执行微调时的一些技巧(如果是这样的话),已经(多次)表明:
如果为一项新任务进行训练,用预训练权重初始化的模型往往比使用随机初始化从零开始训练的模型学习得更快、更准确。
然而,正如人们可能猜测的那样,在这个过程中存在一个瓶颈。目前大多数迁移学习方法依赖于在监督语料库上训练的模型。但是问题是注释数据并不便宜。
如果我们环顾四周,数据,以一种无人监管的方式,是丰富的。因此,使用未标记的数据来学习表示是有意义的,这些表示可以用作训练更好的监督模型的代理。事实上,这是一个长期存在的问题,正如我们将看到的,当前对无监督表示学习的研究终于赶上了有监督的方法。
无监督表示学习
无监督表示学习关注于解决以下问题:
我们如何从未标记的数据中学习好的表示?
除了什么是好的表示的问题之外,从未标记的数据中学习也有很大的潜力。它可以开启许多当前迁移学习无法解决的应用。然而,从历史上看,无监督的表示学习比有监督的表示学习要困难得多。
作为一个简单的例子,让我们考虑乳腺癌检测的任务。目前,所有最佳解决方案都使用 ImageNet 预训练模型作为优化流程的起点。有趣的是,尽管乳腺癌幻灯片图像和常规 ImageNet 样本之间存在显著差异,但迁移学习假设在某种程度上仍然成立。
大致来说,大多数用于乳腺癌检测的监督数据集,如camelion 数据集,在大小和可变性方面都无法与常见的计算机视觉监督数据集相比。另一方面,我们有大量未加注释的乳腺癌幻灯片图像。因此,如果我们可以从无监督的(大得多的语料库)中学习良好的表示,这肯定会有助于学习更多特定的下游任务,这些任务具有有限的注释数据。
幸运的是,视觉无监督表示学习已经显示出巨大的前景。更具体地说,使用基于对比的技术学习的视觉表现现在达到了通过监督方法学习的水平——在一些自我监督的基准测试中*。*
让我们探索一下无监督的对比学习是如何工作的,并仔细看看该领域的一项主要工作。
对比学习
对比法的目的是通过强制相似元素相等而不相似元素不同来学习表征。
最近几个月,我们看到了基于这些原则的无监督深度学习方法的爆炸式增长。事实上,在线性分类基准中,一些自我监督的基于对比的表示已经匹配基于监督的特征。
对比学习的核心是噪声对比估计(NCE)损失。
上式中,可以把 x+ 看作类似于输入 x 的数据点。换句话说,观察值 x 和 x+ 是相关的,并且一对 (x,x+) 代表一个正例。通常情况下, x+ 是对 x 进行某种变换的结果。这可以是旨在改变 x 的大小、形状或方向的几何变换,或者任何类型的数据增强技术。一些例子包括旋转、透明、调整大小、剪切等等*。*
另一方面, x- 是与 x 不同的例子。对 (x,😆 形成了一个反例,它们应该是不相关的。在这里,NCE 损失将迫使他们不同于积极的一对。注意,对于每个正对 (x,x+) 我们有一组 K 个负对。事实上,经验结果表明,需要大量的否定才能获得良好的表象。
**sim(。)函数是一个相似性(距离)度量。它负责最小化阳性之间的差异,同时最大化阳性和阴性之间的差异。 经常,sim(。) 用点积或余弦相似度**来定义。
*最后, **g(。)*是一种卷积神经网络编码器。具体来说,最近的对比学习架构使用暹罗网络来学习正面和负面示例的嵌入。这些嵌入然后作为输入传递给对比损失。
简单地说,我们可以把对比任务看作是试图在一堆否定中找出肯定的例子。
视觉表征对比学习的简单框架——sim clr
SimCLR 使用上述对比学习的相同原则。在本文中,该方法在自监督和半监督学习基准中实现了 SOTA。它引入了一个简单的框架来学习基于大量数据扩充的无标签图像的表示。简单来说,SimCLR 使用对比学习来最大化同一图像的两个增强版本之间的一致性。
学分: 视觉表征对比学习的简单框架
为了理解 SimCLR,让我们探索一下它是如何建立在对比学习框架的核心组件之上的。
给定一个输入图像,我们通过应用两个独立的数据扩充操作符来创建它的两个相关副本。这些变换包括(1) 随机裁剪和调整大小 , (2) 随机颜色扭曲,( 3)随机高斯模糊。
操作的顺序是固定的,但是由于每个操作都有自己的不确定性,这使得结果视图在视觉上有所不同。请注意,由于我们在同一幅图像上应用了 2 个不同的增强函数,如果我们对 5 幅图像进行采样,我们最终会得到批次中的2**×5 = 10个增强观察值。参见下面的视觉概念。
为了最大化底片的数量,想法是将批中的每个图像(索引为 i )与所有其他图像(索引为 j )配对。注意,我们避免将观察 i 与其自身以及其扩充版本配对。结果,对于批中的每个图像,我们得到 2 ×(N-1) 负对— ,其中 N 是批大小。
注意,同样的方法适用于给定观测的两个扩充版本。这样,负对的数量增加得更多。
而且通过这种方式排列否定样本, SimCLR 的优点是不需要额外的逻辑来挖掘否定。为了有一个概念,最近的实现像 PIRL T21 和 MOCO 分别使用一个存储体和一个队列来存储和采样大批量的底片。
事实上,在最初的实现中,SimCLR 的批处理大小为 8192。按照这些想法,这个批量产生每个正样本对 16382 个负样本。此外,作者还表明,更大的批次(因此更多的阴性)往往会产生更好的结果。
SimCLR 使用 ResNet-50 作为主要的 ConvNet 主干。ResNet 接收形状为 (224,224,3) 的增强图像,并输出 2048 维嵌入向量 h 。然后,一个投影头**g(。)*** 应用于嵌入向量*产生最终表示 z = g(h) 。投影头 g(。) 是一个有 2 个密集层的多层感知器(MLP)。两层都有 2048 个单位,隐藏层具有非线性(ReLU)激活功能。**
对于相似度函数,作者使用余弦相似度。它测量 d 维空间中两个非零向量之间角度的余弦值。如果两个向量之间的角度为 0 度,则余弦相似度为 1。否则,它输出一个小于 1 一直到-1 的数。注意,对比学习损失作用于投影头 g(.)—z嵌入向量。**
一旦系统被训练好,我们就可以通过把投影头g*(。)*** 并使用表象 h (直接来自 ResNet)来学习新的下游任务。**
培训和评估
一旦对比学习目标的组成部分就位,系统的训练就简单了。你可以在这里看一下我的实现。
为了训练模型,我使用了 STL-10 数据集。它包含 10 个不同的类,每个类有合理的少量观察值。最重要的是,它包含一个更大的无监督集,其中有 100000 个未标记的图像——这是用于训练的大部分图像。
对于这个实现,我使用 ResNet-18 作为 ConvNet 主干。它接收形状为 (96,96,3) 、常规 STL-10 尺寸的图像,并输出尺寸为 512 的矢量表示。投影头 g(。) 有 2 个全连通层。每层有 512 个单元,产生最终的 64 维特征表示 z 。
为了训练 SimCLR,我采用了数据集的 训练+未标记的 部分— ,总共给出了 105000 个图像。
在训练之后,我们需要一种方法来评估 SimCLR 所学习的表示的质量。一种标准方法是使用线性评估协议*。*****
*想法是在来自 SimCLR 编码器的固定表示上训练线性分类器。为此,我们获取训练数据,将其传递给预训练的 SimCLR 模型,并存储输出表示。注意,此时,我们不需要投影头 g(。)*再也没有了。
这些固定的表示然后被用于使用训练标签作为目标来训练逻辑回归模型。然后,我们可以测量测试的准确性,并使用它作为特性质量的度量。
这个 Jupyter 笔记本显示了评估协议。使用 SimCLR 固定表示作为训练信号,我们达到了 64%的测试精度。有一个想法,对训练数据执行 PCA 并保留最重要的主成分,我们得到的测试精度只有 36%。这强调了 SimCLR 所学习的特征的质量。
一些最后的评论
最初的 SimCLR 论文还提供了其他有趣的结果。其中包括:
- 非监督对比特征学习在半监督基准上的结果;
- 向投影头添加非线性层的实验和益处;
- 使用大批量的实验和好处;
- 用对比目标训练大型模型的结果;
- 对比学习中使用多种强数据扩充方法的消融研究;
- 标准化嵌入对训练基于对比学习的模型的好处;
我鼓励你看看这篇文章,了解更多的细节。
感谢阅读!
参考文献
陈,丁等,“视觉表征对比学习的一个简单框架”arXiv 预印本 arXiv:2002.05709 (2020)。
米斯拉、伊山和劳伦斯·范德马腾。"借口不变表征的自我监督学习."arXiv 预印本 arXiv:1912.01991 (2019)。
何,,等,“无监督视觉表征学习中的动量对比”arXiv 预印本 arXiv:1911.05722 (2019)。
-何,,等,“深度残差学习在图像识别中的应用”IEEE 计算机视觉和模式识别会议录。2016.
原载于https://sthalles . github . io。**
探索人工智能地牢
GPT 的不幸遭遇-3
Mauro Sbicego 在 Unsplash 上拍摄的照片
GPT-3 是由 OpenAI 创建的语言模型,它可以在给出提示的情况下形成自然语言。幕后是一个神经网络,有 1750 亿个参数,从互联网上收集了大量数据。结果是一台能够理解并回答 GPT 3 号提出的问题的机器。除了英语,它还不会说或写任何东西。但它确实对基本语法有所了解。这意味着,如果你让它告诉你什么是三角形,它会说‘一个三面体’或类似的东西。
我必须承认:我讨厌写介绍。所以我写了上面这一段的前两句话,把它插入 AI 地牢中,加上一些上下文,这一段的剩余部分就出来了。(我们马上就会看到,GPT 3 号在这里严重抛售自己。)
截图自 AI 地牢
它显然并不完美,但应该考虑到 AI Dungeon 运行的是 GPT 3 的较弱版本,并且被配置为基于文本的游戏,而不是一种写作作弊的方式。如下例所示,完整的 GPT-3(目前对其访问受到严格限制)可能会被误认为是大学水平的作家。
在我的家庭中,关于“牛仔”一词的起源一直存在争议。我们知道这个词最初是用来描述一个牧民或赶牛的人。我的一些家人坚持认为这个词是在西班牙创造的,描述的是那些工人的墨西哥或西班牙版本。
另一方面,我父亲的家庭坚持认为,这个词是英国牛仔用来形容强悍但总体上平和的牧民或牧人的。
几周前,当我们和我的父亲和他的妻子,我的继母 Barb 一起去看《独行侠》时,这个争论又出现了。他们坚持说,骑白马的人是治安官,不是牛仔。
偶尔,人工智能的笨拙和重复暴露了它的身份:
平心而论,许多人类作家都有类似的缺陷。然而,很少有人能用西班牙语、法语、T4 语、匈牙利语和葡萄牙语书写。
图灵测试
记得尤金·古斯曼吗?2014 年,聊天机器人因通过图灵测试而成为国际头条,说服了 30%的小组成员相信它是人类。尤金·古斯特曼是一个来自乌克兰的 13 岁男孩,充满了俚语、缩写和冷漠的语气。聊天机器人是否成功通过图灵测试仍然是一个有争议的话题;几乎可以肯定,模仿一个怀有敌意的 13 岁孩子比在智力对话中冒充人类要容易得多。
自然,我想看看 GPT-3 在图灵测试中表现如何,但我需要一些标准来评估它的反应。谢天谢地,图灵提供了一个审讯者和计算机之间的对话样本,我试图复制它。
为了促使 GPT-3 回答与图灵对话中相同的问题,我首先给询问者起名叫“保罗”,给计算机起名叫“杰克”。我这样做的目的是为了避免任何混淆,在对话中询问者和计算机是两个独立的角色。然后,我提供了一些关于接下来讨论的背景(斜体)。样本对话和我哄骗人工智能地牢之间有一些相似之处,但对话在中途很大程度上破裂了。
一个单独的对话是否表明能够通过图灵测试是值得怀疑的。然而,如果你认为古斯特曼通过了图灵测试,那么 GPT-3 似乎也能做到。
棘手的问题
通过人工智能地牢的一些操作,我们可以采访来自各种领域的名人的模仿。以下是大数据领域假拉里·佩奇的一个片段:
(改善我们对大数据的使用)有两种主要方法。第一种是自动化,或者我喜欢把它称为智能药丸……另一种方法是以不同的方式分析数据。比如这些数字背后都有什么故事?这个人为什么买东西?他们有什么故事?如果我们能理解所有这些,我们就能有针对性地做广告,所以这对人们真的很重要。
在采访的另一部分,佩奇开始谈到,在他六岁时,由于他妹妹的出生,有人想杀了他,所以考虑一下上面手里拿着盐罐的摘录。你可以在这里阅读这篇采访的全文。
也是你下一篇文章的灵感来源:
以下是发表在 towardsdatascience.com 主办的媒体刊物《走向数据科学》上的一篇文章的标题:“数据科学家分析自己代码的新工具。
你打开文章读了一遍。这是你的一个同事写的,他继续解释说他或她已经创建了一个名为“数据分析工具包”的程序,它允许你轻松地分析你自己的代码**。**
我必须承认,我已经拥有了这样一个工具包。这叫做“漫无目的地滚动,试图找出为什么我的代码被破坏了”。如果你问我,我会说这很有创意——显然 GPT 3 号有不同的想法。
埃米尔·佩龙在 Unsplash 上拍照
假装直到你成功?
我在 GPT 3 的经历给我留下了深刻的印象,但也暴露了它的局限性。最终,GPT 3 号不可思议地模仿了从互联网上刮来的东西,而不是展示一般的智力。即使是完整版,除了最基本的算术都有问题,而且玩的是一盘相对较弱的棋。
OpenAI 首席执行官 Sam Altman 的推文
以人类的标准来判断,GPT 3 号可能笨得让人麻木。这并没有阻止它执行以前被认为是高智能人类领域的任务。这个 Twitter 帖子整理了它的一些成就,包括以各种风格编写小说,从简单的功能描述中生成一个工作的 React 应用程序,以及法律写作。
在这一点上,我相当确信,人们会因为像 GPT-3 这样的语言模型的进步而丢掉工作。我脑子里唯一的问题是,这种情况会在未来五年还是十年发生。人工智能可能离实现还很远,但智能不是扰乱社会的先决条件。
现在,我会享受玩 AI 地牢的乐趣,尽量不去考虑几年后我可能要和它竞争一份工作。我在骗谁呢?到时候就没有竞争了。
探索条形码世界
用 Wolfram 语言编写的计算思维故事
Johannes Plenio 在 Unsplash 上拍摄的照片
人类无法理解,但对电脑和手机来说却是小菜一碟:条形码无处不在。每一件产品,每一个包装,每一个货架上都有大量的细菌。黑白图案,通常是线,有时是点,为我们的硅朋友提供了一个小数字,概括了这个物体的所有内容。
像 barcodelookup.com这样的在线服务提供了拥有数百万商品的数据库,将这些小数字转化为丰富的信息,如产品名称、产品类别和特定供应商的信息。
在 Wolfram 语言中,您可以读取条形码,也可以创建条形码图像。它没有内置的服务来解释条形码,但在这个故事中,我将向您展示如何从 BarcodeLookup 服务连接到 API。
先从自己生成条形码说起。这里使用的函数叫做 BarcodeImage 。它可以生成最常见类型的条形码。例如,这会生成一个 UPC 条形码图像:
BarcodeImage["123456789999", "UPC"]
(图片由作者提供)
这是一个二维码的例子。大多数智能手机会在你将摄像头对准网页时打开网页:
BarcodeImage["https://www.wolfram.com", "QR"]
(图片由作者提供)
自动识别条形码是通过条形码识别功能完成的。即使条形码只是图像的一部分,它也能工作,尽管它偶尔会拾取一个“偏离的”条形码。在这种情况下,结果是正确的:
(图片由作者提供)
接下来,为了解释代码“04150800414 ”,我编写了一个简单的 Wolfram 语言函数,它绑定到条形码查找服务的 API。
[## 条形码查找
在线查找条形码
www.wolframcloud.com](https://www.wolframcloud.com/obj/arnoudb/DeployedResources/Function/BarcodeLookup)
可以通过其名称来访问它:
BarcodeLookup = ResourceFunction[
"user:arnoudb/DeployedResources/Function/BarcodeLookup"
]
现在我们可以查找产品信息了。“密钥”是一个由条形码查找服务 API 要求并提供的小型字母数字字符串。
product = BarcodeLookup["041508300414",key]
例如,您可以通过编程方式向下钻取产品名称:
In[]:= product["products", 1, "product_name"]Out[]= "San Pellegrino Pompelmo Grapefruit Sparkling Fruit Beverage, 11.15 Fl. Oz., 6 Count"
这里的应用可能性几乎是无限的。有了这些功能,构建跟踪库存、生成报告和自动重新进货程序的应用程序变得很容易。
探索冠状病毒数据集
新型冠状病毒 2019 数据集的探索性数据分析
马库斯·斯皮斯克在的照片
在本帖中,我们将对新型冠状病毒 2019 数据集进行简单的探索性数据分析。数据集可以在 Kaggle 上找到。该数据包含 2019 年病例数、死亡数和恢复数的每日信息。数据集“covid_19_data.csv”包含以下各列:
- Sno —序列号
- 观察日期—观察的日期,以年/月/日为单位
- 省/州—观察的省或州
- 国家/地区—观察国
- 上次更新时间-以 UTC 表示的给定省或县的行更新时间
- 已确认—截至该日期的累计已确认病例数
- 死亡人数——截至该日期的累计死亡人数
- 已恢复—到该日期为止已恢复案例的累计数量
让我们将数据读入熊猫数据框:
import pandas as pddf = pd.read_csv("covid_19_data.csv")
让我们打印前五行数据:
print(df.head())
我们可以做的第一件事是在“Confirmed”列上生成一些统计数据。让我们来看看确诊病例的均值和标准差:
print("Mean: ", df['Confirmed'].mean())
print("Standard Deviation: ", df['Confirmed'].std())
我们还可以生成已确认累积病例的直方图:
import seaborn as sns
import matplotlib.pyplot as plt
sns.set()
plt.title("Confimed Cases Histogram")
df['Confirmed'].hist(bins = 10)
我们可以为恢复的案例生成类似的统计数据:
print("Mean: ", df['Recovered'].mean())
print("Standard Deviation: ", df['Recovered'].std())
并绘制直方图:
plt.title("Recovered Cases Histogram")
sns.set()
df['Recovered'].hist(bins = 200)
最后,我们可以看看死亡的统计数据:
print("Mean: ", df['Deaths'].mean())
print("Standard Deviation: ", df['Deaths'].std())
以及直方图:
plt.title("Deaths Histogram")
sns.set()
df['Deaths'].hist(bins = 200)
我们还可以使用 collections 模块中的“Counter”方法查看省/州的频率:
from collections import Counter
print(Counter(df['Province/State'].values))
让我们删除缺失的值,并将计数器限制为仅输出五个最常见的省份:
df.dropna(inplace=True)
print(Counter(df['Province/State'].values).most_common(5))
我们还可以使用盒状图来显示基于最小值、最大值、中值、第一个四分位数和第三个四分位数的数值分布。如果你对它们不熟悉,可以看看文章了解盒图。
例如,让我们绘制“安徽”、“北京”和“重庆”确诊病例的分布图:
df = df[df['Province/State'].isin(['Anhui', 'Beijing', 'Chongqing'])]
sns.boxplot(x= df['Province/State'], y = df['Confirmed'])
plt.show()
我们可以对恢复的案例做同样的事情:
df = df[df['Province/State'].isin(['Anhui', 'Beijing', 'Chongqing'])]
sns.boxplot(x= df['Province/State'], y = df['Recovered'])
plt.show()
对于死亡:
df = df[df['Province/State'].isin(['Anhui', 'Beijing', 'Chongqing'])]
sns.boxplot(x= df['Province/State'], y = df['Deaths'])
plt.show()
我就讲到这里,但是您可以随意使用数据并自己编码。这篇文章的代码可以在 GitHub 上找到。感谢您的阅读!
探索数据:从食物营养中学习
在没有明确目标的情况下,我们可以尝试从数据中探索什么
布鲁克·拉克在 Unsplash 拍摄的照片
我喜欢探索我的数据,并从中发现意想不到的模式。作为一名数据科学家,在我个人看来,我们需要具备这种好奇心特质,才能在这个领域取得成功。探索数据的方法不仅限于诸如可视化数据和获得统计数字的基本技术,一种方法是实现机器学习。
机器学习也是一种探索数据的技术,而不仅仅是人们经常喜欢宣传的预测目的。这就是为什么我经常专注于理解模型的概念,以了解我的数据是如何处理的;更好地了解我们的数据发生了什么变化。
在本文中,我想介绍通过无监督学习来探索数据,我们可以从统计数字和数据挖掘技术中获得什么信息。在这里,因为我的爱好之一是烹饪,我将使用来自 Kaggle 的关于普通食物和产品的食物营养价值的数据集。我想探究这些数据,既是为了学习,也是为了满足自己的好奇心。这意味着,我在这里的目标只是知道我的数据中发生了什么,以及我可以获得什么样的信息,而没有任何特定的目标。让我们开始吧。
探索数据
数据清理
首先,我们需要阅读我们的数据,了解我们的数据如何。这是重要的第一步。
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as snsdata = pd.read_csv('nutrition.csv')
data.head()
data.info()
我们实际上有 76 列,我没有在这里全部显示(这将是一个很长的列表),数据示例如上表所示。
我们的大部分数据是由营养值(卡路里、脂肪、糖、碳水化合物等)组成的。)与美食名。营养值栏有不同的度量单位,如克(克)、毫克(毫克)和微克(微克)。在这种情况下,我们还可以忽略功能 serving_size,因为除了所有数据都基于 100 克食物之外,它不提供任何其他信息。一些列还包含一个 NaN 值,我相信这个 Null 值意味着有等于 0 的值。现在,让我们做一些数据清理。
#Drop the serving_size column
data.drop('serving_size', axis = 1, inplace = True)#Fill the NaN value with 0
data.fillna(0, inplace = True)
在这种情况下,我希望除了 name 特性之外的所有特性都变成数字列。这意味着,我们需要删除数据中所有的非数字文本。我还想转换除卡路里以外的所有数字数据,使其具有相同的度量(克)。让我们开始吧。
#I would use Regular Expression Module to help me clean the data
import re#Looping in each non-numerical features except the name feature
for col in data.drop('name',axis = 1).select_dtypes(exclude = 'number').columns:
for i in data[col]:
if i == '0' or i == 0:
pass
else:
point = re.findall('[a-zA-Z]+',i)[0]
replace = []
if point == 'mg':
for j in data[col]:
if j == '0' or j == 0:
replace.append(float(j))
else:
replace.append(float(re.sub('[a-zA-Z]','',j))/1000)
elif point == 'mcg':
for j in data[col]:
if j == '0' or j == 0:
replace.append(float(j))
else:
replace.append(float(re.sub('[a-zA-Z]','',j))/1000000)
else:
for j in data[col]:
if j == '0' or j == 0:
replace.append(float(j))
else:
replace.append(float(re.sub('[a-zA-Z]','',j)))
data[col] = replace
data.rename({col:col+'(g)'}, axis =1, inplace = True)
break
这是我的数据的最终结果,我将进一步探索。请注意,我知道除了卡路里之外,所有数据现在都是以克为单位,但只是为了学习,我将它添加到我的列名中,这样我们就不会忘记它。
我还创建了另一个名为 food_categories 特性,因为当仔细检查这个命名特性时,逗号前面的第一个单词就是 food。
data['food_categories'] = data['name'].apply(lambda x: x.split(',')[0])
数字统计
如果我们试图一个接一个地可视化这些列,这将是巨大的并且有点重复,因为它不会给我们提供太多的信息。如果你愿意,你可以试试。我可以给你下面的代码。
for i in data.select_dtypes('number').columns:
sns.distplot(data[i])
plt.title(i)
plt.show()
有时候,在这种情况下,如果我们真的只是想探索数据,通过数字而不是可视化来看会更直观(毕竟我是一个更注重数字的人,因为我相信有时可视化是有偏见的)。
pd.set_option('display.max_columns', None)
data.agg(['mean', 'median', 'std', 'skew', 'kurtosis'])
例如,在这里,我使用。数据帧的 agg 方法,用于获取关于每列的平均值、中值、标准差、偏斜度和峰度的信息。这就是数字比形象更有说服力的地方。
众所周知,平均值是数据的平均值。多个要素可能具有相同的平均值,但它们在平均值周围的分布方式不同,这通过标准差(std)来表示。有一个规则叫做经验规则,我们可以通过标准差得到数据扩散的概率。经验法则表明:
- 68%的数据低于平均值 1 *标准差
- 我们 95%的数据低于平均值 2 *标准差
- 我们 99.7%的数据都低于平均值 3 *标准差
经验法则或者也有人说 68–95–99.7 法则经常被用来分析数据异常值。这种统计的主要问题是,它们会受到异常值或极值的影响,并经常导致数据失真。我用一张图片向你展示什么是扭曲的数据。
以上是 total_fat(g)特性图。它向右倾斜,因为尾巴在右边。但是,偏斜度有多大呢?这就是不对称统计的目的。我们可以记住关于偏斜度的一些规则是:
- 如果偏斜度在-0.5 和 0.5 之间,数据是相当对称的
- 如果偏斜度介于-1 和-0.5 之间或介于 0.5 和 1 之间,则数据是中度偏斜的
- 如果偏斜度小于-1 或大于 1,则数据是高度偏斜的
所以我们可以看到,如果我们上面的数据是高度倾斜的,实际上你会遇到的大多数数据都是这样的。那么峰度呢?这个统计数字告诉我们什么?峰度是衡量数据相对于正态分布是重尾还是轻尾的指标。这一分析可总结如下:
- 如果峰度接近于 0,那么通常假设正态分布。这些被称为中 kurtic 分布。
- 如果峰度小于 0,则该分布是轻尾的,称为宽峰分布。
- 如果峰度大于 0,那么该分布具有较重的尾部,称为细峰分布。
如果我们把它形象化,它看起来会像下面的图片。
过度峰度取自booglehead.com
准确地说,我们之前的数据被称为过度峰度,其中正态分布以峰度为 0 来衡量。如果我们只讨论峰度,正态分布将等于 3,这就是为什么在过度峰度中,我们将峰度减去 3。
我们的大部分数据都是不准确的。扭曲的数据实际上非常有趣,因为你可以尝试用它来探索。例如,基于卡路里,什么食物被认为是异常值。
由于我们的数据是足够偏斜的,我不会依靠平均值来发现异常值;相反,我会应用基于中位数的 IQR 方法。
IQR 或四分位距是基于数据位置的。例如,如果我们描述“卡路里”特征,我们将得到下面的描述。
data['calories'].describe()
IQR 将基于 25%的位置或 Q1 和 75%的位置或第三季度。我们也可以通过用 Q1 减去 Q3 得到 IQR 值(Q3-Q1)。使用 IQR 方法,我们可以根据上限或下限来决定哪些数据被视为异常值:
下限= Q1–1.5 * IQR
上限= Q3 + 1.5 * IQR
任何高于或低于此限值的数据都将被视为异常值。让我们试着实现这个方法,看看什么样的食物被认为是基于卡路里的异常值。
#Specifying the limit
cal_Q1 = data.describe()['calories']['25%']
cal_Q3 = data.describe()['calories']['75%']
cal_IQR = cal_Q3 - cal_Q1data[(data['calories'] < 1.5 * (cal_Q1 - cal_IQR)) | (data['calories'] > 1.5 * (cal_Q3 + cal_IQR)) ]['food_categories'].value_counts()
事实证明,大部分高热量食物是油,这并不奇怪。
无监督学习
上面我向你展示了一种从数字上探索数据的方法,现在我想向你展示一个机器学习如何帮助我们探索数据的例子。
无监督学习是一种机器学习,我们没有任何特定的学习目标。一个例子是聚类分析,我们向模型提供数据,输出是一个数据聚类,其中最接近的数据被视为一个聚类。
我喜欢做的是,如果我们没有任何探索数据的特定目标,我们可以让机器学习来为我们学习。使用无监督学习,我们可以获得以前没有意识到的新视角。让我们用我最喜欢的聚类分析算法举例说明。
我最喜欢的聚类算法是凝聚聚类分析,你可以在这里详细阅读。基本上,该分析将每一个数据点分配为一个单独的聚类,并通过合并每个聚类来进行,因此我们只剩下一个聚类。
现在,在我们进行分析之前,我们需要准备数据。聚类分析取决于数据之间的距离。数据的距离会受到其比例的影响,这就是为什么我们还需要转换所有的要素,使其具有相同的比例。如果你还记得,我们已经在我们的功能中的每一个单独的列都是以克为单位的,但是有一个“卡路里”列不是在同一个刻度上。这就是为什么我们仍然需要转换数据。通常我们会将数据转换为遵循标准分布,这就是我们要做的。
#Importing the transformer
from sklearn.preprocessing import StandardScaler#Transforming the data, I drop the name feature as we only need the numerical columnscaler = StandardScaler()
training = pd.DataFrame(scaler.fit_transform(data.drop('name', axis =1)), columns = data.drop('name', axis =1).columns)
这就是我们最终得到的,一个每个要素都具有相同比例的数据集。现在,让我们尝试通过聚集聚类来对数据进行聚类。首先,我们想象集群最终会如何。
from scipy.cluster.hierarchy import linkage, dendrogram#Ward is the most common linkage method
Z = linkage(training,method = 'ward')
dendrogram(Z, truncate_mode = 'lastp')
plt.xticks(rotation = 90, fontsize = 10)
plt.ylabel('Distance')
plt.xlabel('Cluster')
plt.title('Agglomerative Clustering')
上面是凝聚聚类生成的树。它只显示最后 30 个合并事件,因为如果我们在这里全部显示,它会被挤满。正如我们所看到的,数据似乎可以分为两类;当然,如果你想更保守一点,它可以分为 3 个集群,因为在上面的可视化中有证据表明它可能是这样的。尽管如此,我现在会把它保持为两个集群。
让我们回到之前的数据,将凝聚聚类结果输入到我们的数据中。
from sklearn.cluster import AgglomerativeClustering#I specify n_clusters to be 2 based on our previous analysis
ach = AgglomerativeClustering(n_clusters = 2)
ach.fit(training)#Input the label result to the data
data['label'] = ach.labels_
现在,通过无监督学习,我们实际上可以尝试将多维数据可视化成两个轴。有几种方法可以做到这一点,但我会向你展示一种叫做 t-SNE 的技术。
from sklearn.manifold import TSNE#t-SNE is based on a stochastic (random) process, that is why I set the random_state so we could repeat the resulttsne = TSNE(random_state=0)
tsne_results = tsne.fit_transform(training)
tsne_results=pd.DataFrame(tsne_results, columns=['tsne1', 'tsne2'])#Visualize the data
tsne_results['label'] = data['label']
sns.scatterplot(data = tsne_results, x = 'tsne1', y = 'tsne2', hue='label')
plt.show()
现在,我们的多维数据已经被可视化,并且凝聚聚类方法清楚地将我们的数据分成一条清晰的线。好吧,到底是什么让他们分开的?是我们需要分析的。没有简单的方法,除了再次弄脏数字。当然,可视化在这里会有所帮助。我会给出下面每一列的分布代码。
for i in data.select_dtypes('number').columns:
sns.distplot(data[data['label'] == 0][i], label = 'label 0')
sns.distplot(data[data['label'] == 1][i], label = 'label 1')
plt.title(i)
plt.legend()
plt.show()
上面是每一列的循环分布图,但是如果你喜欢用像我这样的数字;我们可以使用 DataFrame 对象中的 groupby 方法。
data.groupby('label').agg(['mean', 'median', 'std'])
结果会是上面的样子。我做了一些分析,使他们分开。以下是我的总结:
- 标签 0 表示蛋白质少、糖和碳水化合物多、纤维多、脂肪和胆固醇少的食物,热量除了 200 卡左右都是分散的。
- 标签 1 表示蛋白质多、糖和碳水化合物少、纤维少、脂肪和胆固醇多的食物,热量只分摊到 200 卡左右。
我们也可以从上面的标签看到我们有什么样的食物。
#Food label 0
data[data['label'] == 0]['food_categories'].value_counts()
标签为 0 的食品前 5 名是饮料、谷类食品、婴儿食品、汤和小吃,这是一种不含太多蛋白质和脂肪的食品。
#Food label 1
data[data['label'] == 1]['food_categories'].value_counts()
在标签 1 中,排名前 5 的食物都是肉类。这并不奇怪,因为与标签 1 相比,这个标签是针对含有更高脂肪和蛋白质的食物的。
结论
在这里,我只是试着摆弄数据,试着从数据中得到我能得到的模式。除了深入了解我的数据能为我提供什么,我没有任何具体的目标。
我们可以看到,与可视化相比,有时数字可以告诉我们更多的信息,机器学习并不总是用于预测,但也可以用于分析。
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您没有订阅为中等会员,请考虑通过我的介绍订阅。
探索感染新冠肺炎病毒动物的数据
美国农业部提供的数据分析
克里斯塔·曼古松在 Unsplash 上的照片
数据
随着病例数每天稳步上升,新冠肺炎几乎成了人们所知的每份报纸的头条新闻。尽管受到了大量的关注,但主流媒体几乎没有触及的一个话题(一些例外是农场和家养动物被感染的报道)是动物是如何受到该疾病的影响的。引用加拿大政府提供的信息,“目前关于动物和新冠肺炎的信息有限,尤其是关于动物被感染后是否会传播病毒的信息。”
科学界为了解病毒如何在动物和人类宿主中发展做出了令人钦佩的努力,关于它的研究与日俱增。然而,关于动物感染的公开数据并不容易找到。
为此,世界动物卫生组织经常在本页发布世界各地动物新病例的报告。然而,从这个来源汇编信息是一项艰巨的工作,并不是每个人都愿意/有时间从每个语句中提取数据,并从中制作一个数据集。少数向公众开放的数据来源之一是美国农业部网站。该表列出了经美国农业部国家兽医服务实验室确认的动物中的 SAR-CoV-2(导致人类感染新冠肺炎的病毒)病例。尽管在每种情况下,只有在某个机构或家庭中报告的第一种动物出现在餐桌上,因此,这是对美国有多少动物携带病毒的粗略估计。
尽管每个病例的规模很小(约 30 个数据点),但该表记录了受感染动物的类型、感染的时间和地点、检测病毒的方法以及是否与受感染的人有过接触。该表不可下载,但如果您需要,可以很容易地复制或抓取。为了让事情变得更有趣,我决定废弃它,而不是使用以下代码将其复制到 Excel 文件中:
来源:作者编写的代码从美国农业部的门户网站上删除数据。
诚然,就其预期目的而言,这是一段相当长的代码,但它完成了自己的工作,并生成了一个表,如果您愿意,可以使用 Python 来处理这个表。当然,它的可用性取决于表在添加案例时保持原样(我怀疑这是否会发生,因为随着更多数据的进入,表的大小和复杂性应该会增加)。如果你想更仔细地看看准备过程,欢迎你访问我的 Github 页面和主持整个过程的 NBViewer 。
分析
来源:作者使用美国农业部截至 8 月 17 日的动物新冠肺炎病例数据制作的图表
到目前为止,数据中的大多数动物(超过 90%)都接触过确诊或可能感染的人类。然而,根据⁴:疾控中心官网公布的信息
“导致新冠肺炎的病毒主要通过咳嗽、打喷嚏和说话时产生的呼吸道飞沫在人与人之间传播。最近的研究表明,被感染但没有症状的人也可能在新冠肺炎的传播中发挥作用。目前,没有证据表明动物在传播导致新冠肺炎的病毒中发挥了重要作用。根据迄今掌握的有限信息,动物将新冠肺炎病毒传播给人类的风险被认为很低”。
此外,疾病预防控制中心在同一份报告中继续补充说:
“我们仍在了解这种病毒,但它似乎可以在某些情况下从人传播到动物,特别是在与新冠肺炎病患者密切接触后”。
因此,数据中的案例极有可能有这个来源,尽管这不是唯一可能的解释,也可能有其他的来源。
从可能的来源转移到感染疾病的动物,受感染的动物种类相对较少,如下图所示:
来源:作者使用美国农业部截至 8 月 17 日的动物新冠肺炎病例数据制作的图表
除了几个例外(特别是在⁵布朗克斯动物园感染了这种疾病的老虎和狮子以及几只水貂),绝大多数记录在案的病例都属于猫和狗。同样,美国的病例分布仅限于少数几个州,迄今为止,50 个州中只有 12 个州报告了病例。
来源:作者使用美国农业部截至 8 月 17 日的动物新冠肺炎病例数据制作的图表
纽约州有 9 例,犹他州有 8 例,是迄今为止报道病例最多的州,其次是德克萨斯州,有 3 例。其他九个州各只有一个传染病。
来源:作者使用美国农业部截至 8 月 17 日的动物新冠肺炎病例数据制作的图表
到目前为止,7 月份是报告感染人数最多的月份,尽管尚未结束,但本月是第二个相对接近的月份,这使得上升趋势可能会继续下去。最后,值得注意的是迄今为止用于疾病诊断的方法,如下图所示:
来源:作者使用美国农业部截至 8 月 17 日的动物新冠肺炎病例数据制作的图表
大多数情况都是使用 PCR-test 来识别的,该测试由⁶FDA 授权,用于测试是否存在活性冠状病毒感染。另一种测试最常见的是检测免疫系统产生的抗体(Ab ),以阻止疾病。
结论
虽然目前还没有什么数据可以说是决定性的,但有几个趋势值得关注:
- 在长达三个月的时间里,动物感染新冠肺炎的病例一直在稳步上升,到目前为止,8 月份的病例数量表明,这种情况可能会继续下去。
- 虽然能够感染这种病毒的物种的完整名单仍然未知,但科学界一直在不间断地工作,以了解农场动物是否也能感染这种疾病。到目前为止,根据这个来源,鸭、鸡、猪对病毒有抵抗力。
- 接受测试的动物中有很大一部分在过去感染过这种病毒,并产生了抗体来对抗它。
这些信息的大部分取决于不久的将来会发生什么,所列出的趋势要么可以逆转,要么被证明是正确的。
[5]: N. Daly,布朗克斯动物园又有七只大型猫科动物冠状病毒检测呈阳性,国家地理,(2020)
探索指环王数据集上 Neo4j 图表数据科学插件的图表目录功能
了解 Neo4j 图形数据科学插件的基础知识,以及如何将图形投影到内存中
为了继续介绍 Neo4j 图形数据科学插件,我们将回顾基础知识,并查看该库的图形管理部分。这是库的一部分,负责将存储的 Neo4j 图形投影到内存中,从而允许更快地执行图形算法。图表管理部分的一个重要部分是图表目录功能。到底是什么?让我们看看的官方文件。
图形算法在图形数据模型上运行,图形数据模型是 Neo4j 属性图形数据模型的投影*。图形投影可视为存储图形的视图,仅包含分析相关的、潜在聚合的拓扑和属性信息。图形投影使用针对拓扑和属性查找操作优化的压缩数据结构完全存储在内存中。*
图形目录是 GDS 库中的一个概念,允许通过名称管理多个图形投影。使用该名称,创建的图形可以在分析工作流中多次使用。
有两个不同的选项可以将存储的图形投影到内存中:
- 本机投影通过读取 Neo4j 存储文件提供最佳性能。
- Cypher projection ,更灵活、更富表现力的方法,较少关注性能
在这篇博文中,我们将深入探讨图表目录的原生投影选项。
图形模型
我已经记不清使用 GoT 数据集的次数了,所以我决定探索互联网,搜索新的令人兴奋的图表。我偶然发现了这个指环王数据集由 José Calvo 提供,我们将在这篇博文中使用。
数据集描述了人、地点、群体和事物(环)之间的相互作用。在选择如何对此数据集进行建模时,我决定让“主”节点具有两个标签,主标签为“节点”,辅助标签为以下之一:
- 人
- 地方
- 组
- 东西
上图中,出于清晰起见,我只添加了“人”作为二级标签。我们将每本书的交互存储为一个单独的关系,这意味着第一本书的交互将被保存为交互 _1 关系,第二本书的交互将被保存为交互 _2 ,以此类推。请记住,我们将把交互关系视为无向和加权的。这些“主”节点也可以是一个职业的一部分,比如兽人、精灵、人类等等。
输入数据
如前所述,数据集在 GitHub 上可用,我们可以用LOAD CSV
语句轻松获取它。
导入节点
LOAD CSV WITH HEADERS FROM
"https://raw.githubusercontent.com/morethanbooks/projects/master/LotR/ontologies/ontology.csv" as row FIELDTERMINATOR "\t"
WITH row, CASE row.type WHEN 'per' THEN 'Person'
WHEN 'gro' THEN 'Group'
WHEN 'thin' THEN 'Thing'
WHEN 'pla' THEN 'Place' END as label
CALL apoc.create.nodes(['Node',label], [apoc.map.clean(row,['type','subtype'],[null,""])]) YIELD node
WITH node, row.subtype as class
MERGE (c:Class{id:class})
MERGE (node)-[:PART_OF]->(c)
我们向“主”节点添加两个标签的主要原因是为了优化交互关系的导入。现在,你可能会说优化是不必要的,因为我们的数据集很小,我同意,但让我们假设我们可能要处理数百万个节点。我们从定义标签“节点”的唯一约束开始。
CREATE CONSTRAINT ON (n:Node) ASSERT n.id IS UNIQUE
导入关系
既然我们已经设置了 unique 约束,cypher query planner 将使用它来更快地匹配我们现有的节点。
UNWIND ['1','2','3'] as book
LOAD CSV WITH HEADERS FROM "https://raw.githubusercontent.com/morethanbooks/projects/master/LotR/tables/networks-id-volume" + book + ".csv" AS row
MATCH (source:Node{id:coalesce(row.IdSource,row.Source)})
MATCH (target:Node{id:coalesce(row.IdTarget,row.Target)})
CALL apoc.create.relationship(source, "INTERACTS_" + book,
{weight:toInteger(row.Weight)}, target) YIELD rel
RETURN distinct true
GDS 图表目录
在图形目录中创建命名图形的语法是:
CALL gds.graph.create(graph name, node label, relationship type).
描述我们想要投影的节点
一般来说,对于本机投影变体,有三个选项来描述我们想要投影到内存中的节点:
- 使用字符串投影单个节点标签:
'Label' ('*' is a wildcard operator that projects all nodes)
- 使用数组投影多个节点标签:
['Label1', 'Label2', 'Label3']
- 使用配置图投影多个节点标签及其属性:
{ Label: { label: 'Label',
properties: ['property1', 'property2']},
Label2:{ label: 'Label2',
properties: ['foo', 'bar']}
}
关于投影节点标签,有一点需要注意:
在内存图中,所有投影的节点标签合并成一个标签。与关系投影不同,当前无法在投影标签上指定过滤器。如果该图用作算法的输入,则将考虑所有节点。
虽然我们可以过滤我们想要投影到内存中图形的节点标签,但是当前不支持在执行图形算法时额外过滤节点。
描述我们想要表达的关系
描述我们想要投影的关系的语法非常类似于节点的语法。
- 使用字符串投影单个关系类型:
'TYPE' ('*' is a wildcard that projects all relationship-types)
- 使用数组投影多个关系类型:
['TYPE1','TYPE2']
- 使用配置图投射更多关系类型及其属性:
{ALIAS_OF_TYPE: {type:'RELATIONSHIP_TYPE',
orientation: 'NATURAL',
aggregation: 'DEFAULT',
properties:['property1','property2']}
配置图中的方向参数定义了我们想要投射的关系的方向。可能的值有:
- “自然”->每种关系的投影方式与其在 Neo4j 中的存储方式相同
- 反向’–>在图形投影过程中,每个关系都是反向的
- “无向”->每个关系都以自然和相反的方向投射
需要注意的重要一点是,GDS 库支持在一个多重图上运行图算法。当我们想要将一个多图转换成一个单图(不是多图)时,聚合参数是很方便的,但是我们将在另一篇博客文章中进一步研究这个问题。
现在我们来看一些实际的例子。
整个图表
让我们首先对节点和关系使用通配符操作符,将整个图形投影到内存中。
CALL gds.graph.create('whole_graph','*', '*')
大多数情况下,我们通过运行(弱)连通分量算法来开始图表分析,以了解我们的图表实际上是如何(不)连通的。
CALL gds.wcc.stream('whole_graph') YIELD nodeId, componentId
RETURN componentId, count(*) as size
ORDER BY size DESC LIMIT 10
结果
该图作为一个整体由一个单独的部分组成。通常,您将从真实世界的数据中获得的是单个超级组件(所有节点的 85%以上)和一些小的不连接组件。
从目录中删除投影图
每次分析后,我们将从内存中释放投影图。
CALL gds.graph.drop('whole_graph');
交互图
下一步,我们想忽略关系中的部分,只关注交互 X** 关系。我们将使用一个数组来描述关系类型,以考虑所有三个interactions _ X关系。**
CALL gds.graph.create('all_interacts','Node',
['INTERACTS_1', 'INTERACTS_2', 'INTERACTS_3'])
让我们在新的投影图上运行弱连通分量算法。
CALL gds.wcc.stream('all_interacts') YIELD nodeId, componentId
RETURN componentId, count(*) as size,
collect(gds.util.asNode(nodeId).Label) as ids
ORDER BY size DESC LIMIT 10
结果
我们的新图由三部分组成。我们有一个超级组件和两个仅由一个节点组成的小组件。我们可以推断出地点“幽暗密林”和“旧森林”没有相互作用 _X 关系。
让我们使用同样的投影图,只看第一本书中的交互。我们可以使用 relationshipTypes 参数过滤图表算法应该考虑哪些关系类型。
CALL gds.wcc.stream('all_interacts',
{relationshipTypes:['INTERACTS_1']})
YIELD nodeId, componentId
RETURN componentId, count(*) as size,
collect(gds.util.asNode(nodeId).Label) as ids
ORDER BY size DESC LIMIT 10
结果
如果我们只考虑第一本书中的相互作用,我们会得到更多不相关的部分。这是有意义的,因为一些角色/地点在第一本书中还没有介绍,所以他们没有交互 _1 关系。
从目录中删除投影图
CALL gds.graph.drop('all_interacts');
无向加权交互图
在最后一个例子中,我们将展示如何投影一个无向加权图。我们将只考虑标记为 Person 和 Thing,的节点,对于关系,我们将投影所有的interactions _ X关系及其权重属性,它们将被视为无向图。
CALL gds.graph.create('undirected_weighted',['Person', 'Thing'],
{INTERACTS_1:{type: 'INTERACTS_1',
orientation: 'UNDIRECTED',
properties:['weight']},
INTERACTS_2:{type:'INTERACTS_2',
orientation: 'UNDIRECTED',
properties:['weight']},
INTERACTS_3: {type:'INTERACTS_3',
orientation:'UNDIRECTED',
properties:['weight']}});
未加权 pageRank
为了在我们的投影图上运行未加权的 pageRank,我们不需要指定任何额外的配置。
CALL gds.pageRank.stream('undirected_weighted')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).Label as name, score
ORDER BY score DESC LIMIT 5
结果
加权网页排名
为了让算法知道它应该考虑关系权重,我们需要使用关系权重属性参数。
CALL gds.pageRank.stream('undirected_weighted',
{relationshipWeightProperty:'weight'})
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).Label as name, score
ORDER BY score DESC
LIMIT 5
结果
由于弗罗多与其他角色有更多的互动(定义为重量),他在 pageRank 的加权变量中名列前茅。
第一本书的图形分析:
写完这篇博文,我们来分析一下第一本书的网络。我们首先只对第一本书的交互关系进行加权 pageRank。
CALL gds.pageRank.stream('undirected_weighted',
{relationshipWeightProperty:'weight',
relationshipTypes:['INTERACTS_1']})
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).Label as name, score
ORDER BY score DESC
LIMIT 5
结果
标准嫌疑人在最上面。佛罗多是目前最重要的角色,其次是甘道夫、阿拉贡和山姆,从排名的中心性来看,他们的重要性差不多。戒指也出现在最重要角色的前五名。
基于 Louvain 算法的社区发现
我们也对网络的社区结构感兴趣。我们将使用 Louvain 模块化算法来确定社区结构。
CALL gds.louvain.stream('undirected_weighted',
{relationshipWeightProperty:'weight',
relationshipTypes:['INTERACTS_1']})
YIELD nodeId, communityId
RETURN communityId,
collect(gds.util.asNode(nodeId).Label) as members
ORDER BY length(members) DESC LIMIT 5
结果
放下投影图
CALL gds.graph.drop('undirected_weighted');
使用 Neo4j Bloom 进行可视化
由于一张图胜过千言万语,我们就把第一本书的网络形象化。PageRank 用于确定节点的大小,community 用于确定节点的颜色。
第一次,我将使用 Neo4j Bloom 来可视化网络,因为最新版本(1.2)增加了对可视化的基于规则的样式的支持。
我们可以观察到阿拉贡和索伦、萨鲁曼是一个群体。这与实际的社区检测算法无关,但它显示了从作为共现图的文本中提取信息的弱点。我想下一步是从书中获取知识,比如朋友、敌人或其他人的关系。
结论
我希望读完这篇博客后,你能更好地理解如何用图形数据科学库来投影图形。请继续关注,因为我们仍然需要通过图表管理部分的 Cypher projection 部分。
和往常一样,代码可以在 GitHub 上获得。
探索 R 中的 gt(表格语法)包
轻松创建演示就绪的显示表格
我喜欢米格里特的前向管道%>%
操作员。在我看来,它是所有编程中最合适、最有用、最自然、几乎像反射一样的操作符之一。过去,它曾将 tidyverse 推上了数据争论的超级明星之路,现在,它正冒险进入让表格变得极其简单的任务。
gt 包是最新的雄心勃勃的条目,使 R 中的表格更容易访问、修改和复制。它的目标是成为餐桌的焦点(用哈德利的话来说,不是我的),考虑到前者对 R 即的巨大影响,这款套装肩负着巨大的压力。
这是 gt 包架构的示意图—
表格布局的语法。来源— GT 文档,R Studio
我们将使用帕尔默企鹅数据,这是现在臭名昭著的虹膜数据集的替代物。你可以在这里下载数据!
在执行基本的 tidyverse 动词后,我们调用gt()
命令并指定所需的行,以便按照所需的形状对数据进行过滤和分组。
添加柱扳手
显然,以上数据是创建的最简单、最原始的数据表。我们现在开始格式化它。我们首先添加列扳手,将公列和母列放入各自的罩中,并定制它们的字体和对齐方式。
创建行汇总统计&格式数据
我们还可以添加一个描述性统计,指定表中每个指标的平均值或总数。这可以实现相对比较,并可以产生丰富的见解。在这里,我计算了每个岛屿的年平均喙长、喙深和鳍状肢,并将数字格式化为不含小数。
添加颜色&脚注
现在有趣的部分是,我使用了通过palatteer
包提供的众多调色板中的一个,并根据表格所代表的单元格的数值对表格进行了有条件的着色。gt 包还提供了一个为表格添加脚注的功能。我在这里用它来说明测量喙长、喙深、鳍长和身体质量的标准。
添加表格标题,子标题&更改列标签
虽然颜色给桌子带来了浮力,但标题还是很有必要的。该软件包还支持在标题/副标题中使用降价文本。这里我使用了emo::ji
包在我的标题中添加了可爱的小企鹅表情符号。由于列标签仍然混乱,我还将&格式的列表重命名为一个更短、更易读的标题。
添加背景颜色&格式边框
我知道继续添加自定义颜色到剩余的空白,即标题,副标题,行平均和脚注。我已经指定了所需的十六进制代码,参考这款彩色啤酒,以获得美学建议。我还为年份行添加了虚线边框,并沿岛屿行加厚了边框,以增强区分度和可读性。
调整字体,对齐&添加源注释
作为最后的点睛之笔,为了确保字体的一致性,我在表格上使用了 Oswald 字体,并使每个单元格居中对齐。最后,在脚注下面,我添加了一个 source-note 来说明数据来源。
这就是最后的杰作!😄