票房收入分析和可视化
克里斯特·卢哈尔斯在 Unsplash 上的照片
数据科学 100 天的第 4 天和第 5 天
欢迎回到我的 100 天数据科学挑战之旅。在第 4 天和第 5 天,我在处理在 Kaggle 上可用的 TMDB 票房预测数据集。
我将首先导入一些我们在这个任务中需要的有用的库。
import pandas as pd
*# for visualizations*
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.style.use('dark_background')
数据加载和探索
一旦你从 Kaggle 下载了数据,你将有 3 个文件。因为这是一个预测竞赛,所以您有训练、测试和 sample_submission 文件。对于这个项目,我的动机只是进行数据分析和可视化。我将忽略 test.csv 和 sample_submission.csv 文件。
让我们使用 pandas 加载数据帧中的 train.csv。
%time train = pd.read_csv('./data/tmdb-box-office-prediction/train.csv')# output
CPU times: user 258 ms, sys: 132 ms, total: 389 ms
Wall time: 403 ms
关于数据集:
id: Integer unique id of each moviebelongs_to_collection: Contains the TMDB Id, Name, Movie Poster, and Backdrop URL of a movie in JSON format.budget: Budget of a movie in dollars. Some row contains 0 values, which mean unknown.genres: Contains all the Genres Name & TMDB Id in JSON Format.homepage: Contains the official URL of a movie.imdb_id: IMDB id of a movie (string).original_language: Two-digit code of the original language, in which the movie was made.original_title: The original title of a movie in original_language.overview: Brief description of the movie.popularity: Popularity of the movie.poster_path: Poster path of a movie. You can see full poster image by adding URL after this link → [https://image.tmdb.org/t/p/original/](https://image.tmdb.org/t/p/original/)production_companies: All production company name and TMDB id in JSON format of a movie.production_countries: Two-digit code and the full name of the production company in JSON format.release_date: The release date of a movie in mm/dd/yy format.runtime: Total runtime of a movie in minutes (Integer).spoken_languages: Two-digit code and the full name of the spoken language.status: Is the movie released or rumored?tagline: Tagline of a movietitle: English title of a movieKeywords: TMDB Id and name of all the keywords in JSON format.cast: All cast TMDB id, name, character name, gender (1 = Female, 2 = Male) in JSON formatcrew: Name, TMDB id, profile path of various kind of crew members job like Director, Writer, Art, Sound, etc.revenue: Total revenue earned by a movie in dollars.
让我们看一下样本数据。
train.head()
正如我们可以看到的,一些特性有字典,因此我现在删除所有这样的列。
train = train.drop(['belongs_to_collection', 'genres', 'crew',
'cast', 'Keywords', 'spoken_languages', 'production_companies', 'production_countries', 'tagline','overview','homepage'], axis=1)
现在是时候看看统计数据了。
print("Shape of data is ")
train.shape# OutputShape of data is
(3000, 12)
数据帧信息。
train.info()# Output
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3000 entries, 0 to 2999
Data columns (total 12 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 id 3000 non-null int64
1 budget 3000 non-null int64
2 imdb_id 3000 non-null object
3 original_language 3000 non-null object
4 original_title 3000 non-null object
5 popularity 3000 non-null float64
6 poster_path 2999 non-null object
7 release_date 3000 non-null object
8 runtime 2998 non-null float64
9 status 3000 non-null object
10 title 3000 non-null object
11 revenue 3000 non-null int64
dtypes: float64(2), int64(3), object(7)
memory usage: 281.4+ KB
描述数据帧。
train.describe()
让我们为发布工作日、日期、月份和年份创建新的列。
train['release_date'] = pd.to_datetime(train['release_date'], infer_datetime_format=True)train['release_day'] = train['release_date'].apply(lambda t: t.day)train['release_weekday'] = train['release_date'].apply(lambda t: t.weekday())train['release_month'] = train['release_date'].apply(lambda t: t.month)
train['release_year'] = train['release_date'].apply(lambda t: t.year if t.year < 2018 else t.year -100)
数据分析和可视化
问题 1:哪部电影的收入最高?
train[train['revenue'] == train['revenue'].max()]
train[['id','title','budget','revenue']].sort_values(['revenue'], ascending=False).head(10).style.background_gradient(subset='revenue', cmap='BuGn')# Please note that output has a gradient style, but in a medium, it is not possible to show.
《复仇者联盟》电影的收入最高。
问题 2:哪部电影的预算最高?
train[train['budget'] == train['budget'].max()]
train[['id','title','budget', 'revenue']].sort_values(['budget'], ascending=False).head(10).style.background_gradient(subset=['budget', 'revenue'], cmap='PuBu')
《加勒比海盗:惊涛骇浪》是最昂贵的电影。
问题 3:哪部电影是最长的电影?
train[train['runtime'] == train['runtime'].max()]
plt.hist(train['runtime'].fillna(0) / 60, bins=40);
plt.title('Distribution of length of film in hours', fontsize=16, color='white');
plt.xlabel('Duration of Movie in Hours')
plt.ylabel('Number of Movies')
train[['id','title','runtime', 'budget', 'revenue']].sort_values(['runtime'],ascending=False).head(10).style.background_gradient(subset=['runtime','budget','revenue'], cmap='YlGn')
卡洛斯是最长的电影,338 分钟(5 小时 38 分钟)的运行时间。
问题 4:大部分电影在哪一年上映?
plt.figure(figsize=(20,12))
edgecolor=(0,0,0),
sns.countplot(train['release_year'].sort_values(), palette = "Dark2", edgecolor=(0,0,0))
plt.title("Movie Release count by Year",fontsize=20)
plt.xlabel('Release Year')
plt.ylabel('Number of Movies Release')
plt.xticks(fontsize=12,rotation=90)
plt.show()
train['release_year'].value_counts().head()# Output2013 141
2015 128
2010 126
2016 125
2012 125
Name: release_year, dtype: int64
2013 年共有 141 部电影上映。
问题 5:人气最高和最低的电影。
最受欢迎电影:
train[train['popularity']==train['popularity'].max()][['original_title','popularity','release_date','revenue']]
最不受欢迎的电影:
train[train['popularity']==train['popularity'].min()][['original_title','popularity','release_date','revenue']]
让我们创建流行分布图。
plt.figure(figsize=(20,12))
edgecolor=(0,0,0),
sns.distplot(train['popularity'], kde=False)
plt.title("Movie Popularity Count",fontsize=20)
plt.xlabel('Popularity')
plt.ylabel('Count')
plt.xticks(fontsize=12,rotation=90)
plt.show()
神奇女侠电影具有最高的受欢迎度 294.33,而大牌电影具有最低的受欢迎度 0。
问题 6:1921-2017 年大部分电影在哪个月上映?
plt.figure(figsize=(20,12))
edgecolor=(0,0,0),
sns.countplot(train['release_month'].sort_values(), palette = "Dark2", edgecolor=(0,0,0))
plt.title("Movie Release count by Month",fontsize=20)
plt.xlabel('Release Month')
plt.ylabel('Number of Movies Release')
plt.xticks(fontsize=12)
plt.show()
train['release_month'].value_counts()# Output
9 362
10 307
12 263
8 256
4 245
3 238
6 237
2 226
5 224
11 221
1 212
7 209
Name: release_month, dtype: int64
大多数电影在九月上映,大约是 362 部。
问题 7:大多数电影在哪个月的哪一天上映?
plt.figure(figsize=(20,12))
edgecolor=(0,0,0),
sns.countplot(train['release_day'].sort_values(), palette = "Dark2", edgecolor=(0,0,0))
plt.title("Movie Release count by Day of Month",fontsize=20)
plt.xlabel('Release Day')
plt.ylabel('Number of Movies Release')
plt.xticks(fontsize=12)
plt.show()
train['release_day'].value_counts().head()#Output
1 152
15 126
12 122
7 110
6 107
Name: release_day, dtype: int64
第一次约会上映的电影数量最多,152 部。
问题 8:大多数电影在一周的哪一天上映?
plt.figure(figsize=(20,12))
sns.countplot(train['release_weekday'].sort_values(), palette='Dark2')
loc = np.array(range(len(train['release_weekday'].unique())))
day_labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
plt.xlabel('Release Day of Week')
plt.ylabel('Number of Movies Release')
plt.xticks(loc, day_labels, fontsize=12)
plt.show()
train['release_weekday'].value_counts()# Output
4 1334
3 609
2 449
1 196
5 158
0 135
6 119
Name: release_weekday, dtype: int64
周五上映的电影数量最高。
最后的话
我希望这篇文章对你有帮助。我尝试用数据科学来回答几个问题。还有很多问题要问。现在,明天我将转向另一个数据集。所有数据分析和可视化的代码都可以在这个 GitHub 库或者 Kaggle 内核中找到。
感谢阅读。
我感谢任何反馈。
100 天的数据科学进步
[## 用熊猫分析和可视化 1955 年至 2020 年的乡村人口
100 天数据科学的第 1、2、3 天。
towardsdatascience.com](/analysing-and-visualising-the-country-wise-population-from-1955-to-2020-with-pandas-matplotlib-70b3614eed6b)
如果你喜欢我的工作并想支持我,我会非常感谢你在我的社交媒体频道上关注我:
- 支持我的最好方式就是在 中 关注我。
- 订阅我的新 YouTube 频道 。
- 在我的 邮箱列表 报名。
异常检测的箱线图
小型数据科学
在上一篇文章中,我写了关于使用简单的统计技术 Z-score 检测异常值的文章。虽然这是一种创建筛选异常值的过滤器的简单方法,但还有一种更好的方法——使用箱线图。
箱线图是理解单变量和分类数据的分布、离散和变化的极好的统计技术——所有这些都在一个图中。
本文的目的是介绍 boxplot 作为异常值检测工具,我主要关注以下几个方面:
- 箱线图背后的统计直觉
- 如何在异常值检测中使用它们
- 一点点编程
箱线图:一种直觉
箱线图是可视化数据相对于中心值的分布的有效工具。我真的不认为你需要了解很多细节,但下面是一个简单的描述,给一点它如何在引擎盖下工作的直觉。如果你没有 100%得到,也不要难过。
一张图胜过千言万语,所以不要用文字来描述这个概念,只需自上而下地看一下下图,就可以建立自己的直觉。这一切都始于一个由七个观察值组成的小数据集:1,6,5,4,4,7,8。
如果把数据从小到大重新排列,中点就是中位数。中位数将数据分成两半。每一半的中点称为“四分位数”。因此,我们得到两个四分位数,第一个四分位数是上半年的中点,第三个四分位数是下半年的中点。当您从顶部开始执行这些步骤时,在图的最后部分,您会看到一个箱线图及其包含的数据。
从统计学上来说,箱线图提供了几条信息,其中两个重要的信息是四分位数,由箱线图的两端表示。这两个四分位数之间的距离称为四分位数间距(IQR)。
在下面的盒状图中,盒子的长度是 IQR,最小和最大值由胡须表示。胡须通常延伸到盒子两侧的 1.5IQR 距离。因此,这些 1.5IQR 值之外的所有数据点都被标记为异常值。
与箱线图和异常值位置相关的统计概念
如果你有正确的直觉,理解一个“离群值”是如何发挥作用的并不困难。查看下图。
通常,最小值和最大值之外的任何数据点(由框两端的胡须表示)都被视为异常值。
Python 中的示例
同样,如果你没有 100%理解统计概念,不要生气。我们可以在不了解很多机械原理的情况下驾驶汽车。但是我们必须知道如何开车!
就像知道如何开车一样,理解如何实现一个算法是业务中最重要的部分。下面是用 Python 构建编程直觉的一小段代码。
# import libraries
import numpy as np
import seaborn as sns
sns.set_style("whitegrid")# data
data = [1, 4, 4, 5, 6, 7, 8, 13]# create boxplot
sns.boxplot(y = data)
正如你所看到的,在这个箱线图中有一个异常值非常明显,我们可以很容易地过滤掉它。我们不知道异常值的确切值,但我们知道它大于 12。因此,让我们过滤那些异常值。
# filter outliers
outliers = [i for i in data if i > 12]print("Outliers are: ", outliers)
现在,箱线图将 13 检测为数据集中的异常值。这个异常值是否是一个异常,这当然是一个不同的问题,只能使用领域知识和其他技术单独回答。
结论
本文的目的是给出 boxplot 背后的统计直觉,并通过一点编程示例演示它是如何工作的。箱线图的强大之处在于,您可以“看到”极值,并通过直观的解释来决定异常值的阈值。这里的演示基于单变量数据,但对于多变量数据集和分类值,它也可以以类似的方式工作。
脑机接口——魔法师时代
随着脑机接口在社会上的实现和商业化整合,不可能的事情很快就会变成可能——准备好称自己为巫师吧。
图片通过 pixabay
正如我在的上一篇文章中所讨论的那样,在我们人类大脑中集成计算机很可能在不久的或遥远的将来成为现实。如果这还不足以让你相信这项技术已经被讨论和研究了(查看 Neuralink 和 NextMind ),那么让我们采取一种直观的、历史的方法。人类交流的历史始于公元前 500,000 年的语言起源。大约 30,000 年前,符号的发明彻底改变了交流。大约 20,000 年前,第一批岩画被创造出来,不久之后表意文字和象形文字随之而来。然后又过了几千年,书面语言才成为现实。快进到几个世纪前,接下来出现了电、电报和留声机。不久之后,电话和移动电话出现了——现在你可以通过拇指与世界上的任何人保持全天候的联系。这些发展表明,通信在各个领域都得到了越来越多的改善——可访问性、易用性、可靠性和效率。我们如何才能提高更多?免提和无语音通信——脑对脑通信。这似乎是不可避免的。
对于这篇文章的其余部分,拿一杯水,沉浸在想象中。
最终,人们只能幻想戴上这种脑机接口设备后,我们的生活会有多大的改善。最终,就像移动电话一样,这项技术将如此融入我们的生活,以至于它几乎就像是我们人体的延伸。大多数人没有意识到的一件重要事情是,每个人本质上都已经是一个电子人。我们的手机一直握在手中,电脑触手可及,它们就像是我们身体和自我的一部分。我们的沟通将如何改善?在技术层面:
- 交流的速度会加快。为了将一个想法传递给另一个人,一个人必须将这个想法压缩成可解释的东西,然后压缩并重新组织成语言,然后通过他们选择的媒介(演讲、书面语言、文本)来翻译它。跳过这一切,直接分享想法,脑对脑。
- 通信带宽会增加。与其浪费时间用文字和图片来交流思想和观点,不如直接分享想法并立刻描绘出整个画面。
- 通信的准确性将是极好的。当前交流的一个典型的准确性障碍是语言障碍。忘记学习另一种复杂的语言,努力完善它的复杂性,只是分享你的想法或想法。此外,通过使用脑机接口,你可能真的能够“设身处地为他人着想”。
目前,脑机接口应用于认知或身体残疾的患者。这里有几个如何使用它的例子:
- 腰部以下瘫痪的患者可以利用脑机接口向有缺陷的身体部位发送刺激,最终能够再次行走。就像婴儿学习如何移动手指一样,身体残疾的病人可以重新学习如何重新激活受损的身体部位。
- 患有痴呆症的老年妇女可能能够修复她的神经退化,增强她的记忆,以记住她的孙子孙女。同样,患有神经疾病的患者将有机会获得神经增强,甚至刺激神经再生,以提高他们的思维能力。这尤其与经常经历神经退化的老年人相关。
- 通过使用脑机接口重新连接神经功能或屏蔽某些记忆,给受试者带来戏剧性应激障碍后的创伤经历可能能够神奇地忘记经历。
但是,正如上一篇文章所提到的,未来脑机接口的使用不会只延伸到认知或身体残疾的人。正如第一台计算机被设计用来计算火炮射表一样,它们被证明对无数的任务和需求都是有用的。这里是不可能变成可能的地方。
用意念控制实物:
图片来自 pixabay
首先,随着脑机接口成为一种社会规范,我们目前使用的许多设备(如果不是全部的话)可能有一天会连接到接口。以下是一些简单的脑机接口使用场景:
- 你早上醒来,闹钟响着‘醒醒!’你用意念让时钟在一瞬间关闭。糟糕…外面还是一片漆黑。想象一下灯打开了,加热器开始温暖房间,咖啡壶加热到想要的温度——继续想象一下,在你跳进去之前,淋浴器打开了。你吃了一顿健康的早餐,边喝咖啡边发邮件(用心地)。工作时间到了——告诉界面锁门关灯。走出家门,你就在上班的路上了。
- 你现在正开车去上班,但一些迷人的东西偷走了你的注意力。你就要撞上另一辆车了——用你的思维在瞬间改变方向。你刚刚用你的思想避免了一场车祸,避免了将危险的想法转化为实际行动所需的处理时间。
- 不要用手操作危险的机器(如伐木机),直接用头脑操作。“思想到行动”技术的安全含义是巨大的。
- 吉他弹得很差?用你的思想去演奏它。音乐创作不仅仅是由想法决定的——它需要身心的联系来将想法转化为声音。任何人都可以成为自己的艺术家,通过脑机接口,创造力将得到极大的增强。
储存
图片来自 pixabay
如前所述,我们储存信息的能力对我们学习、成就和进步的方式有着深远的影响。以下是一些例子:
- 当你小睡一会儿的时候,写下你一直想开始写的文章。一旦你睡着了,你所有的编辑和更新都会以类似 Google Drive 的方式保存下来——全部保存在云上。
- 我们的大脑受限于储存信息的能力。想学习多门课程,但对需要记忆和学习的大量信息感到气馁?通过云端记录下来,交错在你的界面里。你想获得以后开发的信息和技能——进入界面,让它实时地用你想要的信息和技能替换不相关的信息和技能。只要有时间和毅力,任何人都可以成为 博学 。
- *这就是可怕的地方。*在前面的示例中,存储委托给了一个人。但是如果社会可以集体储存然后分享它的经验和知识会怎么样呢?每个人都可以访问(如果不是所有的东西,肯定是很多)。一个集体建造、清洗和改良的大脑。
安全:
图片来自 pixabay
这项技术的安全含义令人震惊。下面是一些基本的例子:
- 八月下旬,你的车在亚利桑那州中部抛锚了。气温超过了华氏 115 度。你手机没电了,你没水了,很可能很长时间都不会有其他人开车经过。使用你的界面拨打紧急求助电话,自救。
- 采石场工人刚刚经历了一场事故。其中一名工人不小心将一块沉重的花岗岩石头掉在了他们的一条腿上,无法触及他们的无线电——他可以向他的同事发送紧急信息,告知他的位置和状况。
- 一天晚上,天很黑,你在未铺砌的人行道上摔倒,不省人事,没有明显的呼救方式——界面正在跟踪你的神经状况,并向当地当局发出警报。你能活到明天。
心与心的交流:
图像通过 pixabay
心灵对心灵的交流——换句话说,心灵感应。人与人之间直接分享思想和观点的能力似乎是不可能的。脑机接口使这成为现实,极大地改善了我们交谈、合作和努力实现共同目标的方式。如果进步像乌龟一样移动,它现在可以像猎豹一样移动。
- 向某人解释一个困难的概念变得容易多了。当一个人参与关于抽象或概念性想法的对话时,通常很难将这些想法转化为另一方可以理解的语言。直接分享复杂的想法和想法,而无需将它们复杂而困难地翻译成语言。
- 小组会议看起来会有很大不同。“头脑风暴”将有一个新的、更直观的含义。人们将能够更有效、更准确地分享问题、想法和解决方案。更好的协作,更多的创新——进步。
- 你在疫情——法律强制要求你呆在家里,不见任何人。没问题—与您所爱的人连接到云,进行正常的对话。
- 你和你的朋友在一起。他们讨厌你发短信告诉你不要打电话。不能再发短信了?用你的思想给某人发送信息或想法。进行充分的交谈,没有打字的负担,也不会因为某人“老是打电话”而让他生气。
感官和情感交流:
图片来自 pixabay
这种类型的交流通常是最困难的。有人可能会说他们知道你在某个时刻的感受,但他们通常无法直接体验到。
如果之前事情看起来很不稳定,你就要被骗了。
有哪些脑机接口可以彻底改变这种交流方式的例子?
- 你没有时间和你的朋友去海滩,因为你必须完成那个项目。你确实有 30 分钟的休息时间,所以你利用你朋友的感官输入,通过她来替代生活。你可以闻到海浪撞击的盐味,感受到温暖的沙滩,听到放松的音乐。享受“海滩日”的新方式。
- 全国爆发了大规模抗议活动。抗议者要求所有种族之间的平等权利——虽然你在历史上被认为存在于特权群体中,但你可以挖掘那些破碎和痛苦的人的感觉,以了解那些需要帮助的人的观点。一个因同理心而强化的新世界。
- 错过了你想去的音乐会?也许你仍然可以购买数字门票,让自己沉浸在真实的体验中——听声音、感受人群、可视化等等。
- 付费观看湖人对凯尔特人的比赛。观看勒布朗詹姆斯在杰森·塔图姆上空的三分投篮。
- 还记得《T4》黑镜集里那个可以直接体验病人症状的医生吗?在那集里,他可以很容易地诊断出病人的问题,即使他自己也能体验到症状。没错。
我想你明白了。可能性和潜力的清单是不可思议的。
为什么这很重要?
脑机接口在人类智能和机器智能之间架起了一座桥梁。随着人工智能日益融入社会,我们最终可能会融合成一个电子人,并利用技术为我们服务,这似乎是相当自然的。那么,为什么不把这项技术直接集成到我们的大脑中呢?通信方法和技术的历史发展清楚地表明,下一步是脑对脑的通信——在不久的将来,我们可能会体验到它的超能力。
BrainOS——最像大脑的人工智能
应用神经科学实现更高效、更智能的人工智能。
娜塔莎·康奈尔在 Unsplash 上的照片
我们的大脑是生物神经网络。通过大数据、大计算和机器学习算法,我们可以创建非常接近真实交易的人工神经网络。
例如,革命性的 GPT-3 模型可以写文章欺骗 88%的读者认为它是人类,它可以写代码、诗歌、歌词、模因,等等。
然而,我们仍然没有达到开启超级智能的“光开关时刻”——也看不到它。
神经科学可以提高人工智能
这是 BrainOS(一种新颖的类脑 AutoML 框架)所基于的前提。原因很简单:我们的大脑是已知最强大的处理器,因此我们至少应该测试我们的大脑(看起来)为 AI 的运行而运行的原理。
作为效率的题外话,让我们比较一下大脑和人工智能。毕竟,大脑是我们衡量人工智能准确性的基准,所以让我们粗略地看一下效率。
大脑每天消耗 300 卡路里。在特斯拉 V100 上训练 GPT-3 需要花费 355 年(310 万小时),特斯拉 V100 单独消耗 300 瓦。乘以瓦特/小时乘以训练小时总数得到 933 兆瓦。这等于 8020 亿卡路里。
NVIDIA 估计人工智能 80–90%的能源成本在于推理——在训练后使用模型。仅计算 GPU 成本,GPT-3 的成本高达 7.2 万亿卡路里。
哎哟。
BrainOS 目前还没有用于生产(我们稍后会提出建议),但目前有一些提高效率的尝试。
首先,脉冲神经网络是一种类似大脑的提高效率的方式,但它们不能提供 BrainOS 将带来的与 AutoML 相同的好处。
神经网络是用来识别模式的大脑的简化模型,但是它们浪费了大量的计算…
medium.com](https://medium.com/bitgrit-data-science-publication/spiking-neural-networks-a-more-brain-like-ai-6f7ad86b7e7e)
虽然 BrainOS 仍然是一个研究项目,但有许多功能性的 AutoML 工具,如 Apteo 。有关 AutoML 的更多信息,请查看本指南:
AutoML 越来越受欢迎。这就是事情的变化。
towardsdatascience.com](/will-automl-be-the-end-of-data-scientists-9af3e63990e0)
BrainOS 如何工作
BrainOS 通过以下属性自动选择合适的 ML 模型:
- 它给出的数据
- 先前的经验
- 世界知识
BrainOS 不仅仅与我们对大脑如何工作的想法有着松散的联系,它还试图对神经元行为进行建模。
“该系统的结构和操作受到神经元细胞行为的启发.”
体系结构
高层架构非常简单:输入数据(来自任何来源)与问题上下文和目标相结合。鉴于此,要么创建一个新模型,要么选择一个现有模型进行训练,然后部署该模型。
高级 BrainOS 架构。作者可视化。
详细组件
问题形式化是系统的切入点,包括上面的“输入数据”框。接下来,critic(或 qualifier)组件通过添加早日期数据集来增强输入数据,并通过应用资格来实现中间数据。
受大脑自适应学习特性的启发,历史数据库结合了历史(或遇到的数据集的经验)和世界知识(或存储的知识以及抽象研究)。
规划器组件简单地规划算法的执行顺序,或者系统的流程。并行执行器是任务调度器,它决定如何高效地执行线程。
模块调度器接收由上述并行执行器发送的线程,计划执行时间表。
选择器是 BrainOS 的关键组件,它通过并行执行许多步骤来挑选出正确的模型:搜索 BrainOS 的历史,搜索研究数据集,从头开始构建工具,并通过组合几个模型来执行集成学习。然后选择最适合的模型。
深度认知神经网络(DCNN) —实现 BrainOS
DCNNs 是在现实世界中实现 BrainOS 的一种方案。
与典型的神经网络不同,DCNNs 表现出感知和推理能力,并能够在小型设备(如智能手机)上进行近实时的大数据分析。此外,它们的能效极高,比类似的深度神经网络高出 300 倍。
市场上还没有任何基于 DCNN 的 AutoML,但鉴于传统深度网络对计算、数据和能源的极高要求,我相信我们很快就会看到它们。
打破障碍,成为一名宝贵的数据科学家
一个有价值的数据科学家长什么样?建议以最有效的方式开始你的数据科学生涯。
来源:默特萨洛夫
H
这是一个很常见的抱怨,我从我的朋友、同事,尤其是年轻人那里听到了很多次。几年前,在我职业生涯的初期,我也是这个陷阱的受害者。现在,我意识到这是数据科学家的一个真正的瓶颈,我想与他人分享我的经验,以便帮助其他数据科学家实现更光明的职业生涯。
每当我遇到其他数据科学研究员,大部分时间都花在谈论 RNN、NLP、深度学习或机器学习算法上。但是当我问他们为什么使用 RNN 而不是深度学习,或者他们的模型如何支持业务时,他们要么提供一个没有说服力的理由,要么停留在对概念和算法的冗长解释上,而没有全面的商业思维。
对于数据科学家来说,饱和于技术模型而低估商业思维的作用是一种惯例。然而,我完全不否认数据科学家的技术工作的不可或缺的作用,我只是想强调在任何其他活动 之前,首先 理解业务概念的重要性。
因此,我在下面列出了开始数据科学项目的标准流程和关键点,这是我作为数据分析师和数据科学家在两家跨国公司工作的 4 年中一直在应用的。
这篇文章是根据我的经历写的。因此,把它作为你的参考,并根据自己的需要进行调整。
1.首先也是最重要的一点——澄清业务问题
在我从事分析和数据科学的这些年里,除了技术概念解释,业务问题澄清是数据科学家与业务合作伙伴沟通时最困难的任务之一。
我相信你在很多文章里都能听到这句话,提醒你在任何情况下都要澄清商业问题。
但是怎么做呢?
工作和研究是不同的。在商界,高层人士从未停止期待数据科学家成为一个知道他们所有问题答案的智者。因此,挖掘问题是我们的工作,如何去做是我们的责任。
当一个销售经理问你“我想知道为什么销售额下降了”的时候,你一定非常熟悉。或者一位营销总监要求“如何提高品牌 A 在我们网站上的促销活动的效率?”
当你听到这些问题时,你是如何想象解决方法或答案的?你会不会不确定,一直问自己*“是他们想让我这么做吗……”还是“我想他们想知道那个……”*?如果你基于这种理解来交付成果,你对自己的交付有多少信心?
事实上,如果你一直这样,你将从他们那里得到的唯一回应是:
“这不是我需要的”
OMG!当你花了这么多心血在这上面,却没有人重视,这是多么可怕。
这是因为你没有真正理解问题,所以没有触及痛点!
例如,主管想知道提高其营销活动功效的方法,那么功效在这里是什么意思?他指的是哪种活动?真正的痛点是什么?如果清楚地阐明这些问题,该请求将被解释为*“如何优化在线推广的预算支出,以提高购买率和新客户数,与去年相比”。*这最终会增加疗效。
一个常见的建议是问 【为什么】 以便挖掘真正的问题。但是,这种解决方案并不总是适用的,因为业务合作伙伴可能不知道您所有问题的原因。
你还能做些什么:
- 询问问题的背景,在你收到请求后,他们为什么以及如何提出请求。
- 确定你有责任回答这个请求。如果你的公司有数据科学家、数据分析师、BI 等几个数据团队,一定要搞清楚每个团队的角色&职责,知道什么时候跳进去,什么时候跳出来。然而,永远不要说“这不是我的工作。问毕”。相反,向他们展示你对公司和数据了如指掌*“根据你的要求,BI 团队已经获得了可以帮助你解决问题的数据,我建议你与 BI 会面,并索要过去 3 年的销售和流失率数据”*。
- 与公司的其他团队合作,经常获得公司内部发生的其他事情的最新消息。此外,始终提出诸如“最新的公司战略、日程表、当前的关键项目和最近的业绩是什么?”这样的问题也是非常重要的或*“我是否了解对我的公司至关重要的项目的愿景和目标?”*
- 想出一些计划,以及在你的专业知识范围内你还能做些什么来将项目提升到一个新的水平。
做一个思想家,而不是一个实干家!
2.确定解决问题的方法
这一部分是为分析提供方法论。
这一步需要对统计模型或机器学习方法有广泛的了解。在一些公司,尤其是非技术通,数据科学家负责分析和数据科学工作流。
随着分析和数据科学的混合作用,解决问题的方法也将随着各种概念和模型而多样化。例如:线性回归不能用于细分客户,或者描述性分析不能预测客户流失。
起初,选择方法似乎毫不费力,但确实总是让你抓狂。如果销售总监要求数据科学团队根据预算支出金额预测下一年的 销售额,同时将在线外观作为公司的重点 ,那么应该使用哪种方法/模型?如果企业希望基于市场运动的预测 能够维持当前公司的领导地位 ,哪种方法是正确的?
您可以做得更多:
- 理解描述性分析和预测性分析 之间的差异是的基础(很多人仍然对这两个概念不清楚)。描述性分析的一个例子是因素之间的关系;而规定性分析则处理计算这种关系的未来结果。描述性分析提供历史洞察力,而规定性分析预见未来价值。
- 确定数据的具体类型以帮助解决问题 : 目标变量和其他变量是连续的、分类的或二元的。
- 了解关键问题的方法:
- 二元 (2 种可能答案)或多类(2 种以上可能答案)分类;
- 回归关系(2 个或 2 个以上因素之间的关系)或回归预测(利用回归模型预测未来值);
- 聚类(将未标记的观察值聚类成具有相似特征的组)或分割(将观察值分成特定的组);
- 趋势检测(历史运动)或时间序列预测(预测该运动的未来值)。
3.获取适当的数据
在确定了业务问题和上述方法之后,接下来的事情就是建立数据需求并从数据仓库中提取适当的数据。
数据选择听起来很简单,但确实很复杂。为了解决业务问题,需要哪种数据。比如预测流失概率的任务,有没有必要有客户的生日信息?
摄取足够的数据将会为您节省大量的精力。记住一个不言而喻的事实:垃圾进来就是垃圾出去。
在数据收集过程中通常会出现两个主要问题
1.数据的不可用性
2。训练数据的偏差
3.1 首先,我们来看看数据不可用
这个问题在全球非常普遍,由于当前数字连接的限制,数据无法在收集时获取。例如,仅仅是不可能获得在家做饭的时间。
作为一个常识,当数据不存在时,你会立刻想到获取数据的方法。但是,您必须考虑不可用数据的后果,包括成本、时间、资源,如果数据对您的模型确实不太重要,您投入的所有努力都将付诸东流。
因此,这种情况的解决方案是暂时推迟不可访问的数据,如果模型需要这些数据以获得更好的结果,您将有更多的资源和信心在未来投资获取这些数据。
如果需要更多数据,您还可以做些什么:
- 拜访数据库所有者时,如果您需要就此与其他方沟通,请携带一份数据请求摘要。总结形式应该包括你的项目背景,数据要求,你的要求。这将有助于顺利讨论,业务合作伙伴将给出适当的解决方案。
- 改变收集数据的过程/方法以获取所需的正确信息。与数据库所有者或 IT 团队合作,或向您的上级提出系统修订计划以供批准。
- 准备预算,如果额外数据对改进模型至关重要且您无法获得,请联系外部数据所有者。
3.2 第二,数据的偏差
当训练集从一开始就有偏差时,这个问题尤其严重。因此,模型将根据偏差进行学习,并在与真实世界进行比较时返回不准确的预测 。
数据偏见最著名的缺陷之一是亚马逊招聘人工智能工具显示了对女性的偏见。该工具审查候选人的简历,以便从中挑选出最优秀的人才。该工具显示出对女性的明显偏见,因为它的训练数据从一开始就不是性别中立的。
因此,首先,小心数据及其自然分布是每个数据科学家的重要职责。
你可以做些什么来消除偏见:
- 确保数据及其代表在人口中的统计分布。例如,如果人口由 56%的男性和 43%的女性以及 1%的其他人组成,则数据分布必须具有相似的比例。
- 验证训练的分割,验证和测试预测模型中的集合以建立类似的变量和类别分配。
- 选择适合问题的学习模型,降低偏度。一些模型可以减少数据中的偏差,包括聚类或降维
- 监控实际数据中的性能。经常对真实数据进行统计测试,以找出不常见的情况。如果测试结果显示男性的流失率比女性高,那就把它挖出来。是突然转变还是偏差的结果?
获得所需的所有数据后,下一步是数据科学家通常会做的事情:
顺序可以是灵活的,这是我在项目和工作中通常采用的标准进度。有时,在调优后,精度没有达到我的期望,我会回到特性工程步骤,寻找其他方法来处理特性。
这些是除了技术技能之外的关键瓶颈,我希望数据科学家能够超越数据洞察提取器。
分解 R 中的地理编码:完全指南
可视化|地图
如何使用 API 找到您感兴趣的地方,并在地图上可视化其位置
如果您想知道如何构建类似于您在应用程序中经常看到的地图,这可能是一个好的起点。在本教程中,我们将介绍如何根据描述或坐标找到一个地方,以及如何根据这些信息构建一个简单的地图。
请注意,本文假设读者对 R 语言有一定的了解:数据结构、操作符、条件语句、函数等等。本教程的所有代码都可以在 GitHub 上找到。
所以,让我们开始吧!
照片由 Julentto 摄影在 Unsplash
什么是地理编码?
地理编码是将一个地方的地址或名称转换成其坐标的过程。反向地理编码执行相反的任务:根据一个地方的坐标返回该地方的地址或描述。
仅此而已,就这么简单。因此,通过使用地理编码,您必须能够说在法国巴黎的埃菲尔铁塔可以在(48.858568,2.294513)纬度、经度坐标找到。在你的地图应用上输入(41.403770,2.174379),你将到达西班牙巴塞罗那的圣家族教堂罗马天主教堂。你可以自己核实——只需在谷歌地图上输入这些信息。
有哪些地理编码工具可用?
当谈到在线免费地理编码工具时,其中一个选项是专门的网站。比如上面提到的谷歌地图。稍微搜索一下,就能找到其他的。
如果你只需要找到几个地址,所有这些都是非常好的工具。但是想象一下有几百个呢?那成千上万呢?这项任务很快变得相当令人头痛。
对于批量请求,API 是更合适的选择。而这里最明显的选择大概就是谷歌地图 API 。为了能够使用谷歌服务,你需要在谷歌云平台上创建帐户,并获得你的 API 密钥。谷歌在他们的网站上提供了关于如何做的详细的说明。
另一个选择是使用来自 OpenStreetMap 的一个名为nomim的公共 API。OpenStreetMap 是一个合作项目,其目标是为公众创建一个免费的地图服务。正如其网站所说:
OpenStreetMap 是由一个地图绘制者社区构建的,该社区贡献并维护世界各地的道路、小径、咖啡馆、火车站等更多信息。
基本上,nomist 是一个在 OpenStreetMap 网站上进行搜索的工具。与谷歌地图不同,Nominatim 不需要你注册任何账户,也不需要你获得一个 API 密匙。但如果你想在应用程序中使用它的服务,你需要提供一个电子邮件地址,这样你的应用程序的活动就可以被跟踪,并在需要时受到限制——OSM 服务器的能力是有限的。
法律考虑
你可能会奇怪,如果 Google 提供了类似的功能,为什么我首先要告诉你关于 Nominatim API 的事情。你的第一个猜测可能是成本——与 OpenStreetMap 基金会不同,谷歌是一家私人公司,对其服务收费。这是事实,但只是部分事实。
首先,如果你现在在谷歌云平台上注册,你将获得 12 个月的免费试用,你的账户上有 300 美元的信用来了解它的功能。其次,即使在那之后,谷歌也免费提供一些最常用服务的有限访问权限,作为永远免费套餐的一部分。如果你的唯一目的是学习,那么这个包里的限制就足够了。要了解更多关于谷歌地图 API 定价的信息,请访问谷歌的帮助页面。
那么,你会问我什么问题?谷歌地图平台服务条款,其中声明:
3.2.4 对滥用服务的限制。
【一】 **无刮。**客户不得提取、导出或以其他方式抓取谷歌地图内容用于服务之外。
©不从谷歌地图内容创建内容。
【e】非谷歌地图不使用。
我不是法律界人士,不知道谷歌如何对待非商业目的使用其服务。但是我没有在这些服务条款中看到任何条款说明上述限制只适用于商业用途。所以,在你决定在你的应用中使用谷歌地图 API 之前,请注意这些限制。
与谷歌地图不同,OpenStreetMap 数据是在开放数据共享开放数据库许可证(ODbL)下获得许可的。正如作者自己所说,下面是 ODbL 1.0 的人类可读摘要 :
您可以自由:
***分享:**复制、分发和使用数据库。
- **创作:**从数据库中产生作品。
- **适应:**对数据库进行修改、改造和建设。
只要你:
- **属性:**给原数据库做参考。
***Share-like:**在相同的许可下分发由原数据库改编的数据库。- **保持开放:**向公众开放对适配数据库的访问。
一个全长许可,如果你想看的话,可以在开放数据共享网站上找到。
说了这么多,现在让我们继续编码!
安装软件包
让我们先安装并加载本教程中用到的所有包,所以以后不用担心。每个包的用途将在文章的相应部分描述。另外请注意,我们使用的是适用于 Windows 的软件版本 R 3.6.2。
***# install packages***
install.packages("ggmap")
install.packages("tmaptools")
install.packages("RCurl")
install.packages("jsonlite")
install.packages("tidyverse")
install.packages("leaflet")***# load packages***
library(ggmap)
library(tmaptools)
library(RCurl)
library(jsonlite)
library(tidyverse)
library(leaflet)
使用 R 包进行地理编码
R 社区创建了几个包,可以用来访问 Google Maps 和 nomist API。让我们看看它们。
包 ggmap
第一个包叫做 ggmap ,它允许你连接到谷歌地图 API。在开始使用这个包之前,您需要向 R 提供您的 API 密钥。
***# replace "api_key" with your API key*** register_google(key = api_key)
现在让我们在 12 家伦敦酒吧的样本上使用这个包中的geocode
函数来演示它是如何工作的。该函数接受以下任一参数作为其output
参数:
- latlon —经纬度;
- latlona —以上所有加地址;
- 更多 —以上所有加地点的类型和地理界限;
- 全部 —以上全部加上一些附加信息。
每个选项对应于生成的信息类型。一般来说,我们不需要比更多的选项提供的信息。
运行 ggmap 地理编码功能
让我们看看我们的结果。正如你所看到的,我们有一个酒吧的名字,它的坐标,地点的类型,结果的精度( rooftop 意味着谷歌能够找到一个具体的建筑)和它的地址。
运行 ggmap 地理编码功能的结果
现在,让我们用刚刚找到的坐标对它们所属的地方进行反向地理编码。
revgeocode
函数允许这样做。它需要两个参数:location
—经度/纬度的数值向量和output
—或者地址或者全部。选项 all for output
返回的信息比我们需要的多得多,所以让我们坚持使用地址。
这次我们将把结果存储在一个列表中,而不是数据框中。这个列表的每个元素将包含另一个列表,其中包含关于酒吧的名称、坐标和地址的信息。
运行 ggmap 反向地理编码功能
运行 ggmap 反向地理编码功能的结果
ggmap 到此为止。现在让我们进入下一个项目。
打包 tmaptools
tmaptools 是一个包,它提供了一套读取和处理空间数据的工具。它促进了另一个名为 tmap 的 R 包的功能,该包是为可视化专题地图而构建的。许多 tmaptools 函数依赖于 Nominatim API。
现在,让我们试着从 tmaptools 获得与使用 ggmap 提取的信息相同的信息。我不得不稍微修改一些搜索请求,因为 Nominatim 无法找到基于它的位置。尽管我尽了最大努力,还是找不到其中一家酒吧——荣耀酒吧。因此,请注意,不同的服务提供商的数据质量和完整性可能会有所不同。
运行 tmaptools 地理编码功能
我们在最终表中只包括坐标和完整地址。这是它的样子。
运行 tmaptools 地理编码函数的结果
现在,是反向地理编码的时候了。在我们的输出中,我们将显示与来自 ggmap 的反向地理编码请求完全相同的信息。
运行 tmaptools 反向地理编码功能
运行 tmaptools 反向地理编码功能的结果
这是我们讨论 R 地理编码包的最后一段代码。在这里你可以读完这篇文章,然后自己练习上面描述的一些技巧。除非…除非你想了解更多!如果是这样,那我们继续!
使用 API 进行地理编码
使用包是一种非常方便快捷的完成事情的方式。对于您想要完成的大多数任务,这些包提供的功能已经足够了。然而,如果你需要一些额外的东西,或者你对其他 API 函数感兴趣,或者你只是想学习如何使用 API,你需要去 Google/nomist 帮助页面做一些阅读。或者在网上搜索一些像这样的视频/教程,提供简短的总结。或者更好——双管齐下。
谷歌地图 API
看了 ggmap 包之后,现在让我们尝试直接使用 Google Maps API 来获取这个地方的位置、地址以及它的电话号码和网站。为了完成这个任务,我们需要地理编码 API 和位置 API 。
地理编码 API
地理编码 API 是一种提供地址和地点的地理编码和反向地理编码功能的服务。您可以通过 web 浏览器发送 HTTP 请求来访问地理编码 API,并获得 JSON 或 XML 格式的响应。虽然,在我们的例子中,我们将从 r。
地理编码 API 请求采用以下格式。
***# format***
[https://maps.googleapis.com/maps/api/geocode/outputFormat?parameters](https://maps.googleapis.com/maps/api/geocode/outputFormat?parameters)***# geocoding example***
[https://maps.googleapis.com/maps/api/geocode/json?address=The+Churchill+Arms,+Notting+Hill&key=YOUR_API_KEY](https://maps.googleapis.com/maps/api/geocode/json?address=The+Churchill+Arms,+Notting+Hill&key=YOUR_API_KEY)***# reverse geocoding example***
[https://maps.googleapis.com/maps/api/geocode/json?latlng=51.5069117,-0.194801&key=YOUR_API_KEY](https://maps.googleapis.com/maps/api/geocode/json?latlng=51.5069117,-0.194801&key=YOUR_API_KEY)
因此,您发送的 web 请求由几个部分组成 API url 后跟outputFormat
(json 或 xml)和列表parameters
。outputFormat
和parameters
之间隔着一个问号(?)和parameters
本身被一个&符号(&)彼此分开。
请求所需的参数包括:
- 对于地理编码:
address
—地址或地名形式的搜索查询和key
— API 关键字; - 对于反向地理编码:
latlng
—您搜索的地点的纬度和经度,以及key
— API 关键字。
我们不会在查询中使用任何可选参数。
你可以在这里和这里阅读更多关于如何构造 API 请求的信息。
值得一提的是,如果你正在构建自己的应用程序,需要实时访问谷歌地图服务,你可以检查谷歌客户端( JavaScript )或服务器端( Java,Python,Go,Node.js ) API。
地点 API
如果您不想只局限于地点的地址和坐标,您可以使用 Places API。例如,要查找某个地方的电话号码和网址,我们需要使用地点搜索 来获取地点 ID ,并在以后使用它从地点详细信息中检索该信息。
在进行 API 调用时,确保提供您想要提取的fields
的列表。否则,谷歌将发送所有这些邮件,并向您收取相应费用。在我们的情况下,这并不重要,因为我们不会超过免费限额,但是如果您计划 对大量请求使用 API,您可能会因此而被收费。
对于 Place Search/Place Details API 调用,您还需要提供outputFormat
(json 或 xml),后跟一个列表parameters
。
对于地点搜索,所需的参数包括:input
—姓名、地址或电话号码(坐标不起作用);inputtype
— 文本查询或电话号码;key
— API 键。
对于地点细节,需要的参数是:place_id
—可以通过使用地点搜索找到;key
— API 键。
对于地点搜索和地点详细信息,我们将使用可选参数fields
——我们希望 Google 返回的附加信息的逗号分隔列表。您可以在前面提供的相应帮助页面上阅读有关可能选项的更多信息。但是在我们的例子中,我们只需要来自地点搜索的字段 place_id 和来自地点详细信息的 formatted_phone_number 加上网站。请记得阅读有关账单的信息!
API 调用的格式如下所示。
***# PLACE SEARCH******# format***
[https://maps.googleapis.com/maps/api/place/findplacefromtext/outputFormat?parameters](https://maps.googleapis.com/maps/api/place/findplacefromtext/outputFormat?parameters)***# example***
[https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input=The+Churchill+Arms,+Notting+Hill&inputtype=textquery&fields=photos,formatted_address,name,place_id&key=YOUR_API_KEY](https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input=The+Churchill+Arms,+Notting+Hill&inputtype=textquery&fields=photos,formatted_address,name,place_id&key=YOUR_API_KEY)***# PLACE DETAILS******# format***
[https://maps.googleapis.com/maps/api/place/details/outputFormat?parameters](https://maps.googleapis.com/maps/api/place/details/outputFormat?parameters)***# example***
[https://maps.googleapis.com/maps/api/place/details/json?place_id=ChIJGTDVMfoPdkgROs9QO9Kgmjc&fields=formatted_phone_number,website&key=YOUR_API_KEY](https://maps.googleapis.com/maps/api/place/details/json?place_id=ChIJGTDVMfoPdkgROs9QO9Kgmjc&fields=formatted_phone_number,website&key=YOUR_API_KEY)
同样,如果您考虑构建一个实际的应用程序,那么值得看看用于服务器端应用程序的 Java/Python/Go/Node.js 客户端或用于 Android 的Places SDK、用于 iOS 的Places SDK和用于客户端应用程序的 Places Library、Maps JavaScript API 。
使用谷歌地图 API 进行地理编码
说了这么多,现在让我们来编写代码本身。
我们的代码由七个函数组成:
- 一个主要功能;
- 用于生成 API 调用的三个函数;
- 从 JSON 输出中提取数据的三个函数。
我们的主函数有三个参数:
search_query
—搜索请求(地址或地点);fields
—提取信息(坐标,地址,联系人或全部);key
—谷歌地图的 API 键。
第一个和最后一个是必需的,第二个是可选的,默认坐标。
这些参数可以是以下类型:
search_query
—字符串、字符向量、字符列表、一维矩阵或带有字符串数据的数据帧;fields
—字符串、字符向量、字符列表;key
—弦。
根据fields
的值,该函数返回一个数据帧,其中包含:
- 坐标 —经纬度;
- 地址 —完整的地址和城市;
- 联系人 —电话号码和网址;
- 全部 —以上全部。
现在让我们来详细看看这个函数的每个组件。
正在生成 API 调用
一旦熟悉了我前面提供的信息,API 调用函数就非常简单了。
它分三步工作:
1.将搜索查询转换为列表。
2。对搜索查询进行百分比编码。
3。构造 API 调用字符串。
第一步是必需的,因为处理公共数据结构(在我们的例子中是一个列表)总是更容易。对于百分比编码,我们使用 RCurl 包中的URLencode
函数。如果你不知道它是什么,访问这个页面有详细的解释。
谷歌地图 API 调用函数
从 JSON 中提取数据
Google 可以返回两种格式的数据——JSON 和 XML。在我们的例子中,我们使用 JSON 输出。这个输出需要转换成 R 对象,所以我们可以很容易地操作它包含的数据。一旦完成,我们的任务就是从格式化的列表中挑选我们需要的元素。
原始 JSON 输出及其格式化版本如下所示。
Google Maps API 的原始 JSON 输出
Google Maps API 的格式化 JSON 输出
那么,我们的函数是如何工作的呢?首先,使用 jsonlite 包中的fromJSON
函数将 JSON 输出转换成 R 列表。之后,我们的函数检查 API 调用是否成功(status = "OK"
),如果成功,它从列表中只提取我们需要的元素来构建最终的数据帧。检索一个城市名称有点棘手,因为首先我们需要找出它存储在address_components
中的序列号。对于联系人来说,将所有NULL
替换为NA
也很重要,如果谷歌没有关于电话号码或网站的信息,就会出现所有的NULL
,这样我们在生成最终数据帧时就不会出错。
将 JSON 输出转换成 R 对象的函数
主要功能
我们已经提供了我们的主要功能的描述。现在让我们解释一下它是如何工作的。
首先,该函数从谷歌地图获取坐标和地址。它检查用户是否真的想要这个信息(即fields
参数中存在坐标和/或地址),如果是,它调用url_google_geocoding
函数来构建 API 调用,并从 RCurl 包中调用getURL
函数来实际创建它。
在我们收到 Google 的响应后,我们需要使用get_geodata_from_json_google
函数将其从 JSON 格式转换成 R 列表。一旦完成,结果将存储在geodata_df
数据帧中。
之后,对联系人重复相同的程序(即电话号码和网站)。仅此而已。
这是代码。
使用 Google Maps API 进行地理编码的主要功能
现在,我们终于可以调用我们的函数并检查结果了。
***# replace "api_key" with your API key***
pubs_google <- geocode_google(pubs, "all", api_key)***# check results***
pubs_google
运行地理编码功能的结果—Google Maps API[第 1-5 列]
运行地理编码功能的结果—Google Maps API[第 6–7 列]
使用谷歌地图 API 进行反向地理编码
下面是几乎相同的功能,但反向地理编码。这一次,它只返回基于地点坐标的地址。我在这里没有给出任何详细的解释,因为到现在为止,你已经能够自己理解代码了。
除了key
参数,主函数还需要coordinates
作为输入,可以是:
- 带有纬度和经度的向量(单个请求);
- 纬度/经度向量的列表;
- 有两列的矩阵——纬度和经度;
- 包含两列(纬度和经度)的数据框。
该函数接受数值和字符串值作为coordinates
。
请注意,每次我们调用时,Google 可能会返回几个结果,但我们只使用第一个结果— results[[1]]
—它对应于 Google 认为的最佳匹配。
另外,对要从 R 列表中提取的元素的硬编码引用也要小心。例如,在我们的例子中,第 5 个元素$address_components[[5]]$long_name
可能指的是城市—伦敦($address_components$types = "postal_town"
)、二级行政区—大伦敦($address_components$types = "administrative_area_level_2"
)或一级行政区—英国($address_components$types = "administrative_area_level_1"
)。因此,在这种情况下,我们必须遍历 R 列表,找到我们需要的信息的types
,并提取相应的long_name
。
反向地理编码功能(谷歌地图 API)
下面是在伦敦酒吧样本上运行这个函数的结果,我们之前从同一个 API 获得了这些酒吧的坐标。
***# extract coordinates from pubs_google***
pubs_google_crd <- pubs_google[ , c("lat", "lng")]***# replace "api_key" with your API key***
pubs_rev_google <- rev_geocode_google(pubs_google_crd, api_key)***# check results***
pubs_rev_google <- cbind(pubs_df, pubs_rev_google)
pubs_rev_google
运行反向地理编码功能的结果— Google Maps API
命名 API
现在让我们把注意力转向 OSM 的提名 API。
nomimsearchAPI 允许您根据描述或地址查找特定位置。它支持结构化请求和自由文本请求。搜索查询还可以包含对应于特定 OpenStreetMap 标签的特殊短语、、。在我们的例子中,这个特殊短语是一个“pub”。
反向地理编码 API 从一个地方的纬度和经度生成一个地址。
API 调用的格式如下所示。
***# geocoding format*** [https://nominatim.openstreetmap.org/search/](https://nominatim.openstreetmap.org/search/)<query>?<params>***# geocoding example*** [https://nominatim.openstreetmap.org/search/The%20Churchill%20Arms,%20Notting%20Hill?format=json&polygon=1&addressdetails=1](https://nominatim.openstreetmap.org/search/The%20Churchill%20Arms,%20Notting%20Hill?format=json&polygon=1&addressdetails=1)***# reverse geocoding format*** [https://nominatim.openstreetmap.org/reverse](https://nominatim.openstreetmap.org/reverse)?<query>***# reverse geocoding example*** [https://nominatim.openstreetmap.org/reverse?format=json&lat=51.5068722&lon=-0.1948221&zoom=18&addressdetails=1](https://nominatim.openstreetmap.org/reverse?format=json&lat=51.5068722&lon=-0.1948221&zoom=18&addressdetails=1)
一些参数对于地理编码和反向地理编码调用都是通用的:
format
=[html | XML | JSON | JSON v2 | geo JSON | geocode JSON]—输出格式;addressdetails
= [0|1] —将地址分解成元素;extratags
= [0|1] —附加信息(维基页面、开放时间等)。);accept-language
—以何种语言显示搜索结果(English = en);email
—除非您提供一个允许跟踪您活动的电子邮件地址,否则您将无法在您的应用中使用 API(会出现错误消息)。
有些参数是每个 API 特有的。
搜索:
query
—自由文本或地址;countrycodes
—通过 ISO 3166-1 alpha-2 国家代码(英国= gb)限制搜索;limit
—限制返回结果的数量。
反转:
query
= lat,lon — in WGS 84 格式;namedetails
= [0|1] —在结果中包含替代名称列表;zoom
=[0–18]—地址所需的详细程度(默认值为 18,即特定的建筑物)。
query
、format
和email
为必选参数,其余为可选参数。我们不会在我们的函数中使用namedetails
参数,也不会改变zoom
参数的默认值——我提供它们只是供您参考。
这里一个重要的方面是标签的使用,它指向 OpenStreeMap mappers 提供的特定信息。这些标签中有一些是重复的(像电子邮件和电话和网站与联系人名称空间中的类似标签),所以不同的人可能会用不同的标签来标记同一类信息,你需要在你的应用程序中说明这一点。
还有一些要求,您必须遵守这些要求才能使用提名服务:
- 限制同一网站/应用程序发送的请求数量——每个应用程序每秒一个请求;
- 不鼓励对大量数据进行批量地理编码,但允许较小的一次性任务(我们的例子);
- 搜索结果必须被缓存,所以不要多次发送相同的请求。
使用命名 API 进行地理编码
下面的函数复制了我们为 Google Maps API 构建的函数,所以我们不会详细描述它。
唯一显著的区别是我们添加了两个额外的可选参数:country
,它对应于 API 调用的countrycodes
参数,用于将您的搜索限制在某些县(默认情况下不使用)和language
,它对应于accept-language
参数,允许您选择显示结果的语言(默认为英语)。两个参数都需要以字符串的形式提供:country
作为逗号分隔的代码列表(例如“gb,dr,fr”),而language
作为单个值(例如“es”)。
地理编码功能(命名 API)
让我们看看运行这个函数的结果。
***# replace "email" with your email address*** pubs_nominatim <- geocode_nominatim(pubs_m, country = "gb", fields = "all", email = email)***# let's now see the results***
pubs_nominatim[, c(1:4)]
pubs_nominatim[, c(1, 5:10)]
pubs_nominatim[, c(1, 11:13)]
pubs_nominatim[, c(1, 14:17)]
运行地理编码函数的结果-命名 API[第 1–4 列]
运行地理编码函数的结果-命名 API[第 5–10 列]
运行地理编码函数的结果-命名 API[第 11–13 列]
运行地理编码函数的结果-命名 API[第 14–17 列]
使用命名 API 进行反向地理编码
类似地,下面的反向地理编码函数在很大程度上类似于我们为 Google Maps API 构建的函数。
反向地理编码功能(命名 API)
下面是在 12 家伦敦酒吧的样本上运行这个函数的结果。
***# extract coordinates from geocoding results*** pubs_nominatim_crd <- pubs_nominatim[, c("lat", "lng")]***# replace "email" with your email address*** pubs_rev_nominatim <- rev_geocode_nominatim(pubs_nominatim_crd, email = email)
pubs_rev_nominatim <- cbind(pubs_m_df, pubs_rev_nominatim)***# let's now see the results***
pubs_rev_nominatim[, 1:4]
pubs_rev_nominatim[, c(1, 5:11)]
运行地理编码反向函数-命名 API 的结果[第 1–4 列]
运行地理编码反向函数-命名 API 的结果[第 5–11 列]
使用传单库构建地图
普遍的事实是,只有当培训材料辅以实际应用的例子时,才能引起对该主题的真正兴趣。我向你们承诺过,基于我们从 API 获得的信息,我们将建立一个交互式地图,我打算兑现这个承诺。
轻松构建地图的方法之一是使用 JavaScript 传单库。传单在其网站上被描述为:“[……]领先的移动友好互动地图开源 JavaScript 库。”许多大型科技公司、一些媒体甚至政府机构都在使用它:GitHub、脸书、Pinterest、金融时报、华盛顿邮报、Data.gov、欧盟委员会都在使用它。在我们的例子中,我们将依赖 RStudio 的传单包,这使得在 r 中集成和控制传单地图变得很容易。
我不会在这里描述这个伟大工具提供的所有特性,因为这是另一篇完整文章的主题。相反,让我们把注意力集中在最重要的事情上。
因此,在传单中创建地图的过程包括三个基本步骤:
- 创建地图微件。
- 向地图添加图层。
- 显示地图。
微件本质上是地图的主干或容器。
图层允许您向地图添加以下元素:
- 图块 —本质上是地图的“皮肤”,它定义了地图的外观和细节层次。更多关于平铺地图;
- 标记 —可用于显示地图上的特定位置;
- 弹出窗口和标注 —可用于向地图添加标注。例如,显示与某个位置相关联的地址或联系信息;
- 多边形——特定的区域或面积。例如,一个州内的一个区;
- 图例等。
对于我们的地图,我们将使用 OpenStreetMap 中的图块(传单的默认图块),并根据我们从 Nominatim 中提取的坐标绘制酒吧的位置。此外,我们将在标记弹出窗口中添加关于酒吧名称、地址和联系方式的信息。由于 Nominatim 没有返回每个酒吧的详细信息,我自己搜索了这些信息。我们没有在我们的可视化中使用任何多边形或图例,我添加的链接仅供参考。
因此,在我们继续之前,让我们做一些数据准备。
构建地图的数据准备
现在我们可以继续构建地图本身。
首先,让我们准备要在弹出消息中显示的文本:酒吧的名称、地址和电话号码。网站将不会单独显示,而是作为一个超链接添加到酒吧的名称。我们将使用一些 html 来以我们想要的格式呈现我们的文本。这里有一个提示。仅当您单击弹出消息所附着的对象时,才会显示弹出消息。如果您想在光标悬停在标记上时显示一些信息,您需要使用标签。然而,与弹出窗口不同,标签不会自动识别 HTML 语法——你需要先使用 htmltools 包中的HTML
函数来转换你的消息。一旦完成,我们可以“画”我们的地图。
小叶功能是不言自明的。您可能唯一不熟悉的是管道操作符%>%
,它是由 tidyverse packages 集合引入的。基本上,它允许您通过将一个函数的输出作为另一个函数的参数来传递,从而轻松地链接函数调用。更多关于那个的信息在这里。
***# text to be diplayed on pop-ups*** website <- paste0("<a href='", pubs_map$website, "'>", pubs_map$pub_name, "</a>")
center <- "<div style='text-align:center'>"
name <- paste0(center, "<b>", website, "</b>", "</div>")
address <- paste0(center, pubs_map$address_display, "</div>")
phone <- paste0(center, pubs_map$phone, "</div>")***# building the map*** pubs_map %>%
leaflet() %>%
addTiles() %>%
addMarkers(~lng, ~lat, popup = paste0(name, address, phone))
最后看看结果吧。
用传单包装制作的地图
结论
在本教程中,我们介绍了使用 Google Maps 和 Nominatim 检索地理编码数据的不同方法,并展示了如何使用 JavaScript 传单库将这些数据用于在地图上绘制特定位置。我希望本指南将作为您探索所有不同种类的 API 和映射工具的起点。
使用 Python 分解 Goodreads 数据集
找出下一本书
Ed Robertson 在 Unsplash 上拍摄的照片
我喜欢看书,总是在寻找下一本书来读,甚至在我开始读最近买的那本之前。所以,我决定摆弄这个 Goodreads 数据集我偶然发现了 Kaggle,看看我最终会得到什么样的书籍推荐。
这非常有趣,充满了学习!
和往常一样,我使用了 Jupyter 笔记本,并使用virtualenv
建立了一个虚拟环境。所有步骤请查看本帖。
进口:
import sys
sys.path.append('./lib/python3.7/site-packages')
import pandas as pd
import re
import mathdata = pd.read_csv("books.csv")
错误:
读取 csv 文件时,会出现以下错误:
ParserError: Error tokenizing data. C error: Expected 10 fields in line 4012, saw 11
发生这种情况是因为,在某些行中,有逗号将所有值向右移动一个位置,从而添加了一个额外的列。
可能要做的事情:
- 完全跳过这些行。但是我们事先并不知道这些行是什么。该数据集的 Kaggle 讨论区列出了这些行,但是删除它们将导致数据丢失。
- 使用文本编辑器,用另一个分隔符如
;
或|
替换所有逗号,然后手动转到有多个作者的行,并在那里放置逗号。这是一个麻烦的过程,需要太多的手动操作。如果损坏的行数太多,这个解决方案是不可行的。
我最终做的是——使用文本编辑器,并在最后添加一列以避免出现ParseError
。我给专栏命名为extra
,并使用pandas
读取 csv 文件。
添加了名为“额外”的列
现在我们可以查看和分析数据了。
data.describe(include = "all")
data.describe(include = "all")
数据:
bookID
:每本书的唯一标识号;
title
:书的名字;
authors
:该书作者的姓名。多个作者用-
分隔;
average_rating
:该书的平均评分;
isbn
:识别图书的唯一编号,国际标准书号;
isbn13
:一个 13 位的 ISBN 来标识图书,而不是标准的 11 位 ISBN;
language_code
:书的主要语言;
# num_pages
:书的页数;
ratings_count
:该书获得的总评分数;
text_reviews_count
:该书收到的文字评论总数。
损坏的行:
13719 行中有 5 行损坏,即它们在extra
字段中有一个值。
为了找出这些行,我们检查哪些在该字段中不具有值NaN
,即具有整数值。因此,我将那些具有整数值的行的索引存储在字段extra
中。
corrupted_rows = []for index, i in data.iterrows():
if -math.inf <= i['extra'] <= math.inf:
print("index number:", index)
print("field value:", i['extra'])
print("...")corrupted_rows.append(index)
损坏的行
data.loc[corrupted_rows, :]
data.loc[corrupted_rows, :]
让我们将多个作者合并到一个字段中。我使用authors
字段中的;
加入它们:
data['authors'] = data['authors']+ ";" +data['average_rating']
我们得到一个警告:SettingWithCopyWarning
。这不是一个错误,所以没有什么是坏的。然而,知道警告试图告诉我们什么总是好的,而不是忽视它。这里有一个解释。
转变:
作者被合并在一个专栏中。现在剩下要做的是将列值从第三列开始(包括第三列,因为我们从索引 0 开始),向左移动一个空格。这是通过使用shift
操作符来实现的,这里我们指定需要向左(或向右)移动多少个空格,以及是沿着行轴还是列轴。
**#-1 indicates one space to the left and axis=1 specifies column axis**data.iloc[corrupted_rows, 3:] = data.iloc[corrupted_rows, 3:].shift(-1, axis = 1)
移位的结果(这不是正确的方式)
这种移位的结果是两列中的值丢失:# num_pages
和text_reviews_count
。这是因为列的数据类型与最终移位值的数据类型不匹配。
解决方案是将所有列的数据类型临时转换为str
,执行 shift,然后将它们转换回原始数据类型。
data.iloc[corrupted_rows, 3:] = data.iloc[corrupted_rows, 3:].astype(str) **#convert to str**data.iloc[corrupted_rows, 3:] = data.iloc[corrupted_rows, 3:].shift(-1, axis = 1) **#the shift**data.describe(include="all")
data.describe(include="all")
我们现在可以删除最后一列。
del data['extra']
我们现在必须将列的数据类型转换回它们的原始类型。
pd.to_numeric
自动配置float
或int
数据类型。
data["average_rating"] = pd.to_numeric(data.average_rating) data["ratings_count"] = pd.to_numeric(data.ratings_count) data["# num_pages"] = pd.to_numeric(data.["# num_pages"])data["text_reviews_count"] = pd.to_numeric(data.["text_reviews_count"])
过滤数据:
我只想保留那些英文书。首先,我们需要一个正在使用的不同语言代码的列表。
language_code_unique = data.language_code.unique()
当我们打印列表时,我们看到英语语言代码以en
开头。因此,简单使用regex
将帮助我们过滤数据。
**#list to store the different English language codes**
english_lang_code = [] language_code_regex = re.compile(r'^en')for code in language_code_unique:
mo2 = language_code_regex.search(code)
if mo2 != None:
english_lang_code.append(code)
输出是对应于英语的 5 种语言代码。然后,我们使用 define 函数直接在数据帧上使用。
def check_lang_code(row):
if row.language_code in english_lang_code:
return rowdata = data[data.language_code.isin(english_lang_code)]
这给我们留下了英文书籍,并将行数减少到 12651。为了进一步减少数据量,我们只提取相关的列:title
、authors
、average_rating
、ratings_count
。
data_filtered = data.iloc[:, [1, 2, 3, 8]]
为了获得更高质量的图书列表,我们需要设置一个阈值average_rating
和ratings_count
。我决定两者兼顾。
ratings_count_mean = data_filtered["ratings_count"].mean()average_rating_mean = data_filtered["average_rating"].mean()data_filtered = data_filtered[(data_filtered.average_rating > average_rating_mean)]data_filtered = data_filtered[(data_filtered.ratings_count > ratings_count_mean)]
这留给我们一个 1013 行× 4 列的数据集。
高评价书籍列表:
使用average_rating
作为获得顶级书籍列表的唯一因素是不够的。
data_filtered.sort_values(by=['average_rating'], ascending=False)
下面的列表不对。
data_filtered.sort_values(by=['average_rating'], ascending=False)
我们需要考虑到ratings_count
。我创建了一个新列weighted_rating
,作为ratings_count
和average_rating
的乘积。
data_filtered['weighted_rating'] = data_filtered['average_rating'] * data_filtered['ratings_count']**#sort in descending order of 'weighted_rating'** data_filtered = data_filtered.sort_values(by='weighted_rating', ascending=False)
data_filtered.head(10)
看起来好多了!
显然,哈利·波特是主角。现在,我已经读完了整个系列,所以我不想包括任何哈利波特的书。这是一个简单的regex
案例。
match_regex = re.compile(r’Harry Potter’)**#list to store all 'Harry Potter' titles**
matched_titles = []for index, row in data_filtered.iterrows():
mo1 = match_regex.search(row.title)
if mo1 != None:
matched_titles.append(row.title)
匹配的 _ 标题
data_without_hp = data_filtered[~data_filtered.title.isin(matched_titles)]
榜单前 20 本书:
data_without_hp.head(20)
列表中有我读过的书,通过添加到match_regex
可以很容易地过滤掉,但我决定就此打住。脱颖而出的书是“蜜蜂的秘密生活”。我以前从未听说过这本书,这本书我一定要读一读!
局限性:(
不幸的是,这个数据集没有流派类别(恐怖/犯罪/搞笑/…)和小说/非小说类别,如果有这两个类别,这份名单会更具策划性和个性化(想到创建这样一份名单,我会兴奋得尖叫)!
要点:
→处理“损坏的行”
→尽可能过滤掉数据以获得期望的结果并提高性能
→一个主要的教训是尽可能减少for
循环的数量,因为它们比其他方法慢:
- 定义一个函数,然后在数据帧上应用它
- 过滤数据框架括号内的数据
- 直接计算函数值
希望你喜欢带走一些有价值的见解!
分解数据科学家面试流程
这是一个全新的十年,我们中的一些人可能正在寻找我们的下一个角色——也许是数据科学家?
根据我参与和主持数据科学面试的经验,我对面试流程进行了细分。数据科学是一个非常广阔的领域,有些数据科学家的职能类似于数据工程师,有些数据科学家的职能类似于产品经理等等。我会尽量保持这种概括,但我以前的经验肯定会使我偏向前者。
该过程
招聘人员电话
通常,招聘人员或人力资源部门的人会安排一次简短的拜访。他们会给你一个公司的概述,高层次的角色细节,并有机会问任何问题。面试官还会问一些千篇一律的问题,比如*你有使用 Python 的经验吗?你有资格在这个国家工作吗?*这种通话通常相当轻松;它通常被用来淘汰有明显危险信号的候选人。
招聘经理电话
在这个过程中的某个时候(通常是在开始的时候),招聘经理会想和你谈谈。在中小型公司,招聘经理是为他们的团队招聘的人。对于更大的公司,他们可以是另一个团队的经理。本次对话将深入到该角色的技术层面。面试官可能会问你以前的经历、技术能力和行为方面的问题,以了解你是谁。这也是一个很好的机会来询问更多关于这个角色的问题。
技术面试/带回家作业
下一部分是 1 小时的技术评估或带回家的作业。
技术评估通常是与团队中的数据科学家/工程师进行视频通话,讨论 Leetcode 问题或数据清理/建模练习。在这次面试中,面试官会评估你的技术能力。在开始解决问题之前,大声说出你的想法并提出任何澄清性的问题是一个好主意。
技术面试的替代方案通常是带回家的作业。这通常是一个建模/数据分析或机器学习任务,需要 3 个小时才能完成。其中一些时间长度可能具有欺骗性——我发现自己花了超过 10 个小时来完成一个 3 小时的带回家作业。根据我评估带回家作业的经验,候选人经常忽略的一个方面是他们工作的陈述和可重复性。如果任务是训练一个分类器,包括一些关于性能和如何评估模型的细节。如果解决方案涉及外部库,请包括如何复制解决方案的说明。
现场
现场面试通常是面试过程的最后阶段。在这次面试中,你将被带到公司与未来的团队成员见面,并经历一整天不同的面试。
没有特定的顺序,这些是典型的采访性质:
文化/行为:团队成员(有时是人力资源)将评估你是否符合文化。在我面试的几家公司,午餐时间是非正式的文化评估。面试官会评估你是否适合这个职位,并衡量你对这家公司的兴趣。
**结对编程:**和坐在你旁边看你编程的人一起解决一个问题。这与技术评估非常相似,只不过是面对面的评估。我看到这次采访有两种不同的方式。有时候,是 Leetcode 的问题。其他时候,它更适用(例如,清理这个数据集或在代码库中进行 XYZ 更改)。这是对你一般技术能力的测试。
**解决问题/白板:**这次面试旨在更好地了解候选人的批判性思维和解决问题的能力。我见过这种采访,从非常技术性的东西(编写伪代码来解决一个非常具体的编程问题)到设计一个实验,再到更抽象的东西,如解决康威的生命游戏。
这就是数据科学家面试流程。
感谢您的阅读!
如果你喜欢这篇文章,可以看看我关于数据科学、数学和编程的其他文章。请通过 Medium 关注我的最新消息。😃
作为一个业余爱好项目,我还在www.dscrashcourse.com建立了一套全面的免费数据科学课程和练习题。
如果你想支持我的写作,下次你报名参加 Coursera 课程时,可以考虑使用我的会员链接。完全公开—我从每一次注册中获得佣金,但不会对您产生额外费用。
再次感谢您的阅读!📕
分解支持向量机(SVM)算法
所以,我昨天在修改机器学习算法;我观察到 SVM 可能是一个广泛使用但复杂的机器学习算法。所以,在理解了其中的错综复杂并从头开始编码之后;我想我必须写一个帖子来帮助像我一样发现它比它的同行稍微复杂一点的人。
作者图片
所以,SVM 基本上使用向量空间来执行指定的任务。当谈到识别手写数字和相关任务时,你会惊讶地发现 SVM 实际上比一些神经网络更好。让我们开始吧!
基本直觉
在我们开始之前;你应该知道 SVM 一次只能划分两个组。但是嘿;这并不意味着它仅限于二元分类器(更强调单词‘一次’)。所以在直觉层面上。支持向量机在超平面的帮助下分离数据集中的两类数据。从超平面到数据点的垂直平分线表示最大可能距离。
SVM 超平面(决定边界)和垂线。作者图片
简而言之;即使可以有无限个超平面来分隔数据;最佳选择是可分离距离最大的一个(用数据点的垂线测量)。
因此,如果一个数据点位于超平面的任一侧;假设超平面是一堵分隔墙(只是打个比方),我们就可以很容易地说出它的类别。但是,这也可以在回归的帮助下完成,对吗?实际上是的,但是 SVM 可以处理更复杂的分色,因为它使用向量空间。不仅如此,SVM 还在确定决策界限方面做了出色的工作。(这是最佳位置—垂直线的最大长度)。
现在我们已经清楚了我们的基本原则;让我们开始讨论它的技术细节。
让我们多刺激一下我们的大脑
简单来说,我们可以说向量是一个既有大小又有方向的量(基础物理/数学)。在 SVM;幅度是数值(可以通过取 x 和 y 坐标的模或和的平方根来计算;类似毕达哥拉斯定理中的斜边)。
除此之外;另一个要知道的是两个向量的点积,简单来说就是两个向量中的值相乘。可以通过下图来理解。
作者图片
例如,如果数据集中有一个数据点“u”(可以用 u 向量表示),它被一个超平面(用红线表示)分隔开。现在,我们取另一个向量(w ),它是从超平面垂直画到原点的。现在,u 和 w 的点积加上偏差决定了我们的支持向量断言的输出。
SV 断言。作者图片
现在,如果我们方程的结果大于或等于零;然后我们可以对另一边的数据点进行分类(+ve)。在上面的例子中;我们可以直观地看到事实并非如此(我们的数据点显然不在+ve 一侧)。但是即使在复杂的情况下,这个等式也像魔法一样有效。
还有,你要注意,如果u . w+b = 0;然后,该点出现在决策边界上(一种罕见的情况)。
“但是萨蒂扬,这并不复杂。那就好理解了。”嗯,如果是这样的话,我会很高兴的。但是 SVM 在获取偏差和向量值时有一些限制。但是是的,一旦你熬过这一关,我相信你会爱上 SVM 的。
SVM 的制约因素
SVM 的约束是 u.w + b 必须是 1 或者-1。即使数学上这些值可以是-1 到 1 之间的任何值,但是因为我们想用向量对值进行分类;我们假设它是绝对的 1 或-1。此外,这涉及到复杂的数学(拉格朗日乘数)。
所以,如果我们的等式是 1;那么属于+类。如果它是-1,那么我们的数据点属于-class。但是嘿,我们还是不知道 w 和 b. 的值是多少
得到 w;我们需要找到决策边界的最佳位置。因此,我们可以从它画一条垂线来测量矢量 w。
SVM 超平面和决策边界。作者图片
我们已经知道,决策边界应该与两侧的数据点有尽可能高的距离。(换句话说;决策边界和 2 个数据超平面之间的宽度必须最大)。
为了实现这一目标;我们需要最大化宽度。那就是:
在简化并用等式 u.w+b -1 = 0 和 u.w+b+1 = 0 替换 X 正向量和 X 负向量的值后;我们得到:
以便最大化宽度;向量 w 的值应该是最小值。如前所述;向量 w 的大小是 1/2 * |w| 。
所以,我们在看一个想要最小化的方程。
这是额外需要阅读的内容。但是为了得到约束,我们必须插入拉格朗日乘数。不仅如此,我们还会看到一个向量 w(我们希望最小化)和偏差(最大化)。
迷路了?坚持住。就差最后一步了。如果你对微积分感兴趣。我们需要对 w 和 b 做偏导数。这给了我们一个二次方程。
而这就是我们如何得到向量 w 和 b (bias)的值。天哪,我知道这很复杂。但仅此而已。
事物的利与弊
除了表演;从计算的角度来看,训练 SVM 可能是一个繁琐的过程,因为二次方程。但是,一旦训练出来;它可以很快预测出分数。因为它只需要计算 u.w+b 的符号(不管它是否大于零)。
我的朋友是支持向量机。
感谢 sklearn 让很多害怕数学的人只用一行代码就能使用这个漂亮的算法。无红利
如果你想了解更多,你必须查看 sentdex 的解释和 MITOCW 讲座,了解更详细的数学解释。
直到下一次!
闯入数据科学:如何根据每个细分市场来做
概述许多故事和技巧,以进入数据科学领域
伊恩·施耐德在 Unsplash 上拍摄的照片
打入数据科学领域很难。根据这个调查,大多数数据科学家列出了他们拥有的核心技能是 Python/R/Excel、数据可视化、批判性思维、沟通技巧、机器学习、统计学、数学、SQL、业务理解、和数据准备。只要看看要掌握的各种技能,学习所有这些技能可能会很可怕。此外,发布在在线工作公告板上的数据科学家招聘广告通常需要大量的经验和/或技术知识,只有在该领域工作过一段时间后才能获得。
尽管打入数据科学领域很难,但这并不是一项不可能完成的壮举。事实上,许多人都这样做了,在这篇文章中,我想总结一下我从许多来源读到和听到的关于如何进入数据科学领域的所有故事,以及这些人给出的提示。
断路器类别
什么是断路器?这只是我为了方便而想出的一个词。在这篇文章中,我将把那些想要打破的人称为“打破者”。虽然许多人是断路器,他们实际上可以归类。Reddit 上有一个帖子对想要进入数据科学领域的人进行了分类,我引用了这个帖子,但我在这里补充了我自己的观点。这些分类是:
1。研究人员
这个分类中的断路器来自于学术界或者曾经在其中集中工作过。通常持有博士学位(或某些国家的硕士);通常来自定量领域,有出版物和会议的记录,并担任研究员/助理/教授/讲师。
研究破坏者在理论上很棒,但通常很难从学术界过渡到工业界。大多数时候,他们还缺乏商业视角,并因职责的不同而疲惫不堪。
2。转行者
职业改变者(career Changers)Breaker 是一个已经在工业领域拥有足够的专业经验的人,可能拥有硕士学位,也可能不拥有硕士学位,并且愿意改变他们的职业,进入数据科学领域。
根据他们以前的经验,这位破坏者可能拥有进入数据科学领域所需的几乎所有核心技能(通常是编程、沟通和/或业务理解),也可能根本没有任何核心技能。唯一可以肯定的是他们在数据科学领域缺乏资历。
3。新毕业生/在校学生
顾名思义,这位断路器是一个大学刚毕业或目前在一个学生。它可以在任何学士专业,但主要是这个断路器来自定量或技术领域。
这是最困难的时候,因为他们需要找到被大量申请人淹没的初级职位。此外,许多这种“入门级”的职位看起来根本不是入门级的,就像他们需要一些先进的技术或一些类似的经验。尽管如此,如果有一个入门级职位似乎有许多高级要求,我会认为这些公司对数据科学了解不多。
故事重述
从我刚才解释的障碍类别来看,取决于你站在哪里,你面前的障碍会有所不同。在这里,我将重述人们如何根据他们的破坏者类别闯入数据科学。
人员断路器
这就是我。我来自学术界,在进入数据科学领域之前,我是一名研究员。
当他们想要进入数据科学领域时,大多数这种类型的破坏者都有一个共同点。
- 他们热爱为科学做出贡献,并希望为更美好的人类实践这一理论。问题是,学术界的世界是艰难的,而且不像它那样纯洁。出版和竞争的环境让许多学术界人士对那些在科学上取得突破的人望而却步。
- 僵化的职业道路,只有少数人能够成功。此外,财务安全和工作生活平衡与考虑组建家庭的人不相容。
- 许多人在理论和/或编程算法方面有足够的知识,但觉得这些知识只停留在某个地方。他们想应用他们的知识。
这个断路器面临着一些障碍。其中大多数是:
- 很难从学术界过渡到工业界,因为环境确实不同。学术界的人没有行业工作环境的经验。在企业中担任数据科学家需要了解商业世界是如何运作的。这意味着来自学术界的人需要从学术文化到企业文化重新校准他们的思想。与可以塑造和体验专业的应届毕业生不同,从学术到行业的心态转变需要巨大的努力。
- 来自学术界的人通常持有 T2 的高等大学学位,这意味着公司认为他们希望 T4 要求比本科学位持有者更高的薪水。不管是真是假,这是他们得到的感觉。
- 弱现场编程技能面试和/或商务沟通技能。许多学术界人士天生热爱写作,专注于他们的研究。数据科学的问题在于,你不仅需要技术技能,还需要每天向非技术人员展示。是的,学术界的研究总是包括展示,但主要是展示给具有相似背景和知识的人。这就是区别,数据科学家需要将技术术语包装成更具商业价值的术语。
那么,这些人实际上是如何进入数据科学的呢?学术界人士仍然占据优势拥有经验和理论基础。大多数人说,他们需要做的是让别人相信你能胜任这份工作。这意味着你具备关于数据科学的必备知识和展示你从事类似工作的经验和技能。
知识可以通过大量阅读、在线课程或有导师来获得。展示经验和技能需要大量的调整;我个人在我的研究时间里量身定制我的经验,以适应我想进入的行业。例如,我是一名在生物统计方法方面有经验的生物学家。我只需要在我的简历和面试中展示我的统计方法,它实际上适用于工业企业。
许多报道还指出,他们是通过网上求职公告板申请工作,而不是随机申请。他们专门申请 他们曾拥有的研究业务背景的工作(例如医疗保健)。虽然,我也看过很多故事(像我一样)从自己的人脉中找到工作。这种联系可能来自他们的大学、Meetup 小组,或者只是你的老朋友。
职业改变者
这种类型的人以前已经是行业专家,但出于各种原因希望将他们的职业生涯转向数据科学。这种破坏者通常是那些:
- 他们想要更高的薪水。大多数职业改变者和研究人员没有相同的动机。虽然财务安全仍然是目标,但研究人员破坏者也受到他们的研究工作可以应用的方式的激励,而职业改变者破坏者主要只是想要更高的工资(不是一概而论,只是从我读到的)。
- 想要更好的职业机会。与金融安全相关,数据科学目前仍然是一个热门工作,行业中有许多需求。职业道路也足够清晰,这吸引了许多人尝试磨合。
- 孤注一掷。我个人遇到过许多想中途改变职业的人,尤其是那些参加训练营的人。这里的人们赌上他们最后的钱和工作来获得进入数据科学的机会。
专业人士通常有更好的优势,因为他们已经有了正确的经验和心态,但仍然有一些缺点:
- 缺乏核心技能。取决于他们的专业背景,他们可能已经拥有几乎所有必要的核心技能,甚至根本没有。例如,从事软件工程的人在编程方面会做得更好,但不一定需要交流他们的工作。
- 他们有时只是没有分析能力或热情去做一件事。对,分析。不要以为只有数据分析器分析数据,数据科学只用深度学习来预测什么。数据科学与分析数据和利用数据进行创造性工作密切相关。我读过并见过许多人,他们只是没有准备好。这一点尤其表现在面试阶段,他们需要展示自己的分析能力,但却做不到。
与其他破坏者相比,拥有一些核心技能的专业人员仍然有优势,特别是如果他们已经拥有领域知识和/或编程技能。许多属于这一类别的人通常会在面试中展示他们的专业经验,并通过大量阅读和参加在线课程/认证来弥补他们的技能不足。建立投资组合也是必须的。一些人也报名参加更高的大学学位(通常是硕士)来增加他们的机会。其他人也推荐做实习。
就像研究员断路器一样,许多人通过在线工作板申请,但通常情况下,职业转换断路器在行业方面更灵活,所以他们随时申请有空缺的职位。我也读过许多故事,说职业改变者 breaker 从他们自己的公司获得了一份数据科学的工作。例如,我读到他们的公司想要建立一个数据科学团队,因为这个人拥有技能,他们雇用他们作为数据科学家。
许多职业改变者也获得了数据科学家的工作,因为他们在网络媒体中的**;尤其是 LinkedIn。他们尝试过在网上写博客或发布他们的工作,然后突然有招聘人员联系他们。**
****联网虽然仍然是人们推荐的最多的方式。有了人际关系网,如果你像平常一样申请,他们可以绕过许多常规步骤,人际关系网也可以帮助你更容易获得这个职位。
新毕业生/当前学生破坏者
在数据科学领域,这种突破可能是最难突破的类型。没有实际的行业经验,并试图找到一个竞争激烈的有限领域(不仅来自新毕业的同事,也来自有经验的人)。这种破碎机大多具有以下特点:
- 找一份任何数据相关职位的工作都可以,但主要目标是数据分析师或数据科学家职位。这并不意味着没有具体的目标,但由于竞争,缺乏联系和有限的景点使这个断路器罚款任何种类的位置。
- 他们可能拥有学士/硕士学位或者正在攻读。有些人没有任何学位,通常是刚从高中毕业。
- ****已经申请了很多公司甚至之前在学生时期或者毕业后实习过。有些人还要求电话面试/面对面面试/编码面试或任何类型的面试,结果各不相同。
- 一些人对数据科学感兴趣是因为薪水**,另一些人感兴趣是因为技术前景。还有许多其他原因,但这主要是我所看到的。**
我再次声明,这个破坏者最难进入数据科学领域,因为:
- ****缺乏经验和核心技能。这一直是这个断路器不好过的主要原因。数据科学仍然是一个新鲜出炉的职业,意味着这个职位的需求大于供给。这也意味着大多数公司和早期创业公司都在寻找有经验的人。
- 没有正确连接。对于大一新生或学生来说,很难找到与工业企业的联系。我读到的许多故事是,人们通过网络找到他们的职业,而这个破坏者的评论通常是“我怎么能做网络呢?”
- 数据科学职位中没有太多的入门级职位,因为大多数职位都需要大量的经验。更有甚者,我还读到许多大一新生甚至很难被要求参加这个所谓的“入门级”职位的面试。
似乎进入数据科学有很多障碍,事实也的确如此,但这并非不可能**。**
这些成功进入的新生是那些坚持努力并通过大量阅读和在线课程不断更新知识的人。一些人通过实习找到工作,另一些人通过进入非技术行业找到工作,该行业有一个与数据相关的职位空缺。****
许多人也给出建议,如果你没有研究生学位,最好尝试找一份实习工作,或者努力追求一份工作。有些人还建议申请另一个职位**,但是当你已经有足够的经验时,你可以尝试再次进入职场,成为一名职业改变者或**研究员。****
作为一名新生或学生,找到一个联系也不是不可能的,事实上,许多人做到了。许多人从他们大学的教授那里,从校园的就业公告板,甚至只是从他们的兴趣小组中找到一个。人们也试图通过在线媒体联系,比如 LinkedIn。关于网络的一个建议是它仍然是人与人之间的互动,意味着给予和索取**。不要在 meetup 会议或 LinkedIn 上通过询问是否有空缺职位来突然联系某人。试着进行适当的讨论,和他们成为朋友。毕竟,人脉不是获得工作的捷径。在产生任何结果之前,它需要被慢慢地处理。我从高中起就开始建立自己的人际网络,直到十年后才有回报。毕竟,网络是关于彼此的信任,在某种程度上,是给予和索取。**
结论
许多人试图进入数据科学领域,根据他们的经验,障碍也会有所不同。成功的断路器给出了许多提示,包括:
- 更新您的技能,使其与数据科学核心技能相匹配
- 根据职位要求个性化你的经历
- 实习
- 联网
如果您喜欢我的内容,并希望获得更多关于数据或数据科学家日常生活的深入知识,请考虑在此订阅我的简讯。
如果您没有订阅为中等会员,请考虑通过我的推荐订阅。
打破 Spotify 的音乐流派分类的算法!
在这篇文章中,我将深入探讨构建您自己的模型的过程,该模型可以将音乐分类为不同的流派,并创建您自己的播放列表。
照片由沃瓦·克拉西尔尼科夫从派克斯拍摄
简介
这个行业中有许多不同类型的流派。但是基本的类型将会有几个主要的方面,使它们更容易被识别。流派是用来标记和定义不同种类的音乐,基于它们的创作方式或基于它们的音乐形式和音乐风格。
在本文中,您将学习构建自己的模型,该模型将接受一首歌曲作为输入,并预测或分类该特定歌曲的一个流派。我们将分为以下几个基本流派——布鲁斯。古典、乡村、迪斯科、嘻哈、爵士、金属、流行、雷鬼和摇滚。该模型将使用 LSTM 网络构建。如果你不知道 LSTM 是什么,不要担心。这篇文章将使你对 LSTM 及其工作有一个简单的了解。
以下是整个项目的 GitHub 链接—https://GitHub . com/rajatkeshri/Music-Genre-Prediction-Using-RNN-LSTM
整篇文章分为 4 个部分
- 先决条件
- 理论
- 数据预处理
- 训练模型
- 根据新数据进行预测
先决条件
在开始这个项目之前,你需要具备一些先决条件。你首先需要的是数据集。我在这个项目中使用的音乐数据可以从 ka ggle-https://www . ka ggle . com/andradaolteanu/gtzan-dataset-music-genre-class ification下载。
注意,这个数据集包含 10 个类,每个类中有 100 首歌曲。对于一个机器学习项目来说,这可能听起来很少,这就是为什么在下一节中,我将向您展示如何增加每类体裁的训练数据的数量。
您需要在 PC/笔记本电脑上安装一些模块,以便开始使用。我们将使用用 python 编码的 Tensorflow 来构建整个 LSTM 模型。我们将使用 python 3.6 或更高版本(如果您使用 python 2.7,则需要使用 python 3.6 或更高版本才能获得完整的支持和功能)。以下是需要安装的 python 包—
- Tensorflow —机器学习库
- librosa——从歌曲中提取特征的语音处理库
- numpy——科学计算的数学模型
- sklrean —另一个机器学习模型(我们将使用这个库来拆分训练和测试数据)
- json——对数据集进行 JSON 化(在下一节中解释)
- pytdub —将 mp3 转换为 wav 文件
这些模块可以使用 pip 或 conda 安装。您可以找到许多关于 pip 或 conda 入门的在线资源和 youtube 视频。一旦以上模块安装完毕,我们就开始编码吧!
理论
对于任何机器学习项目来说,都有两件主要的事情——从数据中提取特征和训练模型。
对于用于机器学习目的的音频和音乐特征提取,通常从歌曲或音频中提取梅尔频率倒谱系数(MFCC,并且这些特征用于训练模型。MFCC 特征提取是一种仅从音频中提取相关信息的方法。
为了更好地解释这一点,当我们以数字格式表示一个音频文件时,计算机将其视为一个波,X 轴为时间,Y 轴为振幅。这如图 1 所示。
音乐在振幅和时间上的表现
这种表示格式不能给我们提供太多关于音频或歌曲的信息,因此我们通过使用快速傅立叶变换(FFT)在频域中表示音频。FFT 是一种主要用于信号处理的数学算法,用于将时域转换到频域。您可以参考此链接或观看一些 youtube 视频,了解什么是 FFT 以及它的具体工作原理—https://www . nti-audio . com/en/support/know-how/Fast-Fourier-transform-FFT #:~:text = Fast % 20 Fourier % 20 transformation % 20 FFT % 20 2D % 20 basics,frequency % 20 information % 20 about % 20 the % 20 signal。
使用该 FFT,我们转换输入音频文件,并在频域和时域中表示它。在频域和时域显示音频数据的图形称为频谱图,如图 2 所示。
图 2
声谱图是一组叠放在一起的 FFT。这是一种直观表示信号响度或幅度的方式,因为信号以不同频率随时间变化。这里,y 轴被转换为对数标度,颜色维度被转换为分贝(你可以把这看作振幅的对数标度)。这是因为人类只能感知非常小且集中的频率和振幅范围,并且人耳根据对数标度的原理工作。
正常的频谱图可以用于提取特征,但是这仍然包含一些不需要的附加信息。由于人耳在对数尺度而不是线性尺度上工作,我们使用 mel 频谱图,该频谱图将该频谱图转换成对数表示,以通过移除或消除不想要的特征来更准确地获得特征。梅尔频谱图是一个频谱图,其中频率被转换为梅尔标度。图 3 显示了 mel 光谱图—
图 3
回到主题,MFCCs 使用 mel 标度,用于从音频信号中提取特征,当表示为图形时,结果是 mel 谱图。简而言之,我们在 mel 光谱图上看到的正是我们训练模型所需的特征。我在部门找到了这篇精彩的文章,它解释了关于 mfccs 的一切。
一旦我们准备好数据集,我们就要训练我们的模型。音乐是一个时间序列数据。这意味着音乐与时间成线性关系。LSTM 非常擅长在输入特征空间中提取模式,输入数据跨越长序列。鉴于 LSTM 的门控结构具有操纵其记忆状态的能力,它们是解决这类问题的理想选择。更多信息可以参考这个的博客 。
数据预处理
我们将在这里使用的数据集是从 Kaggle 下载的,在 10 个标签或流派下各有大约 100 首歌曲。每首歌曲时长 30 秒。如前所述,这个数据量对于训练 LSTM 模型来说要少得多。为了解决这个问题,我将每个音频文件分成 10 段,每段 3 秒长。因此,每个标签下的歌曲数量现在是 1000,这是训练模型以实现良好准确性的合适数量。
现在我们已经准备好了数据,我们需要提取适合于输入我们网络的特征。特征提取将通过使用 MFCCs 来完成。Librosa 用于从每个音频片段中提取特征。我们创建一个字典,以流派的标签或类别作为关键字,从所有 1000 个片段中提取的所有特征作为该标签下的特征数组。一旦我们在一个循环中对所有 10 个类别都这样做了,我们就把字典转储到一个 JSON 文件中。因此,这个 JSON 文件成为我们的数据集,模型将在这个数据集上进行训练。
转到数据集预处理的编码,我们首先定义段的数量和每个段的采样率。为了知道歌曲的回放速度,需要采样率。在这里,我们对每一段都保持不变。
dataset_path = "genres"
jsonpath = "data_json"sample_rate = 22050
samples_per_track = sample_rate * 30
num_segment=10
然后,我们创建一个循环,在这个循环中,我们打开每个流派文件夹中的每个歌曲文件,并将其分成 10 个片段。然后,我们提取每个片段的 MFCC 特征,并将其添加到字典中的流派名称(也是文件夹名称)下。
def preprocess(dataset_path,json_path,
num_mfcc=13,n_fft=2048,hop_length=512,
num_segment=5):
data = {
"mapping": [],
"labels": [],
"mfcc": []
} samples_per_segment = int(samples_per_track / num_segment)
num_mfcc_vectors_per_segment = math.ceil(samples_per_segment /
hop_length) for i, (dirpath,dirnames,filenames) in
enumerate(os.walk(dataset_path)): if dirpath != dataset_path:
#Adding all the labels
label = str(dirpath).split('\\')[-1]
data["mapping"].append(label)
#Going through each song within a label
for f in filenames:
file_path = dataset_path +"/" + str(label) + "/" +
str(f)
y, sr = librosa.load(file_path, sr = sample_rate) #Cutting each song into 10 segments
for n in range(num_segment):
start = samples_per_segment * n
finish = start + samples_per_segment
#print(start,finish)
mfcc = librosa.feature.mfcc(y[start:finish],
sample_rate, n_mfcc = num_mfcc,
n_fft = n_fft, hop_length = hop_length)
mfcc = mfcc.T #259 x 13 #Making sure if
if len(mfcc) == num_mfcc_vectors_per_segment:
data["mfcc"].append(mfcc.tolist())
data["labels"].append(i-1)
print("Track Name ", file_path, n+1) with open(json_path, "w") as fp:
json.dump(data, fp, indent = 4)
上述脚本将创建线段并提取要素,然后将要素转储到 data_json.json 文件中。
训练模特
LSTM 用于训练模型。但在我们建立模型之前,我们必须将模型加载到我们的程序中,并将其分为训练和测试。这是通过打开我们在上一节中创建的 JSON 文件并将其转换成 numpy 数组来实现的,以便于计算。这个方法如下面的代码片段所示。
def load_data(data_path):
print("Data loading\n")
with open(data_path, "r") as fp:
data = json.load(fp) x = np.array(data["mfcc"])
y = np.array(data["labels"]) print("Loaded Data") return x, y
加载数据后,我们准备数据,并分成训练集和测试集,如前所述。这是通过使用 sklearn 的 train_test_split 函数来完成的。该函数如下所示。
def prepare_datasets(test_size,val_size): #load the data
x, y = load_data(data_path) x_train, x_test, y_train, y_test =
train_test_split(x,y,test_size = test_size)
x_train, x_val, y_train, y_val =
train_test_split(x_train,y_train,test_size = val_size) return x_train, x_val, x_test, y_train, y_val, y_test
接下来,使用 tensorflow 创建 LSTM 网络。这里,我们创建了一个 4 层的 LSTM 网络,包括两个隐藏层。下面的代码片段显示了网络的创建。
def build_model(input_shape): model = tf.keras.Sequential() model.add(tf.keras.layers.LSTM(64, input_shape = input_shape)
model.add(tf.keras.layers.LSTM(64))
model.add(tf.keras.layers.Dense(64, activation="relu"))
model.add(tf.keras.layers.Dense(10,activation = "softmax"))
return model
我们将模型初始化为序列,并添加一个具有 64 个神经元的输入层,一个隐藏层,一个密集 LSTM 层和一个具有 10 个神经元的输出层,因为有 10 个流派。输入层的大小取决于我们作为参数“input_shape”传递的 MFCC 系数的大小。您可以尝试更多的隐藏层,并测试准确性。
一旦定义了所有的方法和函数,就该调用它们并训练我们的分类模型了!
if __name__ == "__main__": x_train, x_val, x_test, y_train, y_val, y_test =
prepare_datasets(0.25, 0.2) input_shape = (x_train.shape[1],x_train.shape[2])
model = build_model(input_shape) # compile model
optimiser = tf.keras.optimizers.Adam(lr=0.001)
model.compile(optimizer=optimiser,
loss='sparse_categorical_crossentropy',
metrics=['accuracy']) model.summary()
model.fit(x_train, y_train, validation_data=(x_val, y_val),
batch_size=32, epochs=50)
model.save("model_RNN_LSTM.h5")
print("Saved model to disk")
首先,我们调用“prepare_datasets”函数,并传递测试日期百分比和验证数据百分比。验证数据是训练数据的一部分,模型不是用它来训练的,而是用它来验证模型。验证集告诉我们,在训练完成后,数据是否表现良好。
接下来,我们调用“build_model”函数来构建 are LSTM 网络并编译它。编译用于添加优化器(定义学习率)和损失计算功能。这里,我们使用了分类交叉熵数学函数。你可以点击此链接这里 了解更多信息。
编译后,model.fit()用于在我们的数据上训练模型。根据您的硬件,培训可能需要大约 1 小时到 1.5 小时。我们不想为了测试模型而一直训练我们的模型,因此在训练之后,我们保存模型,以便我们可以使用保存的文件来预测我们的新数据。在训练结束时,您可以看到达到的精确度。
根据新数据预测
恭喜你!我们的模型已经被训练好了!现在是时候检查它预测不同歌曲并将其分类为不同流派的能力了。
在我们开始测试和预测新歌之前,我们必须定义这些常数。
###########################################################################
just_path = "genres/blues/"
song_path = "genres/blues/1.wav"
song_name = "1"
###########################################################################Constants which depend on the model. If you train the model with different values,
#need to change those values here too
num_mfcc = 13
n_fft=2048
hop_length = 512
sample_rate = 22050
samples_per_track = sample_rate * 30
num_segment = 10
############################################################################
如果你还记得,我们用 30 秒长的歌曲来训练我们的模型。因此,该模型将一次接受 30 秒的歌曲片段。为此,我们将要预测的输入歌曲分成多个 30 秒长的片段。这有三种不同的情况——歌曲长度小于 30 秒、歌曲长度等于 30 秒和歌曲长度大于 30 秒。对于长度小于 30 秒的歌曲,我们显示一条错误消息,说明没有达到最小值;对于长度大于 30 秒的歌曲,我们将整首歌分成多个 30 秒的片段,并将每个片段输入到模型中。以下片段是针对上述场景的。
#load the song
x, sr = librosa.load(song_path, sr = sample_rate)
song_length = int(librosa.get_duration(filename=song_path))
flag = 0
if song_length > 30:
print("Song is greater than 30 seconds")
samples_per_track_30 = sample_rate * song_length
parts = int(song_length/30)
samples_per_segment_30 = int(samples_per_track_30 / (parts))
flag = 1
print("Song sliced into "+str(parts)+" parts")
elif song_length == 30:
parts = 1
flag = 0
else:
print("Too short, enter a song of length minimum 30
seconds")
flag = 2for i in range(0,parts):
if flag == 1:
print("Song snippet ",i+1)
start30 = samples_per_segment_30 * i
finish30 = start30 + samples_per_segment_30
y = x[start30:finish30]
#print(len(y))
elif flag == 0:
print("Song is 30 seconds, no slicing")
接下来,我们加载保存的模型,并定义不同的类别或流派。该模型将预测一个从 0 到 9 的数字,每个数字将代表训练期间定义的流派。
model = tf.keras.models.load_model("model_RNN_LSTM.h5") classes = ["Blues","Classical","Country","Disco","Hiphop",
"Jazz","Metal","Pop","Reggae","Rock"]
该模型为输入歌曲的每个片段预测某种风格。组合了特定输入歌曲的所有切片片段的所有预测的预测最多的流派给出了最终的预测。例如,如果给定长度为 120 秒的歌曲作为输入,它首先被分成 3 个各 30 秒的片段,并且每个片段作为预测特定流派的模型的输入。平均预测次数最多的类型是整首歌的类型。对于预测,我们再次提取每个片段的 MFCC 特征,然后调用“model.predict()”来获得预测。
for n in range(num_segment):
start = samples_per_segment * n
finish = start + samples_per_segment
#print(len(y[start:finish]))
mfcc = librosa.feature.mfcc(y[start:finish],
sample_rate, n_mfcc = num_mfcc, n_fft = n_fft,
hop_length = hop_length) mfcc = mfcc.T
mfcc = mfcc.reshape(1, mfcc.shape[0], mfcc.shape[1])
array = model.predict(mfcc)*100
array = array.tolist()#find maximum percentage class predicted
class_predictions.append(array[0].index(max(array[0])))occurence_dict = {}
for i in class_predictions:
if i not in occurence_dict:
occurence_dict[i] = 1
else:
occurence_dict[i] +=1max_key = max(occurence_dict, key=occurence_dict.get)
prediction_per_part.append(classes[max_key]) prediction = max(set(prediction_per_part), key = prediction_per_part.count)
print(prediction)
现在你知道 Spotify 如何为你分类你的音乐了吧!希望你喜欢读这篇文章。感谢您的阅读。
打破深度学习中的对称性
在 L 层深度学习模型中将权重初始化为零矩阵可以导致成本降低,但权重不变。这篇文章讲的是深度学习中一个美丽却至关重要的术语“打破对称”。
照片来自 Unsplash,作者 Ellicia@ellicia_
T 深度学习算法的准确性让我们所有人着迷。每个领域都会不时地使用深度学习模型,无论是自动驾驶汽车、人工智能、语音到文本转换、图像识别、情感分析,还是更多。深度学习改善了许多问题的现状。但这些都是非常复杂的技术,仍处于开发阶段。
由于总是有一个起点,趋势表明,大概所有的深度学习指导者都是从“逻辑回归作为神经网络”开始的,这构成了深度学习的基本原理,它的单层深度学习模型使用交叉熵作为代价函数和梯度下降算法来更新权重。现在,我已经间接地提到了这篇文章的所有先决条件。
有一个假设非常小,就像埋在沙子里的铁钉一样,通常会被忽略,即我们将权重初始化为零。当我们处理单层神经网络时,这个假设仍然有效。其中不包含任何隐藏层。
让我们考虑著名的泰坦尼克号数据集问题,我们需要预测谁幸存下来,给定他们的某些特征。我们将不使用原始数据集,而是使用准备好进行训练的干净数据集。
案例 0:单层深度学习模型
因此,让我们使用激活函数为 sigmoid 函数的单层深度学习模型来预测谁在泰坦尼克号上幸存下来。这是一个逻辑回归,但是具有使用梯度下降算法的反向传播步骤和 0.001 的学习率。
################# WEIGHTS ARE INITIALIZED TO ZERO ##################
W = np.zeros((1,X.shape[0]))
b = np.zeros((1,1))################# WEIGHTS ARE INITIALIZED RANDOMLY #################
W = np.random.randn(1,X.shape[0])
b = np.zeros((1,1))################### ONCE WEIGHTS ARE INITIALIZED ###################
## dict for storing costs
ini_single = {}irts = 1000
while irts > 0 :
irts = irts -1
## Forward Propagation
Z = np.dot(W,X) + b
A = sigmoid(Z)## Cost estimation
logerror = -(np.multiply(Y, np.log(A)) + np.multiply(1-Y, np.log(1 - A)))
cost = logerror.sum()/m
ini_single[1000-irts] = cost
print('The cost of the function is: ' + str(cost))
## Backward Propagation
dZ = A-Y
dw = np.dot(dZ,X.T)/m
db = np.sum(dZ)/m## Updating Weights
W = W - 0.001*dw
b = b - 0.001*db
一旦我们执行了代码,我们就可以为两种权重初始化技术生成单层深度学习模型的成本与迭代次数。因此,我们可以说在几次迭代之后,两种权重初始化技术趋向于相同的成本,但是初始化为非零的权重最初具有较低的成本。
titanic 数据集的单层深度学习模型(作者发表)。
单层的结果是令人满意的,因为两种技术在一些迭代之后收敛到相同的成本。现在,让我们在模型中引入一个隐藏层,将权重和偏差初始化为零。
情况 1:两层深度学习模型,权重初始化为零矩阵
## dict for storing costs
ini_zero = {}## initializing weights of a 2 layer Deep Learning model as zero matrix.
W1 = np.zeros((4,X.shape[0]))
b1 = np.zeros((4,1))
W2 = np.zeros((Y.shape[0],4))
b2 = np.zeros((Y.shape[0],1))irts = 10
while irts > 0 :
print('================ iteration number: ' + str(n-irts) + '================')
irts = irts -1
## Forward Propagation
Z1 = np.dot(W1,X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2,A1) + b2
A2 = sigmoid(Z2)## Cost estimation
logerror = -(np.multiply(Y, np.log(A2)) + np.multiply(1-Y, np.log(1 - A2)))
cost = logerror.sum()/m
ini_zero[n-irts] = cost
print('The cost of the function is: ' + str(cost)## Backward Propagation
dz2 = A2 - Y
dw2 = np.dot(dz2, A1.T)/m
db2 = np.sum(dz2, axis=1, keepdims = True)/m
derivative = 1 - np.tanh(Z1) * np.tanh(Z1)
dz1 = np.multiply(np.dot(W2.T, dz2) , derivative)
dw1 = np.dot(dz1,X.T)/m
db1 = np.sum(dz1, axis=1, keepdims = True)/m## Updating Weights
W1 = W1 - 0.01*dw1
b1 = b1 - 0.01*db1
W2 = W2 - 0.01*dw2
b2 = b2 - 0.01*db2
如上所述,这是一个两层深度学习模型,其中隐藏层的激活函数是 tanh ,输出层的激活函数是 sigmoid 函数,学习率等于 0.01。
如果我们仔细检查,那么成本在下降,但权重 W1 和 W2 的值保持不变。W 的无变化在深度学习中被称为对称。将权重初始化为零会给模型造成混乱,这就是为什么需要随机初始化权重,因此打破了对称性。
当权重初始化为零时,10 次迭代的成本、W1 和 W2 的值(由作者发布)。
但是为什么成本在变化呢?敏锐的观察表明,W 保持为零,但成本仍在下降。同样的问题让我很开心,现在我有了答案。改变成本的原因是“b2”,即输出层的偏差。对于梯度下降的第一次迭代,所有的预测都是相同的,但是我们发现:
dZ2 = A2-Y 其中 dZ2 是代价函数相对于 Z2 的偏导数, A2 是输出层的输出, Y 是目标变量的实际值。
如果我们找到 dZ2,很明显它对于泰坦尼克号这样不平衡的数据会有一个非零值。因此,在梯度下降的迭代过程中唯一改变的参数是 b2,这是成本降低的原因。这也说明了梯度下降算法有多厉害。
现在,如果我们以非零的方式初始化权重,那么让我们看看会发生什么。
情况 2:两层深度学习模型,权重初始化为非零
## dict for storing costs
ini_nonzero = {}## initializing weights of a 2 layer Deep Learning model as randmon value matrix.
W1 = np.random.randn(4,X.shape[0])*0.01
b1 = np.zeros((4,1))
W2 = np.random.randn(Y.shape[0],4) *0.01
b2 = np.zeros((Y.shape[0],1))irts = n
while irts > 0 :
irts = irts -1
## Forward Propagation
Z1 = np.dot(W1,X) + b1
A1 = np.tanh(Z1)
Z2 = np.dot(W2,A1) + b2
A2 = sigmoid(Z2)## Cost estimation
logerror = -(np.multiply(Y, np.log(A2)) + np.multiply(1-Y, np.log(1 - A2)))
cost = logerror.sum()/m
ini_nonzero[n-irts] = cost
print('The cost of the function is: ' + str(cost))## Backward Propagation
dz2 = A2 - Y
dw2 = np.dot(dz2, A1.T)/m
db2 = np.sum(dz2, axis=1, keepdims = True)/m
derivative = 1 - np.tanh(Z1) * np.tanh(Z1)
dz1 = np.multiply(np.dot(W2.T, dz2) , derivative)
dw1 = np.dot(dz1,X.T)/m
db1 = np.sum(dz1, axis=1, keepdims = True)/m## Updating Weights
W1 = W1 - 0.01*dw1
b1 = b1 - 0.01*db1
W2 = W2 - 0.01*dw2
b2 = b2 - 0.01*db2
这里,我们已经通过正态分布随机初始化了权重,并改变了权重,但没有改变偏差,学习率也是相同的,但差异是巨大的**。**
当权重被初始化为非零时,10 次迭代的成本、W1 和 W2 的值(由作者发布)。
这是权重初始化有多重要的明显区别。但是敏锐的观察者会注意到偏差仍然初始化为零。正如我们已经看到的,梯度下降对偏差有直接影响,因此它们可能会也可能不会初始化为零。这不会像一个权重初始化为零那样产生巨大的差异。
另一个观察结果是,我们将权重乘以系数 0.01(恰好等于学习率),以确保权重较小。如果权重足够大,并且我们使用类似 sigmoid 或 tanh 的激活函数,那么初始斜率(激活函数中的输入值很大)将会非常小。因此,性能会很好,但需要时间来达到最佳结果。
让我们运行这两个代码(案例 1 和案例 2)3000 次迭代。
3000 次迭代的成本与迭代次数(由作者发布)。
这表明情况 1 和情况 2 将在一些迭代之后收敛,但是在大多数情况下,在该迭代次数下,将发生数据的过度拟合。因此,最好选择第二种情况,在这种情况下,我们可以在更短的时间内获得结果,并且过度拟合的可能性也最小化。
总结
审视微小的步骤是令人钦佩的,因为它们可以创造巨大的差异。
初始化权重的一小步就能产生这样的差异,但重要的是要注意偏差仍然初始化为零。通过欣赏这一点,我们可以节省时间和巨大的数据问题,如过度拟合。完整的代码文件可以在这里找到。
用 MCMC 破解 Python 中的 Enigma 代码(漫威主题)
一台谜机。来源
知识就是力量。这条规则几乎可以应用于任何领域,但可以说它从来没有比战争时期更有意义。预测你的敌人下一步行动的能力同样困难,因为这是值得的,如果你能提前阅读他们的计划,这项任务会变得容易得多。
这是第二次世界大战期间各方都知道的事情,纳粹德国为确保他们通信的隐私和安全付出了巨大的努力。一个主要的工具是“Engima”,这种机器可以通过简单的字母转换过程(例如,所有的“a”都变成了“z”)来安全地加密和解密他们的通信。
虽然加密过程很简单(至少以今天的标准来看),但对于盟军来说,找到正确的密钥来解密被截获的信息是一项艰巨的任务。更糟糕的是,这些按键每天都会切换,使得之前的所有努力都是徒劳的。当然,正如你可能知道的,艾伦·图灵和他的团队在布莱奇利公园遇到了挑战,这导致了计算的突破,并成为“人工智能”的基础。
然而,这篇文章不是关于图灵或他的方法(尽管他们有一些共同的品质)。这也不是关于解密纳粹通讯。相反,我们将采取更古怪的策略,看看神盾局特工截获的一条(虚构的)神秘信息,这条信息来自曾进行种族灭绝的泰坦军阀灭霸(漫威电影宇宙最初 22 部电影的主角)。你将扮演一个神盾局分析师的角色,他只有通过使用 Python 和他的马尔可夫链蒙特卡罗(MCMC)知识才能尝试解密代码并拯救宇宙。
如果你对真正的英格玛机以及它是如何被解密的感兴趣,我推荐你从这个数字迷视频开始:https://www.youtube.com/watch?v=G2_Q9FoD-oQ
"huvw !kzcq7nv3 qv3!hqv ,evwrhqv3rvq9qwi3qvhuv2cq,3vmk,7v,7zvbikb!kvhuvzqe3!7ufv3 qvmk,7nv,evuriv57r1nv!ev3rvieqv3 qvwreh!wvq73!3!qev57r17v,ev3 qv!7b!7!3uve3r7qev3rv1!mqv ,kbvrbv3 qvi7!;qceqvri3vrbvq9!e3q7wqverv3 ,3v3 qvr3 qcv ,kbvh,uv3 c!;qfvricv2cq,3qe3vw ,kkq72qv ,evtqq7vb!7z!72v3 qve3r7qev!7v3 !ev;,e3vi7!;qceqnvti3v7r1v3 quv,cqv1!3 !7vricv2c,emfv3 qvem,wqve3r7qnv57r1ev,kerv,ev3 qv3qeeqc,w3nvcqe!zqevr7v,e2,czfv,b3qcvkr5!evb,!kicqvr7vq,c3 nv3 rcv ,ev3,5q7v!3v,7zvmi3v!3v!7vrz!7ev;,ik3fv3 qvmr1qcve3r7qv!evr7vhrc,2fv!v ,;qvrczqcqzvcr7,7v3 qv,wwieqcv3rvcq3c!q;qv!3vbrcvhqnv!7vcq3ic7v!ve ,kkvzqe3cruv9,7z,cfv3 qvh!7zve3r7qv!evr7vq,c3 nv!vmi3v!3v!7v3 qve3,bbv!v2,;qv3rvkr5!nvti3v7r1v!v ,;qv q,czv3 ,3v!3v!evmr1qc!72v,vwutrc2v57r17v,ev3 qv;!e!r7fv3 qvcq,k!3uve3r7qv!evr7v3 qvwqkqe3!,kv q,zv57r17v,ev57r1 qcqfv!3v!ev1!3 v3,7qkqqcv3!;,7v!7v !evm,3 q3!wvwrkkqw3!r7nv2!b3qzv3rv !hvtuv3 qv,e2,cz!,7ev,b3qcv3 qvz,c5vqk;qevb,!kicqv!7v,wxi!c!72vbrcv3 qheqk;qefv3 qv3!hqve3r7qv!ev,kervr7vq,c3 nv1!3 v,v2crimvrbvercwqcqcenvwiccq73kuv2i,czqzvtuv3 q!cvkq,zqcnv3 qv,7w!q73vr7qfv3 qvk,e3ve3r7qnv3 qverikve3r7qnv ,evuq3v3rvtqvbri7znvti3v!v ,;qvmi3vhuvb,;ric!3qvz,i2 3qcnv2,hrc,nvr7v3rv!3ev3c,!knv,7zve qv ,ev7r3vz!e,mmr!73qzvhqvuq3fvr7wqv,ve3r7qv!evwrkkqw3qzv!v1!kkvtqv,tkqv3rv ,c7qeev!3evmr1qcvie!72v,v2,i73kq3v!v ,;qvrczqcqzv3 qvz1,c;qevr7v7!z,;qkk!cfv3 qv3!hqvbrcvwreh!wvrczqcv!ev7q,cnv,7zv1 q7v!vwrkkqw3v,kkv3 qve3r7qev!v1!kkv rkzvi7!;qceqv!7vhuv ,7zefv i2ev,7zv5!eeqenvv3 ,7re"
以上是我们截获的神秘信息。这些字符是字母数字,来自英语,包括一些分散的标点符号。我们也注意到了 7、3、v 等常见字符,但是手工解决这个是没有希望的。幸运的是,研究生院教了我们关于 MCMCs 的知识,我们觉得它可能很适合这个问题。MCMC 算法有 7 个步骤,如下所示:
第一步 —选择一个随机的解决方案。
第 2 步 —将解决方案应用于问题。
第 3 步 —评估这种方法的效果如何。
步骤 4 —对溶液进行 1 次调整。
第五步 —应用新的解决方案解决问题。
第 6 步 —重新评估我们的解决方案。
步骤 7 (a) —如果新的解决方案具有更好的分数,它将成为当前的解决方案,我们从步骤 4 开始重复。否则:
步骤 7(b)-计算新解和旧解的比值,然后在 0 和 1 之间随机选择一个数字。如果比率超过该数字,则接受该解决方案。如果不符合,则拒绝该解决方案。不管怎样,我们从第 4 步开始重复。
注意,步骤 7 (b) 通过有时允许“更差”的解决方案最终提供更好的答案,允许探索更大百分比的潜在解决方案空间。接受这些“更差”解决方案的概率取决于它们有多差。这通常被称为“局部极小问题”。
然而,有一个问题:我们如何衡量解决方案的效果?我们需要一个经验分数来告诉我们两个解决方案中的哪一个更有可能是真正的解密消息。
为此,我们查看相邻的字母。例如,在加密的消息中,第一个字符串之一是“!kzcq7nv3”。我们可以计算在英语中,’ k ‘跟在’!'后面的可能性有多大,或者“z”跟在“k”后面,依此类推。然后,如果我们随机改变一个字母,我们可以看到新的字母配对是更多还是更少可能来自英语单词。为了得到这些配对概率,我们将需要一个巨大的英语单词语料库——最好包括漫威单词,如复仇者联盟、灭霸或绿巨人。为此,我们可以抓取整个漫威维基(参见 GitHub ),并计算每个字母跟随另一个字母的频率。
Python 字典,包含漫威维基中“b”后面的字母的频率。
由此,我们发现字母配对“ba”出现了 41,943 次,而“bn”只出现了 141 次(“subnet”和“Kly’bn”,如果你想知道的话)。然后我们可以将这些计数转换成百分比。因为这些百分比往往很小,所以取它们的对数来使它们的值正常化是有意义的。这将把 0.0001%这样的值变成-4。现在我们有了每个字母配对及其各自对数似然性的字典,我们可以通过简单地将每个字母配对的所有对数似然性相加来评估任何解密消息的尝试。例如,如果我们评估字符串“hello ”,对数似然将是-8.6,而字符串“z9kk3”将是-32.6。这是因为在漫威维基(或任何英文文本)中,“他”远比“z9”更常见,等等。
假设我们现在有一个函数来评估任何潜在的解决方案,我们可以实现 MCMC 方法来尝试解密消息,代码如上。
我们从步骤 1 开始,随机选择一个解决方案,并评估其得分情况。应用第一种解决方案会呈现以下“解密”消息:
“我;1vd5awx47。VX;。d x;vnq1c x;。c;x:x1!。x;我;8wxn。;h5n4n4at!5td5 我;”
这种可能性的对数为-11,396。然后,我们通过交换字母配对对解决方案进行一次更改,对模型重新评分,并确定这是否使解决方案更有可能或更不可能。冲洗并重复。到第 1000 次迭代时,分数显著提高到-4,792,解密后的消息现在为:
“fyalpimoc NHA sp as if aprtalef asea j lus afy AGC rsavmrrnoabumbimafya”。
它仍然远不可读,但空间看起来很自然,数字/不当的标点符号已经消失了。
到第 3000 次迭代时,该消息开始看起来几乎是英语,得分为-3891:
《儿童》作者:hreas 氏族,mulmil 作者:
在第 7000 次尝试时,我们可以读到信息的开头一行:
“我的孩子。是时候执行我的伟大计划,实现我的
直到第 24,000 次迭代,上面的句号才被逗号正确地切换,分数才收敛到其全局最优值-3,451。最终解决方案如下(警告 —漫威几部电影的部分剧透!):
My children, the time has come to execute my great plan and fulfil my destiny. The plan, as you know, is to use the cosmic entities known as the infinity stones to wipe half of the universe out of existence so that the other half may thrive. Our greatest challenge has been finding the stones in this vast universe, but now they are within our grasp. The space stone, knows also as the Tesseract, resides on Asgard. after Loki's failure on earth, Thor has taken it and put it in Odin's vault. The power stone is on Morag. I have ordered Ronan the accuser to retrieve it for me, in return I shall destroy Xandar. The mind stone is on Earth, I put it in the staff I gave to Loki, but now I have heard that it is powering a cyborg known as the Vision. The reality stone is on the celestial head known as Knowhere. It is with Taneleer Tivan in his pathetic collection, gifted to him by the Asgardians after the dark elves failure in acquiring it for themselves. The time stone is also on earth, with a group of sorcerers, currently guarded by their leader, the Ancient One. The last stone, the soul stone, has yet to be found, but I have put my favourite daughter, Gamora, on to its trail, and she has not disappointed me yet. Once a stone is collected I will be able to harness its power using a gauntlet I have ordered the Dwarves to make for me on Nidavellir. The time for cosmic order is near, and when I collect all the stones I will hold Universe in my hands. Hugs and kisses, Thanos
(感谢超级漫威极客鲍勃·加德为我写下这篇文章。)
你很快打印出这条信息,并迅速传给你的老板。几个小时后复仇者们就集合起来了,他们正在制定保护石头和击败灭霸的计划。你很快被提升为高级数据科学家,并获得了可观的加薪。
但是,根据漫威漫画,存在着具有无限可能性的无限宇宙。在所有这些中,你成功地破译了信息并击败了灭霸吗?为了测试这个假设,我们可以重新运行 MCMC 算法 100 次,看看它收敛到正确解的次数。
100 次独立重复的算法每次迭代的对数似然性。
从上面我们可以看到,它并不总是成功地达到全局最大值。事实上,我们可以看看最终对数似然的分布,看看这 100 次中有多少次我们接近最优。
100 次独立重复的最终对数可能性的频率。
从这里,我们发现在 100 个宇宙中,我们有 50%会正确地解密信息并拯救地球。但是其他 50 次呢?他们会看到什么信息?下表让你知道,根据算法收敛的分数,你会向你的老板尼克·弗瑞提出什么解决方案。
然而,很可能通过足够的迭代,大多数问题最终会找到正确的答案。
最后一个例外,它落入了一个几乎不可能恢复的陷阱。常见的字母几乎都被数字取代了。鉴于数字最有可能跟在其他数字后面,任何用字母替换单个字符的尝试都会遭遇对数似然性的灾难性下降,这几乎永远不会被接受。
就拿*“孩子”这个词来说吧。在最低分的尝试中,它被解密为:. 46!?327、。如果该算法将【2】换成了正确的字符【r】,它将不会提高给定的分数【32】**【27】将会比漫威维基中的【3r】和【r7】*出现得更频繁。
一个简单的解决方案是在算法开始时重复步骤 1-3(选择全新的随机解决方案并评估它们)几次,然后继续执行其中最高的执行。通过包括这一点,并将迭代次数增加到 100,000 次,我们能够在 100%的时间内接近解决方案(1 或 2 个不正确的字符)。这不仅拯救了我们的宇宙,也拯救了所有发现自己处于同样困境的多节诗。
GitHub:https://GitHub . com/JackWillz/Projects/tree/master/MCMC % 20-% 20 enigma % 20 thanos
你已经看到文章的结尾了!我叫 Jack J,是一名将人工智能应用于竞技游戏和电子竞技的专业数据科学家。我是 iTero 的创始人。GGT23和jung . GG。你可以在 Twitter 上关注我,加入 iTero Discord 或者给我发邮件到 jack@itero.gg 。下一场见。
打破游戏:潘德雷肯四梅林的崛起
图片此处
在我的第一个潘德雷肯四人组博客中,我介绍了我为手机游戏《命运大令》( FGO)设置的多智能体强化学习(RL ),我列出了几个目标:
1)为游戏添加支持
FGO 没有玩家对玩家的方面,基本上所有的角色都可以使用,但它仍然有一个合理定义的元。在游戏中,元粗略地描述了比其他人更占优势的策略、角色或武器。在 FGO,元在很大程度上是由支持角色定义的,这些角色可以实现强大的/主导的策略。对于 FGO 的北美服务器来说,第一个真正的游戏突破和元定义支持是 2018 年底发布的 Merlin。
花之法师梅林是 FGO 版的魔术师/巫师/德鲁伊,大多数人都熟悉他是亚瑟王传说中的国王创造者。我说梅林在《FGO》中是一个超定义角色,因为他提供治疗来帮助团队承受敌人的伤害,提供无敌能力,充能团队的终极能力,如果这些还不够,他还可以极大地放大团队的伤害输出。
因此,如果标题和过去的几个段落还不足以作为铺垫,我决定将梅林作为一个角色添加到我的游戏环境中,以训练一个代理人使用梅林的能力。
2)使用某种多代理框架清除最终游戏内容
我暂时不打算正式尝试清除任何种类的后期游戏内容,但加入梅林让我不得不这样做,以便为代理人提供足够的挑战。所以我选择了一个相对高级的任务来复制成一个环境,并建立了一个机器人团队来完成它。
3)让这个项目的某个版本被某个地方接受为一个讲座。
谁知道这是否会发生,但我肯定会尝试。
梅林打破了游戏
梅林对 FGO 的介绍基本上打破了游戏规则,因为他加入了大量的治疗和伤害提升,使得原本具有挑战性的内容变得相当简单。当我把他编进代码,开始和他一起训练机器人团队时,我发现梅林也破坏了我的游戏环境。
Merlin 的技术实现
从技术角度来看,梅林和我以前的特工略有不同,他们都是伤害交易者类型的角色。我之前为他们制造的伤害制造者基本上都有影响他们自己或者整个团队的能力。因为每个角色有三种能力,所以每个角色的行动空间是 4,包括传球选项。然而,梅林最终的行动空间是 6。梅林的能力是全队增益,全队无敌,和有针对性的伤害提升。两个全队技能代表两个可能的动作,传球是第三个,目标伤害提升用三个可能的动作表示,动作空间为 6。有针对性的伤害提升是我的一个潘德雷肯特工新增加的,我基本上让一个技能有三种可能的行动,我让梅林特工选择谁是这个技能的目标,这样特工就可以选择对团队中的三个角色中的任何一个使用这个技能。
除了这些技能之外,梅林也是我添加的第一个终极技能,高贵幻象(NP)与伤害无关的角色。在我的自定义游戏环境中,当以前的角色将他们的 NPs 充能到 100%时,我会让他们只造成一些伤害,但对于梅林,我不得不做一些修改。梅林的 NP 被称为“阿瓦隆花园”,我实际上利用了我添加的机制来跟踪技能及其持续时间的效果。因此,每当梅林在游戏环境中将他的 NP 充到 100%时,他的 NP 就像技能一样应用到他自己和其他特工身上
直接后果
一旦我把梅林编码成一个角色,游戏环境能够处理他,我发现我有一个有趣的问题。在我最困难的游戏环境中,我的代理团队一初始化就赢了 90%以上的时间。从表面上看,这是一件坏事。我发现,在这种设置中训练的特工基本上什么都不做。他们不会使用技能,他们实际上永远不会做任何有趣的事情…相比之下,我以前的机器人做过的最好的事情是,一旦它们经过完全训练,胜率在 85-90%之间。
不同的是梅林。
原图此处
本质上,梅林作为一个角色提供了如此多的功能,机器人基本上可以做他们想做的任何事情,并且仍然获胜。他的 NP 阿瓦隆花园允许机器人有效地治疗团队受到的几乎所有伤害,梅林的伤害 buffs 允许代理团队赢得胜利,不管他们单独做了什么。在我的游戏环境的那个版本中,机器人团队的奖励基于胜利,胜利+1,失败-1。然而,在团队所做的一切都是胜利的情况下,得到强化的行动是最常见的。
每个角色有三种能力,每次任务允许使用一次。一个普通的任务持续 7-15 回合,所以大部分时间他们必须通过。所以有了这个设置,这意味着机器人学会了pass
,因此什么也不做。
跟着梅林学习
我花了几天时间才想出如何处理这个问题,因为从技术上来说,机器人正在获胜,并且做得很好,但它们只是没有学会我认为有用的行为。我的一部分只是想继续让游戏环境变得越来越困难,但在某一点上,环境将不再像一个合理的 FGO 水平。所以训练环境将不再真正代表实际的比赛。
我在这里的突破来自于我重读安德烈·卡帕西的博客关于教一个 RL 代理玩乒乓的时候。
安德烈·卡帕西的博客很值得一读!
如果你还没有机会并且对 RL 感兴趣,它值得一读!无论如何,我在重读中注意到的是,Andrej 注意到我们应该做的是:
鼓励和劝阻大约一半的行为
这让我想到了我和梅林的情况,以及他造成的困难。在我目前的实现中,我没有贴现未来的奖励,只是根据输赢应用了一个简单的+1 和-1 奖励,所以博客中列出的一些方法并不适用。阻止一个代理人采取的大约一半的行动的概念确实如此,问题是如何阻止。
我做的第一件有效的事情是设置机器人必须获胜的回合限制,否则他们实际上会收到少量的负面奖励。例如,回合限制为 12,如果机器人在 10 回合中获胜,它将获得全额+1 奖励,如果它在 13 回合中获胜,它将获得-.25 奖励,如果它失败,它将获得全额-1 惩罚。这种奖励结构意味着机器人将会知道他们不能只是赢,而是必须快速赢。
然而,这种方法对机器人应该以多快的速度获胜施加了一个略微人为的限制。为了解决这个问题,我最终做的是让机器人必须比过去的自己赢得更快,才能获得全额奖励。
由于我已经跟踪了在 1000 个游戏周期内赢得的游戏数量,作为我训练指标的一部分,我开始记录这些游戏有多长,并使用一个 1000 个游戏周期内游戏的平均长度来设置为机器人团队收集全部+1 奖励所需的回合数。这意味着机器人总是试图比以前的自己赢得更快。
使用这种奖励方法,潘德雷肯四号学会了有趣的行为,即使是在加入梅林之后。所以,一旦我能够让机器人再次学习,并在我以前的游戏环境中获得 97%以上的胜率,我觉得是时候看看我是否可以训练机器人清除一些更难的 FGO 内容。FGO 任务的难度是根据通关团队的等级来评定的。到目前为止,我的大部分基准测试都是建立在一个中级任务的基础上的,这个任务在 40 级的农场中很常见。在 FGO,最高等级的任务实际上是 90 级,少数任务是 90+级,这通常是某种类型的 boss 战。我选择了一个 78 级的任务来构建更难的内容,这个任务被称为 FGO 故事中发生在塞勒姆女巫审判期间的绞架山上的处决地点。
行刑现场
虽然我可以选择一个不同的任务进行基准测试,但我选择 Gallows Hill Salem 任务的原因是因为它是游戏中我目前需要的一个名为“哭泣之夜之桩”的项目的最佳投放点。
为了提升角色的属性,你通常需要收集特定的材料。我正在制作的一个角色需要哀嚎之夜的木桩,完全升级需要 216 根木桩,平均需要运行 1.5 次才能放下木桩。是的……这个游戏有很多关于农业的内容。
建立关卡
关卡的结构遵循了后来游戏 FGO 内容的标准格式。从第一波到第三波,有三个难度增加的级别。
第一波相当容易,三个敌人的总血量是 38000。高水平的团队可以很快解决这个问题。
第一波敌人
第二波通过增加更强壮的敌人增加了难度。作为快速基准,这一波的敌人有 70813 点生命值,一个敌人的生命值相当于整个第一波。
第二波敌人
现在进入最后一波,第三波。对于这个任务,wave 3 有 290,058 HP。所以是前两次浪潮总和的两倍多。如果你长时间困在上面,这个会变得棘手,因为拥有 192K HP 的主要敌人每 4 回合就会发动一次强大的攻击。在对我的潘德雷肯四代理进行基准测试时,随机初始化的团队通常会进行到第三波,然后在试图削减敌人的 HP 时陷入困境并死亡。
挥动三个敌人
所以在建造这个关卡的过程中,我想做两件事。首先,适当地调整等级,这样代理团队将必须通过一个真实的健康等级。第二,为了增加难度,我想让特工们在冲锋后用更强大的攻击来对付他们的敌人。
第一点,与我之前的困难等级相比,我在每一波都给敌人增加了更多的生命值。第一波有 30 点生命值,第二波有 55 点生命值,第三波有 140 点生命值,总共 225 点生命值,比我之前 180 点的最高值有所提高。
对于第二点,我增加了机制让敌人每 X 回合造成更多的伤害。例如,这最后一波每 4 回合造成正常伤害+ 10 点额外伤害。代理作为一个团队有 30 总生命值,所以第三波的长期战斗可以很容易地击败代理团队。
一旦新的机制和规格到位,是时候训练和基准潘德雷肯四。
培训和结果
在我的其他各种管道改进后,我能够将环境编码起来,并决定让代理人扮演的团队。
这支队伍将由两个伤害经销商组成,梅林作为支援角色。这两个伤害处理者是伊师塔,我之前把她编为一个有用的角色,还有一个新的伤害处理者,昵称是尼禄·卡斯特,我想用她,因为她在这个级别有很好的匹配。
一旦团队就位,我们就可以开始行动了!
大致按照我对潘德雷肯四号的训练协议,我让机器人玩,并监控它们的进展。请参见下面的运行示例。训练开始于前 20,000 圈的高探索和学习率,这就是为什么在图的第一部分没有改善。然后我开始每转 10000 转左右降低探索率和学习率,直到 70000。正如我们所希望的,在训练过程中,输赢百分比会增加(蓝色),而在同一时间内,输赢的回合数会减少。
超过 70,000 场游戏平均轮到赢(红色)从 9.75 开始,到 7 点左右结束。整体胜率从 45%开始,到 80%结束。
这些训练结果令人振奋,因为机器人似乎在学习,这对它们来说似乎是一个足够的挑战,因为胜率从来没有特别高。
所以在理论上这似乎是成功的,但现在潘德雷肯四正在玩更困难的内容,我想把它与自己玩的水平进行比较。
打破潘德雷肯四人的游戏
为了测试潘德雷肯四人组的表现,我让潘德雷肯四人组训练有素的特工和我自己在实际的 FGO 游戏中玩了 10 轮处决,我们都在相同的限制下玩。
- 技能只能使用一次
- 一旦一个角色的高贵幻象(NP)充能到 100%,它就必须被使用。
- 波浪必须从前面打到后面(没有重新瞄准)
结果如下表所示:
为了进行基准测试,我包含了随机初始化的代理的运行。我在他们的“平均值”旁边加了星号,因为随机初始化的代理人会在前两波中蹒跚而行,到达第三波,然后因为长时间停滞不前而死去。我发现看这个令人沮丧,而且恢复一个团队并继续玩下去需要花费资源,这似乎对我来说是一种浪费,所以我在五轮左右后就停止了。相比之下,训练有素的潘德雷肯四特工和我本人实际上都没有失去水平。
作为一个人类玩家,我仍然利用了更多的游戏信息,比如每个人的指令卡属于哪个角色,我认为这帮助我比机器人玩得更快。然而,看到纸上的机器人行为,我实际上认为它会比我的人类策略差很多,但令人惊讶的是,机器人策略工作得很好,而且实际上相当一致。
在改进《潘德雷肯四》的过程中,我一直在做的一件事是,我想尽可能地把我自己和我对如何玩这个游戏的信念从管道中移除。这主要是通过切换到+1 和-1 奖励的纯政策梯度方法,并设计新的水平,而没有通过伤害提升或其他机制激励某些行动。看看这里的结果,我认为这种努力是相当成功的。
对立的策略
不管使用什么策略,对于这样一个任务来说,真正获胜的唯一方法是使用强大的伤害处理 NPs 来清除它。我的基本策略是保存我团队的 NPs,只在第三波的时候发射,以尽快清除他们。而潘德雷肯四号使用了一种非常不同的策略,实际上每场比赛两次发射本队的 NPs。
我的方法
作为一名玩家,我倾向于通过为最后一波敌人保留技能和 NPs 来玩 FGO,因为他们通常相当强大,为最后的艰难对抗保留火力是有意义的。所以从游戏性的角度来看,我通常会在第一波和第二波中不使用任何技能,或者只使用一些攻击 buffs 来更快地通过这些波。然后在第三波,我用我的团队的效用技能充能 NPs 到 100%并且相对快地赢了。所以在整个关卡中,我依赖于使用每个伤害制造者的 NPs 一次。
潘德雷肯四国的方法
然而,潘德雷肯四所做的几乎完全相反。潘德雷肯四号使用它的实用技能来攻击伊师塔和尼禄的 NPs,并立即清除前两波攻击,同时保留大部分战斗技能用于第三波攻击。一旦到了第三波,它开始发挥它的攻击 buffs 和梅林的支持能力,以增加它的回合伤害,治疗,并有能力重新充电到 100%的 NPs,并通过在关卡中第二次使用尼禄和伊师塔的 NPs 来赢得胜利。
打破潘德雷肯四人的方法
理论上,我认为这在实际的 FGO 等级中不会很顺利,因为我认为代理团队会在第三波中被卡住而死亡。然而,我感到惊喜,觉得我有一些东西要向代理商学习。
潘德雷肯四回合 1 伊师塔冲向她的 NP 并清除波浪
早期游戏:第一和第二波
从游戏性来看,似乎潘德雷肯四号使用它的 NPs 立即清除了前两波,因为它降低了可能的变化,并且非常一致地让机器人清除了那些初始波。它可能避免的一个危险是,有几次我以正常方式玩游戏,但意外地让 NPs 充满电,这意味着我被迫在糟糕的时候使用这些 NPs,并在不利的情况下进入第三波。这些跑了 9 圈或更多才完成,这意味着我比潘德雷肯平均速度慢 4 倍。所以潘德雷肯四人组决定使用那些 NPs 和实用技能,立即否定了这种潜在的危险。
潘德雷肯四回合 2:尼禄施法者给她的 NP 充电,并用它来清除波浪
进入第三波时,特工们的 NPs 充电量相对较少,所以作为一个人类,我会很担心,因为团队 NPs 的充电量越低,他们在 NPs 恢复之前在危险的第三波上花费的时间就越长。事实并非如此,因为潘德雷肯四号能够有效地使用梅林。
游戏后期:第三波
一旦游戏进行到第三波,潘德雷肯四号使用梅林的阿瓦隆花园,该花园给予队伍 5 轮治疗,每轮增加 5%的 NP。加上他的全队攻击 buff,每回合增加 20%的 NP 电荷,这意味着他可以在接下来的一段时间里给全队 45%的 NP 电荷。这与他所提供的持续性和不可战胜性相结合,给了团队足够的支持来度过任何潜在的伤害。
3 回合攻击 buffs 和梅林的 NP“阿瓦隆花园”。
我之前提到过梅林被压制了,我希望潘德雷肯四号能学会以有趣的方式使用梅林。我希望但不能保证看到的是,潘德雷肯四号学会了使用梅林提供的全队无敌技能来阻挡第三波的强大攻击。我提到过第三波每 4 回合使用强力充电攻击。潘德雷肯四号在训练中学会了这种模式,并利用梅林的全队无敌成功阻挡了这些攻击(见下文)。在正确的时间使用该技能,结合梅林用自己的 NP 提供的治疗,意味着机器人可以在第三波战斗中相当安全地战斗,直到他们通常能够为他们的 NP 充电并获胜。
梅林特工使用无敌来抵消充能敌人的伤害。
结束语
在这篇文章中,分解潘德雷肯四人组正在学习的策略是一次有趣的经历,因为我还没有真正研究过我的经纪人已经开发的战术方面。正如我提到的,我特别高兴的是,他们开发了一种不同于我用来玩 FGO 的游戏风格,因为它展示了强化学习方法的一些乐趣,并让代理自由探索他们的环境和行动空间。
比人类玩家更容易使用能力的倾向是我在其他 RL 项目中看到的有趣的一点,比如 OpenAI 的 OpenAI Five。人们对 OpenAI 五个代理人的评论是,他们对使用长冷却时间的能力没有人类那样有所保留,他们倾向于像我一样玩,并抓住能力寻找更“最佳”的时间来使用能力或冷却时间。这也可能是如何激励代理更直接地消费资源而不是保存资源的函数,因为如果他们保存了资源,就不能保证你将来会使用它。这种短期规划看起来很有趣,但我也想知道如何才能让代理在能力使用上更保守。看看我是否能让代理人在本质上更保守的想法可能是我试图让代理人更像“我”,而不是他们所需要的。
虽然他们的策略与我的不同,但仍然相当有效,我对他们的结果非常满意。我认为向他们扔一些不同结构的任务会很有趣。例如,有一些任务有非常强大的最终 bosses,我认为在任务早期燃烧法术很难清除。因此,这将是一次有趣的测试,看看潘德雷肯四人组如何适应这种难度。
展望未来,我认为我的很多工作将会围绕着增加更难的内容和训练代理人,这些代理人也许可以更好地概括不同的任务。我在 OpenAI 的作品中看到的一个有趣的笔记是关于等级和代理统计的随机化,以促进对他们环境的更大探索,以及他们的代理被训练成彼此的完美“克隆”的方式。这提供了一种可能性,有三个代理共享相同的重量,但可以自由地扮演任何一组 FGO 人物和明确的任务。
用伊师塔的 NP 结束游戏。尼禄·卡斯特上一轮用了她的。