TowardsDataScience-博客中文翻译-2019-八-

龙哥盟 / 2024-10-13 / 原文

TowardsDataScience 博客中文翻译 2019(八)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

卫报食谱(第 1 部分):探索性数据

原文:https://towardsdatascience.com/analyzing-the-guardian-food-recipes-from-2009-to-2019-11b83e12efdf?source=collection_archive---------25-----------------------

第 1 部分:探索性数据分析——卫报食谱

The Guardian Food Recipes by TheGuardian

介绍

《卫报》每天都会公布名厨的食谱。报纸的美食版为美食爱好者、业余厨师、饥饿的学生或疲惫的父母提供了新菜肴的灵感。它邀请业余厨师探索无限的烹饪世界,接触新的食材和风味,学习烹饪技术或为庆祝盛宴寻找灵感。简而言之,《卫报》的美食栏目吊起了每个读者的胃口。

然而,报纸上的烹饪文章揭示的不仅仅是食物成分。它们影响着饮食文化、消费者购买、读者饮食和传统的家庭食谱。此外,他们还充当年轻厨师的跳板,并维系着值得信赖和喜爱的厨师群体的建立。

我对网络搜集的好奇心以及对数据分析和食物的热情,自然而然地吸引我访问和探索这些报纸文章的内容。《卫报》是我开始研究时想到的第一份报纸,因此让我得以深入了解英国烹饪界。这篇文章的目的是呈现一些从 2009 年 1 月 1 日到 2019 年 6 月 16 日出版的《卫报》食物食谱的探索性数据分析

如果你觉得有点饿,想在阅读的同时吃点零食,你可以在这里找到所有有趣的食谱!

British Food Recipes — Established Belfast’s poached eggs, Jeremy Fox’s beet gazpacho (photo by Lizzie Mayson), Gill Meller’s roast chicken (photo by Romas Foord), Rebecca Oliver’s smoked mackerel sandwich (photo by Jean Cazals), River Cottage Strawberries (photo by Lizzie Mayson)

数据和方法

在开始我的分析之前,我首先需要收集数据!这是通过使用美汤和请求的网页抓取完成的。因为这是我第一次体验,所以不像烤馅饼那么简单。我花了几个小时通读食谱页面的 HTML 代码,查看每个元素的存储位置。我很幸运地找到了其他媒体成员的巨大帮助,尤其是来自克里·帕克的教程和 Ritvik Kharkar 的文章。

我总共收集了 7,361 篇食谱文章,最早的一篇可以追溯到 2009 年 1 月 3 日,最近的一篇是 2019 年 6 月 16 日。在浏览食谱网址时,我特别注意检索以下七条信息:

  • 出版日期
  • 文章标题,或者,如果你喜欢,食谱标题
  • 文章副标题,一句话描述食谱
  • 文章内容、配方文本和配料表
  • 作者姓名
  • 评论数量和文章被分享的次数

有些文章没有关于上述要素的信息,因此,如果没有找到一个要素,将写下“无”。第二步,我删除了没有作者和字幕的食谱。

分析食谱

以下图表说明了为更好地理解《卫报》的烹饪遗产所采取的分析步骤。在此,我提出以下初步分析:

  • 每年每月的食谱数量
  • 每年最著名的五位厨师(根据出版的食谱数量)
  • 每年最著名的种类(根据食谱数量)
  • 为特殊场合发布的食谱的百分比
  • 十个最常分享的食谱
  • 评论最多的十种食谱

每年每月的食谱数量

下面的条形图显示了 2009 年至 2019 年期间每年发布的食谱数量,以及全年每个月的食谱数量。有趣的是,在 2012 年之后,食品食谱的出版数量有所上升,在 2013 年达到顶峰,共有 882 种食谱。此后,这一数字又略有下降,但从那时起,平均每天发布 2 个食谱。

你对 2019 年的猜测是什么?厨师们会有创意,发表比 2013 年还要多的作品吗?

The bar charts show the number of recipes published each year and each month between 2009 and 2019.

年度五大名厨

看看对《卫报》食谱贡献最大的五位作者,就能洞察厨师们的受欢迎程度。这一年有变化吗?有没有一个厨师得到了更多的关注,并因此获得了在自己的专栏中发表文章的特权?下面的交互图显示了每年发布食谱数量最多的五位厨师。

乍看之下,奈杰尔·斯莱特和约塔姆·奥托林吉是最负盛名的美食食谱作者,这是无可争议的。自 2009 年以来,两位厨师不断为卫报烹饪遗产做出贡献,影响人们购买、准备、烹饪、分享和食用食物的方式。更糟糕的是注意到奈杰尔·斯莱特可能像煎锅上的爆米花一样忙碌,因为他每年贡献超过 100 份食谱。因此,他超越了所有其他厨师!

另一个有趣的点是 2013 年后投稿作者的转变。从 2009 年到 2012 年,厨师丹·莱帕德和休·费恩利-惠汀斯塔定期为《卫报》撰稿。然而,自 2013 年以来,他们的贡献已经停止,让年轻的厨师接手 Top Banana。去年,2018 年,今年,米拉·索达,安娜·琼斯和汤姆·亨特加入了前五名。

The stacked bar chart shows the most popular chefs from 2009 to 2019 (per percentage of the total recipes published each year).

一些快速的事实关于上面的一些厨师!

丹·莱帕德因他惊人的糕点食谱而闻名!如果你正在寻找一个入口即化的食谱,你可能会喜欢丹的食谱。他教授所有烘烤最漂亮、最奢华的糕点、蛋糕和面包的技巧。休·费恩利-惠汀斯托尔因他是河边小屋的跑步者而闻名,也因他发起的与食品生产相关的环境问题运动而闻名。如果你想真正发现用季节性的、当地的和可持续的英国原料准备的典型的英国食物,那么休·费恩利-惠汀斯托尔的食谱将会适合你!

自 2013 年以来,与《卫报》分享美食食谱的厨师名人不断更换。Meera Sodha 因其庆祝印度蔬菜的菜肴而闻名。如果你正在寻找一个去东方目的地的逃脱之旅,Meera 的食谱会让你尝一尝。安娜·琼斯因其蔬菜烹饪而闻名,这种烹饪尊重当地产品的季节性。她透露了在伦敦哪里可以找到最美味的香草作为午餐。最后,汤姆·亨特以尊重自然和人类的多样性而闻名。如果你不知道如何利用你的西兰花茎、你的棕色香蕉或吃剩的面包,那么汤姆的建议会让你大吃一惊。

Highest contributing and new chefs of the Guardian: Nigel Slater, Yotam Ottolenghi, Meera Sodha, Hugh Fearnley-Whittingstall, Anna Jones, Dan Lepard, Tom Hunt (Pictures from their own Instagram account).

年度最佳类别

看看每年的顶级类别,可能会发现与贡献最高的厨师有一些相似之处。这是一些厨师拥有个人食谱专栏的结果,因此他们的大部分食谱都是这样归类的。

在您与下图互动之前,我发现特别有趣的是,有些类别反映了一些全球食品和健康趋势。例如,Yotam Ottolenghi 在 2008 年至 2010 年间写的“新素食主义”类别可能引领了素食主义的当前趋势,以及越来越多的英国人减少饮食中的动物产品。致力于甜食的类别,如丹·勒帕德的“如何烘焙”和鲁比·坦多的“鲁比烘焙”直到 2015 年都在前十名之列。虽然对烘焙的热爱并没有消失,英国烘焙大赛的食谱仍然刊登在《卫报》上,但随着英格兰公共卫生部努力解决肥胖危机,它们的重要性可能在某种程度上有所下降。

The stacked bar chart shows the most popular categories from 2009 to 2019. (Per percentage of the total recipes published each year).

英国的节日和食物

像圣诞节或复活节这样的节日与食物有着内在的联系。这些场合的菜肴都是精心挑选的。一些家庭会提前几天计划菜单,尝试一些新的食谱以及准备传统的家庭食谱!这些场合为厨师、餐馆、食品公司和食品零售商提供了一个激发业余爱好者灵感和诱惑你贪吃的绝佳机会!

下面的图表显示了各种场合的食谱(情人节、复活节、万圣节、篝火之夜、圣诞节、新年)在每年和每月公布的食谱总数中所占的百分比。

The bar chart shows the percentage of recipes for each occasion for each year, each month from 2009 to 2019. (Per percentage of the total recipes published each year, each month)

有趣的是,圣诞节的食谱在 10 月份左右开始出版,在 12 月份占所有食谱的 30%。篝火之夜,也被称为盖伊·福克斯之夜,是英国和一些英联邦国家的传统纪念活动。这个节日在 11 月 5 日庆祝,全国各地都会燃放大型烟花和篝火。通常,家人和朋友会聚在一起享受奶酪土豆、奶油南瓜饼、松脆的太妃糖苹果或粘稠的巧克力棉花糖!

British Festivities Recipes — Liam Charles’ shortbread (photo by Yuki Sugiura), Joe Trivelli’s traditional Easter roast (photo by Jean Cazals), Yotam Ottolenghi’s deviled eggs (photo by Louise Hagger), Yotam Ottolenghi’s alternative Christmas recipes (photo by Louise Hagger), Nigel Slater’s trout tartare, turkey, pumpkin, quince pie (photo by Jonathan Lovekin).

分享最多的 10 道菜,评论最多的 10 道菜

看看十个分享最多的和十个评论最多的食谱,可以让你对读者的兴趣或引起读者争议的文章有一个有趣的了解。下表列出了分享和评论最多的食谱以及它们背后的作者。

毫不奇怪,最著名的厨师也是最受欢迎的。显然,读者喜欢分享他们的圣诞食谱!读者也喜欢学习技巧和诀窍,因此,“如何烹饪”食谱也很受欢迎!另外,请注意“Yotam Ottolenghi 的学生超便宜食谱”的高分享数!学生知道在哪里可以找到最好的食物,对吗?

The table shows the ten most shared recipes (by number of shares)

评论最多的食谱显示了读者对一篇文章的关注程度。这说明文章给了读者思考的食粮!看看下面的食谱和它们的评论,看看食物如何密切影响我们的情绪,有时会引起钦佩、惊讶或愤慨。

The table shows the ten most commented recipes (by number of comments)

结论

该结束了!:-)这篇文章探讨了 2013 年 1 月至 2019 年 6 月发表在《卫报》上的大约 7361 种食物食谱。探索这些食谱并更多地了解著名的英国厨师真是令人愉快。

如果你有兴趣看我的预处理步骤,我是如何挑选,清洗,切碎,调味并最终整理众多数据的,你可以看看我在这里的 GitHub 库!

菜单上的下一道菜是什么?

下一餐(《卫报》食品文章第二部分)将会带来更多你喜欢向其学习的厨师的风味,并展示每个季节你应该准备的食物。我将向您展示我的自然语言处理(NLP)分析的结果。做好准备,看看被切碎的食谱吧!

感谢阅读!奥德

洗碗之前!

我希望你喜欢这篇文章,如果你想留下任何意见,建议或想法,我真的很感激!所以,请随时伸出手来!

也非常感谢 Medium 的成员分享他们的工作,并提供有用的教程,总是让我对有用的工具和方法有新的见解!

PostScriptum:请注意,通过查看《卫报》的美食食谱,我只是为你提供了英国美食界的一个小概览,因此,可能会错过一些你喜爱的美食名人。

我是 数据和植物科学家 垂直未来 ,先前在WBC SD。理学硕士。在城市分析和智能城市方面,来自 UCL 的 Bartlett 伦敦的 CASA 和 BSc。在食品科学中从 苏黎世联邦理工学院 。对城市、美食、健康充满热情通过TwitterLinkedIn联系。

使用 R (ggplot2)以商业分析师的心态分析泰坦尼克号

原文:https://towardsdatascience.com/analyzing-the-titanic-with-a-business-analyst-mindset-using-r-ggplot2-ee5355a4dab3?source=collection_archive---------12-----------------------

最近,我迷上了 R 编程软件和 Hadley Wickham 创造的奇妙的数据可视化包( ggplot2 )。我的职业是商业分析师,在电子支付行业有着丰富的经验,但我对数据分析、可视化和向利益相关者传达数据充满热情。

撰写这篇文章的动机

嗯,为什么是泰坦尼克号……有人可能会问?巧合的是,我决定再看一遍《泰坦尼克号》电影,但这一次是以商业分析师的心态,受到数据分析力量的启发。我第一次看这部电影时,脑海中有几个关于泰坦尼克号上发生的事情的问题,但当时没有找到答案。这一次,我受到数据分析的解决方案驱动本质的启发,决定通过在谷歌上获取无处不在的大型数据集来寻找我自己问题的答案。

我从几个关于泰坦尼克号沉船事件的探索性问题开始了我的分析(我问了很多问题,我猜你们都已经知道了:)。下面的可视化仪表板在我的分析过程中实现了。

Titanic Dashboard

探究问题

  1. 泰坦尼克号上的存活率是多少?
  2. 我如何用数据来形象化泰坦尼克号上的救援人员采用的妇女和儿童优先的方法?
  3. 泰坦尼克号上的年龄分布是怎样的(幸存者和遇难者)?
  4. 泰坦尼克号上按船票等级划分的幸存者年龄分布是怎样的?
  5. 一个多世纪以前,泰坦尼克号是最贵的船,那么所有船票等级的票价是如何比较的呢?

如果你看过这部电影,那么你就来对地方了,如果你没有,那么你就是我发现的目标。也许,你会决定马上看。现在,让我们开始吧。

加载包和浏览数据

让我们从加载包开始,我们将使用这些包来创建用于分析的可视化。Tidyverse 软件包将有助于数据处理和绘图。

加载相关库,将保存在电脑驱动器上的泰坦尼克号数据集导入 R 工作室。

注意:源数据帧不包含机组人员的信息,但包含几乎 80%乘客的实际和估计年龄

library(tidyverse)titanic <- read.csv(file.choose())

检查数据集的结构(变量名和变量类型)。这一步对于确定变量是否适合绘图至关重要。

#Check out the structure of the dataset
summary(titanic)
str(titanic)
names(titanic)
head(titanic.df, n = 10)#Remove rows with NA
titanic.df <- filter(titanic, survived != "")

首先,清理数据集以移除或替换丢失的值。

数据集中的列如下所示:

  • Pclass: 票类(1 = 1 号,2 = 2 号;3=第三)
  • 幸存:幸存 ( 0 =否;1 =是)
  • 姓名: 乘客姓名
  • 性别:性别(男或女)
  • 年龄: 乘客 年龄
  • SibSp: 船上兄弟姐妹和/或配偶人数
  • Parch: 船上父母和/或子女的数量
  • 票号: 票号
  • 票价: 票价价格(英镑)
  • 座舱:座舱座舱
  • 已装船 : 装船港(C =瑟堡:Q =皇后镇:S=南安普顿)
  • : 救生艇
  • 车身 : 车身识别号
  • home.dest : 乘客家或目的地的地址

下一步是我们需要决定我们需要什么样的变量和合适的比例来可视化我们的数据。我使用了下面的表格分类,

使用 ggplot2 进行可视化

来回答我们的第一个问题,泰坦尼克号上的存活率是多少?

按班级排列(*第一、第二和第三),幸存的女性比例分别为 97%、89%和 49%。

按等级(*第一、第二和第三)排列,男性存活率分别为 34%、15%(约 14.6%)和 15%(约 15.2%)。

运行 下面的代码生成相应的可视化效果:

ggplot(data = titanic.df) +
  aes(x = age, fill = survived) +
  geom_histogram(bin = 30, colour = "#1380A1") +
  #scale_fill_brewer(palette = "Accent") +
  labs(title = "Survival rate on the Titanic",
       y = "Survived",
       subtitle = "Distribution By Age, Gender and class of ticket",
      caption = "Author: etoma.egot") +
  theme_tomski() + # using a custom theme for my visualizations
#theme_bw()+ #Use the inbuilt ggplot2 them for your practice facet_grid(sex~pclass, scales = "free")#Proportion of 1st, 2nd and  3rd class women and men who survivedmf.survived <- titanic.df %>%
  filter(survived == 1)%>%
  group_by(pclass,sex)%>%
  summarise(Counts = n()
  )mf.died <- titanic.df %>%
  filter(survived != 1)%>%
  group_by(pclass,sex)%>%
  summarise(Counts = n()
  )mf.perc.survived <- mf.survived/(mf.survived + mf.died) * 100
select (mf.perc.survived, Counts)

Survival Rate on the Titanic

结果解读:

  • 该图有助于确定考虑到所有三个变量(年龄、性别、机票等级)的存活率模式。
  • 按班级排列(*第一、第二和第三),幸存的女性比例分别为 97%、89%和 49%。
  • 按等级(*第一、第二和第三)排列,男性存活率分别为 34%、15%(约 14.6%)和 15%(约 15.2%)。
  • 在一年级和二年级的学生中,除了一年级的一名女生外,所有的孩子都活了下来。三年级的孩子死亡率更高。

对于我们的第二个问题,我如何用数据来证实泰坦尼克号上的救援人员采用的妇女和儿童优先的方法?

救援人员首先考虑的是儿童和妇女,在所有级别中,优先考虑的是妇女、儿童和至少 60 岁的老年人。

运行代码以获得以下可视化效果:

titanic.df %>%
  filter(fare <= 300)%>%
  ggplot(mapping = aes(x = age, y = fare)) +
  geom_point(aes(colour = survived, size = fare, alpha = 0.7)) +
  geom_smooth(se = FALSE)+
  facet_grid(sex~pclass, scales = "free") +
  labs(title = "Priority and pattern of rescue on the Titanic",
       x = "Age (yrs)",
       y = "Fare(£)",
       subtitle = "Children and women in order of ticket class were\nconsidered first in the rescue plan with priority been\nwomen, children and older adults >= 60yrs", 

       caption = "Author: etoma.egot") +
  theme(
    plot.subtitle = element_text(colour = "#17c5c9",
                                     size=14))+
           theme_tomski()  #using a custom theme

Priority and pattern of rescue on the Titanic

结果解读

  • 遵循上图中的分布结果。(票价与机票等级成正比)。抛开儿童这个事实(<=12) on the titanic were charged separate boarding fares. It seemed like the fares for children and teens seem unusually high when compared with average fares for non-children age groups. Let me know if you know why this is so.
  • Nonetheless,the bubble chart gives some other clues in regards to the pattern of rescue operations. Evidently, Women and Children first approach in order of ticket class was adopted in the rescue plans by rescuers with priority been women and children and older adults at least 60yrs across all classes.
  • Apparently little or no priority was given to male passengers by rescuers

注意:我从气泡图中移除了异常票价(500)。支付这些费用的男性和女性无论如何都获救了。

我使用箱线图来可视化接下来的三个问题:

继续第三个问题,泰坦尼克号上的年龄分布是怎样的(幸存者和遇难者)?

总的来说,泰坦尼克号上的男性比女性平均大 3 岁。

titanic.df %>%
    ggplot(mapping =  aes(x = pclass, y = age)) +
  geom_point(colour = "#1380A1", size = 1) +
  geom_jitter(aes(colour = survived))+ #This generates multiple colours
  geom_boxplot(alpha = 0.7, outlier.colour = NA)+
  labs(title = "Age Distribution by Class on the Titanic",
       x = "Ticket Class",
       y = "Age(Yrs)",
       subtitle = "The males on the titanic were older than the females by an average of 3yrs across all ticket classes ",
       caption = "Author: etoma.egot") +
  theme_tomski() +   #using my own custom theme
  theme(plot.subtitle = element_text(
                                     size=18))+

  facet_wrap(.~sex)#Calculating Mean and median age by Class and Gender for adults
titanic.df %>%
    group_by(pclass, sex)%>%
  summarise(
    n = n(), #count of passengers
    Average.age = mean(age, na.rm = TRUE),
    Median.age  = median(age, na.rm = TRUE)
  )

Age Distribution by Class on the Titanic

成绩解读

负偏态 —箱线图将显示更接近上四分位数的中位数
正偏态 —箱线图将显示更接近下四分位数的中位数

  • 大约 75%的女性(第一、第二、第三名)至少在 22 岁、20 岁和 17 岁之间。年龄中位数为 36 岁(正态分布)、28 岁(负偏态)和 22 岁(正偏态)

  • 大约 75%的男性年龄至少在 30 岁、24 岁和 20 岁之间。年龄中位数为 42 岁(负偏差)、30 岁(正偏差)和 25 岁(正偏差)

#概要:
一般来说,在所有船票等级中,泰坦尼克号上的男性比女性平均年长 3 岁。

随后,对于第 4 个问题,泰坦尼克号上按船票等级划分的幸存者年龄分布是怎样的?

第一类中男性和女性幸存者的平均年龄相同(36 岁)
-第二类中女性比男性大 1.5 倍
-第三类中男性比女性大 2 岁

titanic.df %>%
  filter(survived ==1)%>%
  ggplot(mapping =  aes(x = pclass, y = age)) +
  geom_point(size = 1) +
  geom_jitter(colour = "#1380A1")+ 
  geom_boxplot(alpha = 0.7, outlier.colour = NA)+
  labs(title = "Survivors Age Distribution by Class on the Titanic",
       x = "Ticket Class",
       y = "Age(Yrs)",
       subtitle = "The median age of male and female survivors in 1st class was the same(36 yrs)\nThe females in 2nd class were 1.5 times older than the males\nThe males in 3rd class were older than the females by 2yrs",
       caption = "Author: etoma.egot") +
  theme_tomski() +   #using my own custom theme
  theme(plot.subtitle = element_text(colour = "#1380A1",
                                     size=18))+
  facet_wrap(.~sex)#Calculating Mean and median age by Class and Gender for adults
titanic.df %>%
  filter(survived ==1)%>%
  group_by(pclass, sex)%>%
  summarise(
    n = n(), #count of passengers
    Average.age = mean(age, na.rm = TRUE),
    Median.age  = median(age, na.rm = TRUE)
  )

Survivor age distribution by class on the Titanic

结果解释

女性
——年龄中位数为 36 岁(正态分布)、28 岁(负偏态)和 22 岁(正偏态)

男性
——年龄中位数为 36 岁(正偏)、19 岁(负偏)和 25 岁(负偏)

#总结:
-第一类男性和女性幸存者的平均年龄相同(36 岁)
-第二类女性比男性大 1.5 倍
-第三类男性比女性大 2 岁

最后,关于最后一个问题,泰坦尼克号是一个多世纪前最贵的船,那么所有船票等级的票价值如何比较?

头等票的价格大约是二等票的三倍,二等票的价值大约是三等票的两倍。

#Prepare Data, remove outliers in fare
titanic.df %>%
  filter(fare < 300)%>%
      ggplot(mapping =  aes(x = pclass, y = fare)) +
  #geom_point(colour = "#1380A1", size = 1) +
  #geom_jitter(aes(colour = survived))+
  geom_boxplot(colour = "#1380A1", outlier.colour = NA)+
  labs(title = "Fare Value by Class",
       x = "Ticket Class",
       y = "Ticket Fare (£)",
       subtitle = "1st class ticket was worth 3 times a 2nd class ticket\nand 2nd class ticket was worth almost twice that of 3rd class",
       caption = "Author: etoma.egot") +
  theme_tomski()+ #using my own custom theme 
  theme(plot.subtitle = element_text(colour = "#1380A1",size=18))+

  coord_cartesian(ylim = c(0,125))+
  coord_flip()#Calculating Mean and Median Fare by Class
titanic.df %>%
  filter(fare < 300)%>%
    group_by(pclass)%>%
  summarise(
    Average.fares = mean(fare, na.rm = TRUE),
    Median.fare  = median(fare, na.rm = TRUE)
  )#Calculating Mean and Median Fare by Class for children
titanic.df %>%
  filter(fare < 300, age <= 12)%>%
  group_by(pclass)%>%
  summarise(
    n = n(),
    Average.fares = mean(fare, na.rm = TRUE),
    Median.fare  = median(fare, na.rm = TRUE)
  )#Calculating Mean and Median Fare by Class for adults
titanic.df %>%
  filter(fare < 300, age >= 12)%>%
  group_by(pclass)%>%
  summarise(
    n = n(),
    Average.fare = mean(fare, na.rm = TRUE),
    Median.fare  = median(fare, na.rm = TRUE)
  )

Fare Value By Class on the Titanic

结果解释

  • 方框图证实了机票价格与机票等级成正比。非常直观。
  • 分布向右倾斜。一等舱、二等舱和三等舱的票价中位数分别为 59.4 英镑、15 英镑和 8.05 英镑。一等舱、二等舱和三等舱的平均票价分别为 82.2 英镑、21.2 英镑和 13.3 英镑。(平均票价大于中间票价)。
  • 因此,这个分布的中心的更好的测量是中位数。因此,头等票的价格大约是二等票的三倍,而二等票的价值大约是三等票的两倍。
  • 与同一班级的成人相比,儿童的平均票价和中位票价更高。

注:
对于对称分布,均值在中间。因此,平均值是用于比较的适当度量。但是如果分布是偏斜的,那么平均值通常不在中间。因此,中位数是进行比较的适当标准
我对我在 TDS 上的第一篇文章感到非常兴奋,尽管如此,如果你做过类似的分析,我仍然需要澄清,在不同的年龄组中,儿童是否真的比一些成年人付出更多,正如我的可视化气泡图结果似乎所表明的那样。

感谢阅读!。

分析印度新当选总理的推特资料

原文:https://towardsdatascience.com/analyzing-the-twitter-profile-of-indias-newly-elected-pm-b61ae0edf6a5?source=collection_archive---------15-----------------------

一个简单的 Python 项目

Source: Image by Author

免责声明:本博客与政治无关,只是出于学术兴趣而写。

很长一段时间以来,我想写一篇关于使用 Python 分析真实用户数据的博客,以重温我的概念并探索新的主题。

巧合的是,上周,6 亿印度人连续第二次投票选举纳伦德·莫迪为总理,莫迪是印度推特上关注最多的政治家,并有效地利用推特与选民沟通。因此,他的 Twitter 个人资料可能是一个成熟的分析数据的丰富来源。此外,分析一个政治家的声明是有趣的!

这就是为什么我决定为这个项目分析他的资料。这个博客对那些正在寻找基于真实数据的简单数据分析项目的人会有帮助。

在深入细节之前,这里是项目的关键部分:

  • 在 Twitter 上创建一个开发者账户
  • 使用 Tweepy 删除推文
  • 创建一个熊猫数据框架
  • 推文的统计分析
  • 情感分析
  • 词频分析
  • 主题建模

在 Twitter 上创建一个开发者账户

我只需要在 Twitter 开发者网站上注册并回答几个问题。Twitter 的批准大约在 2-3 小时后发出。

我们需要您的开发者帐户的以下信息:消费者密钥、消费者秘密、访问密钥和访问秘密。

使用 Tweepy 删除推文

Tweepy 是一个易于使用的 Python 库,用于访问 Twitter API。

首先,让我们导入我们将使用的所有库。

import tweepy 
import pandas as pd
import numpy as np from IPython.display 
import display 
import matplotlib.pyplot as plt
import seaborn as sns 
from textblob import TextBlob
import re
import warnings
warnings.filterwarnings('ignore') 
%matplotlib inline

接下来,让我们保存所有的 Twitter 凭证。很明显我藏了我的。创建一个单独的文件来存储凭证是个好主意,但是我在同一个文件中使用了。

#It's not a good pratice to include the keys in the same code, as we have to display. However, I am lazyconsumer_key = "XXXXXXXXXXXXXXXXX"
consumer_secret = "XXXXXXXXXXXXXXXX"
access_key = "XXXXXXXXXXXXXXXXXX"
access_secret = "XXXXXXXXXXXXXXXXXX"

接下来,我们迭代提取推文,一次删除 200 条推文。在做这个分析时,我从鲁道夫·费罗对特朗普推文的博客情绪分析中获得了灵感。

创建一个熊猫数据框架

让我们创建一个熊猫数据框架,这将有助于分析 Twitter 数据。我们还需要了解我们下载的数据的结构。

Source: Image by Author

接下来,我们将把这些相关参数添加到数据帧中。

推文的统计分析

这一段比较直截了当。我们希望得到简单的统计数据,比如推文的平均长度,最受欢迎的推文,以及多年来喜欢和转发的趋势。

接下来,让我们看看过去两年中赞和转发的趋势。我还没有探究 Twitter 对 API 的一般访问的限制,但我相信它限制在 3200 条 tweets。这就是为什么我们只有最近两年的数据。

为了绘制趋势,我们将创建熊猫系列,然后进行绘制。即使在这短暂的时间内,我们也可以观察到喜欢和转发的上升趋势。

让我们创建一些有趣的图表。

首先,我们将创建一个关联图来了解被喜欢和转发的推文的特征。

Source: Image by Author

一些不足为奇的发现是——RTs 和 Likes 高度相关。一些更有见地的学习包括:

  • 中等长度的推文会给莫迪带来更多的转发和点赞
  • 这是有争议的。带有负面情绪的莫迪的推文通常会获得更多的 RTs 和赞。然而,它可能与表达对不幸事件的遗憾有关。

其次,让我们在散点图上绘制情感、喜欢和 RTs,以重新检查我们的假设。

这再次表明,带有负面情绪的推文获得了更多的即时战略和喜欢。然而,我们没有进行广泛的清理,印度英语(使用印地语)可能会影响这些结果。

情感分析

对于情感分析,我们将使用 TextBlob。这是一个 Python 库,提供简单的 API 访问来执行基本的自然语言处理任务。

TextBlob 的工作方式就像 Python 字符串一样,因此可以类似地用于转换数据。

exampleText=TextBlog("Ajitesh")
exampleText[1:3]

输出→ TextBlob("ji ")

exampleText.upper()

Output- TextBlob("AJITESH ")

我们将分三步进行情感分析——清理 Tweet 的文本、标记化和情感分析。

Source: Image by Author

在分析这些推文时,我们只想局限于莫迪发布的推文。尽管我们无法识别莫迪先生转发的推文。我们有一条捷径。我们可以忽略零赞的推文,因为 Twitter 不会给转发推文的用户指定“赞”。此外,莫迪的任何推文都不太可能没有“赞”。

让我们从数据清理步骤开始。

接下来,我们将做标记化和情感分析。

词频分析

对我来说,莫迪先生最令人难忘的倡议之一是“Swachh Bharat”,一项保持印度清洁的倡议。让我们看看他在这些推文中提到了多少次“Swachh Bharat”。

我们先创建一个词云来可视化不同词的相对使用频率。我已经创建了一个简单的单词云,但是你可以想象一下,创建一个图像颜色的单词云。

有趣的是,西孟加拉邦和奥迪萨被提及的频率更高,莫迪的政党在这两个地方取得了惊人的进展。

我还用旧的 python 方式创建了一个频率表:

  • 创建映射单词和频率的词典
  • 然后,将单词及其频率作为元组存储在列表中
  • 最后,对列表进行排序并打印结果

主题建模

假设你有圣雄甘地所有的文本形式的演讲。你可以使用主题模型来描绘这些演讲中的关键主题。

我在 PyTexas 看到了 Christine Doig 关于主题建模的精彩演讲,并尝试在我们的案例中实现。

本质上,在主题建模中,我们使用统计模型来发现大量无组织文本中出现的抽象主题。这是一种无监督的学习方法。下图解释了我们通过主题建模想要达到的目标。

Source: Christine Doig Slides (Image by Author)

有两种方法进行主题建模——LSA(潜在语义分析)和概率推理方法,如 LDA(潜在狄利克雷分配)。下面是 LSA 和 LDA 之间差异的图示。在我们的例子中,我们将使用 LDA。

Source — Topic Modelling by Jordan Boyd-Graber (Image by Author)

让我们实现 LDA 来分析推文中的主题。

source — Image by Author

输出是一个交互式图形,我不知道如何嵌入。然而,您可以在这里找到带有输出的完整代码。

我可以看到两个清晰的主题——政治和感恩——分别用 4 和 1 来表示。然而,主题建模在这里没有多大用处。我可能会把这些应用到一系列的演讲中。

我这边就这样。我知道我们可以在这里做更多的分析。请评论让我知道我还可以探索什么。

分析特朗普的推特强迫症

原文:https://towardsdatascience.com/analyzing-trumps-twitter-compulsion-3c6a61ba8354?source=collection_archive---------16-----------------------

Image via Unsplash

从来没有一位美国总统如此频繁地使用 Twitter,令人不安。从一位许多人认为精神崩溃的总统的短信中,我们能收集到什么隐藏的见解?

我从特朗普推特档案复制了特朗普的推文数据,选择分析他总统任期顶部 2017 年 1 月 20 日开始的推文。将文本数据保存为 csv 文件后,我使用 Pandas 库将该文件导入到 Jupyter 笔记本中。

作为熨斗学校的数据科学学生,我一直在研究统计分布和概率。泊松分布是有趣的,因为它允许我们通过检查在特定时间范围内发生的事件的平均数来计算给定事件发生的概率。

image from Slideplayer.com

利用 Twitter 上的信息,我想确定特朗普在接下来的一个小时内至少撰写 2 次推文的概率。这看起来很简单,但为了进行这种计算,我需要确定他在某个时间段内发推文的频率。

我从数据中寻找答案,相信他每天使用 Twitter 肯定有一种模式。当然,总统繁忙的日程安排会限制他在白天或晚上的特定时间使用智能手机。

唉,似乎一天中没有一个小时是不发推特的,尽管特朗普很少在早上 5 点至 10 点之间发推特。他的公开日程安排显示,特朗普在一个典型的日子里从早上 8 点左右到上午 11 点都在椭圆形办公室,因此我们可以看到,他很可能已经发了 800 多次推特,同时可能做出影响世界各地数百万人生活的重要行政决策。

我不知道这些推文实际上是来自特朗普本人,还是由他的工作人员发送的。他的一些推文肯定是在他出国旅行或穿越美国时发出的,但存档的推特数据只给了我们东部标准时间戳。

Factbase】已经创建了一个详细的日历,它从多个公共来源汇总信息,并提供位置和会议数据。他们已经确定,特朗普在任的 879 天中有 705 天是在白宫度过的,这意味着这些推文的 80%是准确的。

也许他一周中的推文频率会给我们更好的洞察力。互联网和应用程序的使用显示了可预测的流量和行为模式。根据 Sprout Social 的说法,在 Twitter 上发帖的最佳时间是周二和周三。周一至周五上午 8 点到下午 4 点也有稳定的流量,周六 twitter 的参与度会下降。

下面是特朗普一周每天的推文频率图。一般来说,周三和周五是他最忙的日子。这可能与新闻周期或 Twitter 流量高峰期有关吗?或者说,发推特主要是一种冲动行为,如果是这样的话,它打断了什么更重要的工作?

看看每天的平均推文,特朗普的推文频率逐年增加。虽然这不是一个完整的年同比比较,因为我们距离 2019 年还不到一半——但他每天的平均推文率在周末几乎翻了一番。

那么,特朗普在接下来的一个小时内发两条推特的可能性有多大?鉴于目前是 2019 年的周二,他平均每天发 12 条左右的推文,并且他报告说每天只睡 5 个小时左右,这种概率相当低——只有 11%。

如果时间不是特朗普发推特需求的最佳指标,还能是什么?

我从 Axios 下载了一份特朗普泄露的私人日程,并将其转换为 csv 文件,然后我将该文件与他的推文数据合并。我们现在可以看到特朗普在发推文时应该在做什么以及他在哪里-2018 年 11 月 7 日至 2019 年 2 月 1 日。看起来大多数(166 条推文)是在他被安排在椭圆形办公室的时候发出的。

有 50 条推文丢失了位置数据,但它们大多是在假期期间发出的。我们知道特朗普在 Mar a Lago 过感恩节,由于政府关门,他在华盛顿特区过圣诞节。

那么,特朗普在椭圆形办公室发推文时的日程安排是什么?毫不奇怪,这主要被归类为执行时间,,但他也在几次会议和午餐期间发推特。缩小范围,我们可以查看特朗普日程表上的所有活动类别,无论位置如何,以找到每个活动期间的推文频率。

我们没有得到任何关于执行时间的额外信息,但是我们可以得到关于他的会议和午餐的额外细节。下面是归类为会议的活动的频率图。看起来,在政策讨论、情报简报和与他的幕僚长开会时,他最容易被 Twitter 分心,基本上是在进行他工作中一些最重要的方面。

特朗普的午餐推特大多是在私人午餐期间发出的,当它是工作午餐时,频率会下降。

作为一名布鲁克林居民,我有点惊讶地看到他正在与纽约州长安德鲁·科莫一起吃饭和发推特。11 月 28 日午餐期间,他发了 5 条微博,4 条被转发,1 条是这样的

总之,分析特朗普的推文出人意料地容易。预测他是否会在某个时间段发微博是一个愚蠢的练习,但它不可避免地揭示了他日常活动的有趣信息。虽然已经对他的推文的内容和影响进行了几次调查,但我们也可以分析他的习惯造成的破坏和风险。

使用 NLP 分析与 Pokemon 相关的#BringBackNationalDex 标签的推文

原文:https://towardsdatascience.com/analyzing-tweets-from-the-polemical-pokemon-related-bringbacknationaldex-tag-with-spacy-and-gcloud-661ec0a08a4c?source=collection_archive---------26-----------------------

使用 spaCy 和 Google Cloud 发现顶级词类术语、情感和提到的口袋妖怪

突发新闻:口袋妖怪社区一片哗然。上周,游戏狂,主要口袋妖怪游戏的开发商,宣布即将推出的游戏,口袋妖怪剑与盾,将不会拥有口袋妖怪的完整库。这个图书馆被称为国家口袋妖怪——因此这个运动被命名为# BringBackNationalPokedex——目前由 809 个口袋妖怪组成。除了仅仅是一个神奇生物的列表,完整的 Pokedex 代表了这个系列的进化和成长,这个系列自诞生以来已经征服了数百万人的心。就我个人而言,我觉得这有点令人难过,因为我认为这个声明违背了口袋妖怪的本质和定义:必须抓住他们

Border Control. By Wooden Plank Studios (https://www.woodenplankstudios.com/comic/galar-border-patrol/)

作为该系列的长期粉丝,作为一个好奇的数据人,我想快速看看社区在#BringBackNationalPokedex 标签下发布了什么。使用 Tweepy ,一个用于访问 Twitter API 的 Python 库,我快速编写了一个脚本,并让它运行几个小时来收集数据。然后,使用 Python 的自然语言处理(NLP)库 spaCy ,和 Google 的云自然语言 API ,我对上述数据进行了分析。

在这篇文章中,我将展示我的发现。

我这个实验的目标是学习推特圈分享的热门名词、动词形容词副词以及标签。此外,我还想看看哪些命名的实体,也就是说,一个“被赋予名称的真实世界的对象——例如,一个人、一个国家、一个产品或一本书的标题”,如 spaCy 所定义的。因为没有情绪分析,任何推文分析都是不完整的,所以我通过这个情绪模型运行推文,以了解人们对这个决定有多高兴或愤怒。最后,出于好奇,我很想知道哪些是被提及最多的口袋妖怪。

数据和准备步骤

本实验中使用的数据集由 2019 年 6 月 13 日和 6 月 14 日收集的 2724 条推文组成,其中包括标签#BringBackNationalDex。为了清理它,我删除了提到的转发,例如,“RT @account_name ”,将“神奇宝贝”的实例改为“口袋妖怪”,删除了所有特殊字符(问号、逗号等),以及包含图像的推文中的 https 地址。我没有做的事情是将推文小写,因为这样做,我可能会丢失一些实体和专有名词,否则 spaCy 不会检测到它们。

顶级名词、动词、形容词、副词和实体

spaCy 最强大的功能之一是词性 (POS)标记,它为每个文档的术语分配一个预测标签,如名词和动词。利用这一点,我可以发现所获得的推文的主要思想或背景。

在小学,我们学到了一个句子中最基本的部分是名词。这些必要的词存在的唯一用途是命名事物;就是这样,地点,人,想法,感觉。因为名词是如此重要,所以我想用它们来打开这篇文章。因此,对于第一个情节,我将展示来自 tweet 语料库的前 30 个名词。

在排名第一的位置上,我们有术语“游戏”,这一点也不奇怪,因为整个问题是关于即将到来的口袋妖怪游戏。接下来是术语“动画”,指的是声称为什么不是所有的口袋妖怪都将出现的主要原因是开发者没有足够的劳动力来制作所有口袋妖怪的动画。然后在第三个位置,是单词“口袋妖怪”

The only Pokemon that appear on this list is Wingull, and that is because there was a tweet featuring a Wingull animation that went viral and was retweeted several times. Other important nouns from the list are “time”, most probably because of those who think the game needs more time before being released, the Japanese word “互換切り” or “Compatibility Switch”, which honestly I don’t understand the context (can someone corroborate this translation?), and lastly the proper noun “Galar”, which is the name of the new Pokemon region.

我要介绍的第二个词性是动词。有了名词,我们学习了用户谈论的主要内容,现在有了动词,我们将发现补充这些名词的动作。下图显示了前 30 个动词。

第一个术语是互联网在这些情况下想要什么的明显例子:想要“知道】,要求信息或要求解释。下面的术语,“发现”,指的是人们希望他们最喜欢的口袋妖怪找到进入游戏的方法。然后我们有“感觉”,主要来自用户陈述他们的观点,“舒适”,这是上面提到的 Wingull tweet 的一部分,以及“需要”,可能因为类似于“知道”的原因

为了给所呈现的术语添加进一步的上下文和精炼,我计算了形容词和副词;这两个语法概念分别用来描述和修饰名词和动词。

上图是关于顶级形容词的。图中的第一个词,“旧的”,涉及一条转发,说了一些类似于的话,“即使话题【Pokedex 问题】变旧了,我也会继续谈论它。”然后,在第二个位置的是单词“新的”,,在大多数情况下,这个形容词出现在抨击游戏的一些新功能的推文中,或者出现在另一条关于一些新视频的转发推文中,这些视频讨论了争议。列表中的第三个形容词是“最喜欢的”,,它出现在用户谈论他们最喜欢的口袋妖怪以及可能遗漏它们的推文中。其他引起我注意的术语还有、【胜任】、、【增田俊一】、谁是游戏背后的导演。然而,将这个名字标在形容词下面可能是 spaCy 的一个假阳性预测。既然我们知道了名词是如何修饰的,让我们来看看副词。

最受欢迎的副词是“不”,,它出现在暗示负面情绪(我们很快会看到更多)或不同意的推文中。比如“…做 信任游戏怪胎“我会 买游戏”,或者“游戏会 有全国 Pokedex。”然后,我们有“完全”,来自 Wingull 的推文,在它之后,副词“以前”,主要用于推文,比较即将到来的游戏和几年前发布的游戏。其他有趣的副词还有:“后来”、“T47”、“불완전한”(韩语中的“不完全”)、“最终”**

现在,让我们将注意力从语法和部分句子转移到语料库的实体,就是这样,人们在推文中讨论的特定和现有的事情。

主导实体是“口袋妖怪”。然后,我们就有了【one】,“用来指代“这一款游戏”,或者,“这一款”【口袋妖怪】一代”“游戏怪胎”,争议的中心开发者。此外,其他经常出现的实体还有美国任天堂的推特账号、“Nintendo America”“剑与盾”“增田俊一”等名字。

情感分析

通常,在这种互联网变得有点愤怒和紧张的争议事件中,事情往往会有点失控。可悲的是,当这种情况发生时,人们选择以消极甚至仇恨的方式做出反应和评论。为了测试这个假设,我通过情绪分析引擎运行了这些推文,以量化其内容的“积极”“消极”。我使用的情感模型是由谷歌云的自然语言 API 提供的,主要是因为我喜欢它如何将语料库分割成句子来计算每个句子的情感,因为它是一个 API,这意味着你不必安装、训练或下载模型。

总的来说,谷歌传递了它检测到的 5501 个句子的情感。每一个情感输出都包含两个值:“分数”“量级”。前者是一个介于 -11 之间的值,其中 -1 表示负面情绪, 1 表示正面情绪,而 magnitude(我在此不使用)则指定 “文档中存在多少情绪内容。” 下面的直方图显示了情绪值的分布。

令人惊讶的是,情绪几乎完全平衡;平均值为 -0.045 ,标准差为 0.27 。直方图中心的峰值表明大多数推文根本没有情感,在人工检查推文和值后,我发现这些零值推文只是由标签组成的,所以根本没有情感。关于分布的两端,我们可以看到高度负面的推文比高度正面的多。一些例子是:“他们毁了传奇!”、 “口袋妖怪粉丝:抵制任天堂和游戏狂”,“那个游戏太英国化了,他们甚至不让其他地区的 Pokemon 进来。”从更积极的角度来看,我们有一些充满希望的评论,比如: " 【原文】我仍然会得到它,但是【原文】我非常担心我的团队不会在游戏中,而且【原文】我真的【原文】不喜欢那个#BringBackNationalDex," “看到口袋妖怪社区对游戏的热情真是太棒了,# bringgbndex

提到口袋妖怪

在我结束之前,我想展示一下在推文中出现最多的口袋妖怪。除了 Wingull,由于许多转发,它在 tweets 语料库中出现了 160 次,我发现很奇怪的是,没有多少提到口袋妖怪。还有,你会看到,皮卡丘不是顶级的。

第五代传奇口袋妖怪捷克罗姆名列榜首。紧随其后的是首发口袋妖怪——辛达奎尔布拉齐肯沼泽——然后在第五个位置上我们有皮卡丘

结论

Twitter 不浪费任何时间。当社区决定反对或支持某件事时,他们会聚集在一个标签下,让自己的声音被听到。在这篇文章中,我分享了我在调查一个包含#BringBackNationalDex 标签的推特样本后发现的发现,该标签是在宣布即将推出的口袋妖怪游戏不会以完整的生物名单为特色后创建的。

在我调查的第一部分,我使用了 NLP 库 spaCy,来发现与 tweets 一起使用的热门名词、动词、形容词和副词。在这里,我发现推文背后的整体意义是对答案的需求,失望感,甚至是对他们最喜欢的口袋妖怪可能无法穿越边境到 Galar 的消息的悲伤。此外,为了了解推文的整体感觉,我使用谷歌云的自然语言 API 计算了他们的情绪,并得出结论,虽然有些人很愤怒,但其他人充满了希望。最后,捷克罗姆,而不是皮卡丘,是语料库中被提及最多的口袋妖怪。

感谢阅读:)

本项目使用的代码和数据集可从以下网址获得:

[## juandes/带回 pokedex-nlp

在 GitHub 上创建一个帐户,为 juandes/bring-back-pokedex-nlp 开发做贡献。

github.com](https://github.com/juandes/bring-back-pokedex-nlp)

使用 Spark、Optimus 和 Twint 在几分钟内使用 NLP 分析推文

原文:https://towardsdatascience.com/analyzing-tweets-with-nlp-in-minutes-with-spark-optimus-and-twint-a0c96084995f?source=collection_archive---------4-----------------------

社交媒体一直是研究人们沟通和行为方式的黄金,在本文中,我将向您展示在没有 Twitter API 的情况下分析推文的最简单方法,并可扩展用于大数据。

介绍

如果你在这里,很可能你对分析推文(或类似的东西)感兴趣,你有很多推文,或者可以得到它们。最烦人的事情之一就是获得一个 Twitter 应用程序,获得认证和所有这些。如果你用的是熊猫,那就没办法衡量了。

那么,一个不需要 Twitter API 认证的系统怎么样,它可以获得无限量(几乎是无限量)的推文和分析它们的能力,以及 NLP 等等。好吧,你一定会喜欢的,因为这正是我现在要给你看的。

获得项目和回购

https://matrixds.com/

你可以很容易地理解我将要向你展示的一切。只是铲车这个 MatrixDS 项目:

[## MatrixDS |数据项目工作台

MatrixDS 是一个构建、共享和管理任何规模的数据项目的地方。

community.platform.matrixds.com](https://community.platform.matrixds.com/community/project/5ccc9c4b3175e0603c394444/files)

还有一个 GitHub repo,里面什么都有:

[## FavioVazquez/Twitter _ Optimus _ twint

用 Twint,Optimus 和 Apache Spark 分析推文。-FavioVazquez/Twitter _ Optimus _ twint

github.com](https://github.com/FavioVazquez/twitter_optimus_twint)

使用 MatrixDS,您可以免费运行笔记本、获取数据和运行分析,因此如果您想了解更多信息,请这么做。

得到 Twint 和擎天柱

Twint 利用 Twitter 的搜索运营商让你抓取特定用户的推文,抓取与某些主题、标签和趋势相关的推文,或者从推文中挑选出敏感的信息,如电子邮件和电话号码。

通过我共同创建的库 Optimus,你可以清理数据,准备数据,分析数据,创建剖面图和图表,执行机器学习和深度学习,所有这些都以分布式的方式进行,因为在后端我们有 Spark,TensorFlow,Sparkling Water 和 Keras。

因此,让我们首先安装您需要的所有东西,因为当您在 Matrix 项目中时,请转到分析 Tweets 笔记本并运行(您也可以从 JupyterLab 终端执行此操作):

!pip install --user -r requirements.txt

之后,我们需要安装 Twint,运行:

!pip install --upgrade --user -e git+[https://github.com/twintproject/twint.git@origin/master#egg=twint](https://github.com/twintproject/twint.git@origin/master#egg=twint)

这将下载一个 scr/文件夹,因此我们需要做一些配置:

!mv src/twint .
!rm -r src

然后导入我们需要运行的 Twint:

%load_ext autoreload
%autoreload 2import sys
sys.path.append("twint/")

最后:

import twint

Optimus 是在第一步安装的,所以我们就开始吧(这会为你启动一个 Spark 集群):

from optimus import Optimus
op = Optimus()

设置 Twint 以删除推文

https://www.theverge.com/2015/11/3/9661180/twitter-vine-favorite-fav-likes-hearts

# Set up TWINT config
c = twint.Config()

如果您在笔记本电脑上运行,您还需要运行:

# Solve compatibility issues with notebooks and RunTime errors.
import nest_asyncio
nest_asyncio.apply()

搜索数据科学推文

我将开始我们的分析,废弃关于数据科学的推文,你可以把它改成你想要的任何东西。

为此,我们只需运行以下命令:

c.Search = "data science"
# Custom output format
c.Format = "Username: {username} |  Tweet: {tweet}"
c.Limit = 1
c.Pandas = Truetwint.run.Search(c)

让我给你解释一下这段代码。在我们运行代码的最后一部分:

c = twint.Config()

我们开始了新的 Twint 配置。之后,我们需要通过不同的选项,我们想刮推文。以下是配置选项的完整列表:

Variable             Type       Description
--------------------------------------------
Username             (string) - Twitter user's username
User_id              (string) - Twitter user's user_id
Search               (string) - Search terms
Geo                  (string) - Geo coordinates (lat,lon,km/mi.)
Location             (bool)   - Set to True to attempt to grab a Twitter user's location (slow).
Near                 (string) - Near a certain City (Example: london)
Lang                 (string) - Compatible language codes: https://github.com/twintproject/twint/wiki/Langauge-codes
Output               (string) - Name of the output file.
Elasticsearch        (string) - Elasticsearch instance
Timedelta            (int)    - Time interval for every request (days)
Year                 (string) - Filter Tweets before the specified year.
Since                (string) - Filter Tweets sent since date (Example: 2017-12-27).
Until                (string) - Filter Tweets sent until date (Example: 2017-12-27).
Email                (bool)   - Set to True to show Tweets that _might_ contain emails.
Phone                (bool)   - Set to True to show Tweets that _might_ contain phone numbers.
Verified             (bool)   - Set to True to only show Tweets by _verified_ users
Store_csv            (bool)   - Set to True to write as a csv file.
Store_json           (bool)   - Set to True to write as a json file.
Custom               (dict)   - Custom csv/json formatting (see below).
Show_hashtags        (bool)   - Set to True to show hashtags in the terminal output.
Limit                (int)    - Number of Tweets to pull (Increments of 20).
Count                (bool)   - Count the total number of Tweets fetched.
Stats                (bool)   - Set to True to show Tweet stats in the terminal output.
Database             (string) - Store Tweets in a sqlite3 database. Set this to the DB. (Example: twitter.db)
To                   (string) - Display Tweets tweeted _to_ the specified user.
All                  (string) - Display all Tweets associated with the mentioned user.
Debug                (bool)   - Store information in debug logs.
Format               (string) - Custom terminal output formatting.
Essid                (string) - Elasticsearch session ID.
User_full            (bool)   - Set to True to display full user information. By default, only usernames are shown.
Profile_full         (bool)   - Set to True to use a slow, but effective method to enumerate a user's Timeline.
Store_object         (bool)   - Store tweets/user infos/usernames in JSON objects.
Store_pandas         (bool)   - Save Tweets in a DataFrame (Pandas) file.
Pandas_type          (string) - Specify HDF5 or Pickle (HDF5 as default).
Pandas               (bool)   - Enable Pandas integration.
Index_tweets         (string) - Custom Elasticsearch Index name for Tweets (default: twinttweets).
Index_follow         (string) - Custom Elasticsearch Index name for Follows (default: twintgraph).
Index_users          (string) - Custom Elasticsearch Index name for Users (default: twintuser).
Index_type           (string) - Custom Elasticsearch Document type (default: items).
Retries_count        (int)    - Number of retries of requests (default: 10).
Resume               (int)    - Resume from a specific tweet id (**currently broken, January 11, 2019**).
Images               (bool)   - Display only Tweets with images.
Videos               (bool)   - Display only Tweets with videos.
Media                (bool)   - Display Tweets with only images or videos.
Replies              (bool)   - Display replies to a subject.
Pandas_clean         (bool)   - Automatically clean Pandas dataframe at every scrape.
Lowercase            (bool)   - Automatically convert uppercases in lowercases.
Pandas_au            (bool)   - Automatically update the Pandas dataframe at every scrape.
Proxy_host           (string) - Proxy hostname or IP.
Proxy_port           (int)    - Proxy port.
Proxy_type           (string) - Proxy type.
Tor_control_port     (int) - Tor control port.
Tor_control_password (string) - Tor control password (not hashed).
Retweets             (bool)   - Display replies to a subject.
Hide_output          (bool)   - Hide output.
Get_replies          (bool)   - All replies to the tweet.

所以在这段代码中:

c.Search = "data science"
# Custom output format
c.Format = "Username: {username} |  Tweet: {tweet}"
c.Limit = 1
c.Pandas = True

我们设置搜索词,然后格式化响应(只是为了检查),只获得 20 条 tweets,限制=1(它们以 20 为增量),最后使结果与 Pandas 兼容。

然后当我们跑的时候:

twint.run.Search(c)

我们正在展开搜索。结果是:

Username: tmj_phl_pharm |  Tweet: If you're looking for work in Spring House, PA, check out this Biotech/Clinical/R&D/Science job via the link in our bio: KellyOCG Exclusive: Data Access Analyst in Spring House, PA- Direct Hire at Kelly Services #KellyJobs #KellyServices
Username: DataSci_Plow |  Tweet: Bring your Jupyter Notebook to life with interactive widgets  https://www.plow.io/post/bring-your-jupyter-notebook-to-life-with-interactive-widgets?utm_source=Twitter&utm_campaign=Data_science … +1 Hal2000Bot #data #science
Username: ottofwagner |  Tweet: Top 7 R Packages for Data Science and AI   https://noeliagorod.com/2019/03/07/top-7-r-packages-for-data-science-and-ai/ … #DataScience #rstats #MachineLearning
Username: semigoose1 |  Tweet: ëäSujy #crypto #bitcoin #java #competition #influencer #datascience #fintech #science #EU  https://vk.com/id15800296  https://semigreeth.wordpress.com/2019/05/03/easujy-crypto-bitcoin-java-competition-influencer-datascience-fintech-science-eu- https-vk-com-id15800296/ …
Username: Datascience__ |  Tweet: Introduction to Data Analytics for Business  http://zpy.io/c736cf9f  #datascience #ad
Username: Datascience__ |  Tweet: How Entrepreneurs in Emerging Markets can master the Blockchain Technology  http://zpy.io/f5fad501  #datascience #ad
Username: viktor_spas |  Tweet: [Перевод] Почему Data Science командам нужны универсалы, а не специалисты  https://habr.com/ru/post/450420/?utm_source=dlvr.it&utm_medium=twitter&utm_campaign=450420 … pic.twitter.com/i98frTwPSE
Username: gp_pulipaka |  Tweet: Orchestra is a #RPA for Orchestrating Project Teams. #BigData #Analytics #DataScience #AI #MachineLearning #Robotics #IoT #IIoT #PyTorch #Python #RStats #TensorFlow #JavaScript #ReactJS #GoLang #CloudComputing #Serverless #DataScientist #Linux @lruettimann  http://bit.ly/2Hn6qYd  pic.twitter.com/kXizChP59U
Username: amruthasuri |  Tweet: "Here's a typical example of a day in the life of a RagingFX trader. Yesterday I received these two signals at 10am EST. Here's what I did... My other activities have kept me so busy that ...  http://bit.ly/2Jm9WT1  #Learning #DataScience #bigdata #Fintech pic.twitter.com/Jbes6ro1lY
Username: PapersTrending |  Tweet: [1/10] Real numbers, data science and chaos: How to fit any dataset with a single parameter - 192 stars - pdf:  https://arxiv.org/pdf/1904.12320v1.pdf … - github: https://github.com/Ranlot/single-parameter-fit …
Username: webAnalyste |  Tweet: Building Data Science Capabilities Means Playing the Long Game  http://dlvr.it/R41k3t  pic.twitter.com/Et5CskR2h4
Username: DataSci_Plow |  Tweet: Building Data Science Capabilities Means Playing the Long Game  https://www.plow.io/post/building-data-science-capabilities-means-playing-the-long-game?utm_source=Twitter&utm_campaign=Data_science … +1 Hal2000Bot #data #science
Username: webAnalyste |  Tweet: Towards Well Being, with Data Science (part 2)  http://dlvr.it/R41k1K  pic.twitter.com/4VbljUcsLh
Username: DataSci_Plow |  Tweet: Understanding when Simple and Multiple Linear Regression give Different Results  https://www.plow.io/post/understanding-when-simple-and-multiple-linear-regression-give-different-results?utm_source=Twitter&utm_campaign=Data_science … +1 Hal2000Bot #data #science
Username: DataSci_Plow |  Tweet: Artificial Curiosity  https://www.plow.io/post/artificial-curiosity?utm_source=Twitter&utm_campaign=Data_science … +1 Hal2000Bot #data #science
Username: gp_pulipaka |  Tweet: Synchronizing the Digital #SCM using AI for Supply Chain Planning. #BigData #Analytics #DataScience #AI #RPA #MachineLearning #IoT #IIoT #Python #RStats #TensorFlow #JavaScript #ReactJS #GoLang #CloudComputing #Serverless #DataScientist #Linux @lruettimann  http://bit.ly/2KX8vrt  pic.twitter.com/tftxwilkQf
Username: DataSci_Plow |  Tweet: Extreme Rare Event Classification using Autoencoders in Keras  https://www.plow.io/post/extreme-rare-event-classification-using-autoencoders-in-keras?utm_source=Twitter&utm_campaign=Data_science … +1 Hal2000Bot #data #science
Username: DataSci_Plow |  Tweet: Five Methods to Debug your Neural Network  https://www.plow.io/post/five-methods-to-debug-your-neural-network?utm_source=Twitter&utm_campaign=Data_science … +1 Hal2000Bot #data #science
Username: iamjony94 |  Tweet: 26 Mobile and Desktop Tools for Marketers  http://bit.ly/2LkL3cN  #socialmedia #digitalmarketing #contentmarketing #growthhacking #startup #SEO #ecommerce #marketing #influencermarketing #blogging #infographic #deeplearning #ai #machinelearning #bigdata #datascience #fintech pic.twitter.com/mxHiY4eNXR
Username: TDWI |  Tweet: #ATL #DataPros: Our #analyst, @prussom is headed your way to speak @ the #FDSRoadTour on Wed, 5/8! Register to attend for free, learn about Modern #DataManagement in the Age of #Cloud & #DataScience: Trends, Challenges & Opportunities.  https://bit.ly/2WlYOJb  #Atlanta #freeevent

看起来不太好,但我们得到了我们想要的。推文!

将结果保存到熊猫中

遗憾的是 Twint 和 Spark 之间没有直接联系,但是我们可以用熊猫来做,然后将结果传递给 Optimus。

我创建了一些简单的函数,你可以在实际项目中看到,这些函数帮助你处理熊猫和这个部分的奇怪的 Twint API。所以当我们运行这个时:

available_columns()

你会看到:

Index(['conversation_id', 'created_at', 'date', 'day', 'hashtags', 'hour','id', 'link', 'location', 'name', 'near', 'nlikes', 'nreplies','nretweets', 'place', 'profile_image_url', 'quote_url', 'retweet','search', 'timezone', 'tweet', 'user_id', 'user_id_str', 'username'],dtype='object')

这些是我们刚刚查询得到的列。有很多不同的东西可以用来处理这些数据,但是对于本文,我将只使用其中的一部分。因此,为了将 Twint 的结果转换为 Pandas,我们运行:

df_pd = twint_to_pandas(["date", "username", "tweet", "hashtags", "nlikes"])

你会看到这只熊猫:

好多了不是吗?

情感分析(简单的方法)

我们将使用 Optimus 和 TextBlob 对一些推文进行情感分析。我们需要做的第一件事是清理这些推文,因为擎天柱是最好的选择。

为了将数据保存为 Optimus (Spark) DF,我们需要运行:

df = op.create.data_frame(pdf= df_pd)

我们将使用 Optimus 删除重音符号和特殊字符(对于真实的工作场景,您需要做的远不止这些,如删除链接、图像和停用词),为此:

clean_tweets = df.cols.remove_accents("tweet") \
                 .cols.remove_special_chars("tweet")

然后,我们需要从 Spark 收集这些推文,将它们放在 Python 列表中,为此:

tweets = clean_tweets.select("tweet").rdd.flatMap(lambda x: x).collect()

然后,为了分析这些推文的情绪,我们将使用 TextBlob 情绪函数:

from textblob import TextBlob
from IPython.display import Markdown, display# Pretty printing the result
def printmd(string, color=None):
    colorstr = "<span style='color:{}'>{}</span>".format(color, string)
    display(Markdown(colorstr))for tweet in tweets:
    print(tweet)
    analysis = TextBlob(tweet)
    print(analysis.sentiment)
    if analysis.sentiment[0]>0:
        printmd('Positive', color="green")
    elif analysis.sentiment[0]<0:
        printmd('Negative', color="red")
    else:
        printmd("No result", color="grey")
        print("")

这将给我们:

IAM Platform Curated Retweet  Via  httpstwittercomarmaninspace  ArtificialIntelligence AI What About The User Experience  httpswwwforbescomsitestomtaulli20190427artificialintelligenceaiwhatabouttheuserexperience  AI DataScience MachineLearning BigData DeepLearning Robots IoT ML DL IAMPlatform TopInfluence ArtificialIntelligence
Sentiment(polarity=0.0, subjectivity=0.0)

中立的

Seattle Data Science Career Advice Landing a Job in The Emerald City Tips from Metis Seattle Career Advisor Marybeth Redmond –  httpsbitly2IYjzaj  pictwittercom98hMYZVxsu
Sentiment(polarity=0.0, subjectivity=0.0)

中立的

This webinarworkshop is designed for business leaders data science managers and decision makers who want to build effective AI and data science capabilities for their organization Register here  httpsbitly2GDQeQT  pictwittercomxENQ0Dtv1X
Sentiment(polarity=0.6, subjectivity=0.8)

积极的

Contoh yang menarik dari sport science kali ini dari sisi statistik dan pemetaan lapangan Dengan makin gencarnya scientific method masuk di sport maka pengolahan data seperti ini akan semakin menjadi hal biasa  httpslnkdinfQHqgjh 
Sentiment(polarity=0.0, subjectivity=0.0)

中立的

Complete handson machine learning tutorial with data science Tensorflow artificial intelligence and neural networks  Machine Learning Data Science and Deep Learning with Python   httpsmedia4yousocialcareerdevelopmenthtmlmachinelearning  python machine learning online data science udemy elearning pictwittercomqgGVzRUFAM
Sentiment(polarity=-0.16666666666666666, subjectivity=0.6)

否定的;消极的;负面的;负的

We share criminal data bases have science and medical collaoarations Freedom of movement means we can live and work in EU countries with no hassle at all much easier if youre from a poorer background We have Erasmus loads more good things
Sentiment(polarity=0.18939393939393936, subjectivity=0.39166666666666666)

积极的

Value of Manufacturers Shipments for Durable Goods BigData DataScience housing rstats ggplot pictwittercomXy0UIQtNHy
Sentiment(polarity=0.0, subjectivity=0.0)

中立的

Top DataScience and MachineLearning Methods Used in 2018 2019 AI MoRebaie TMounaged AINow6 JulezNorton  httpswwwkdnuggetscom201904topdatasciencemachinelearningmethods20182019html 
Sentiment(polarity=0.5, subjectivity=0.5)

积极的

Come check out the Santa Monica Data Science  Artificial Intelligence meetup to learn about In PersonComplete Handson Machine Learning Tutorial with Data Science  httpbitly2IRh0GU 
Sentiment(polarity=-0.6, subjectivity=1.0)

否定的;消极的;负面的;负的

Great talks about the future of multimodality clinical translation and data science Very inspiring 1stPETMRIsymposium unitue PETMRI molecularimaging AI pictwittercomO542P9PKXF
Sentiment(polarity=0.4833333333333334, subjectivity=0.625)

积极的

Did engineering now into data science last 5 years and doing MSC in data science this year
Sentiment(polarity=0.0, subjectivity=0.06666666666666667)

中立的

Program Officer – Data Science  httpbitly2PV3ROF 
Sentiment(polarity=0.0, subjectivity=0.0)

中立。

诸如此类。

这非常容易,但它不会扩展,因为最终我们从 Spark 收集数据,所以驱动程序的 RAM 是极限。让我们做得更好一点。

将情感直接添加到 Spark 数据框架中

将这些代码转换成 Spark 代码很简单。这段代码也可以帮助您转换其他代码。因此,让我们开始从 Spark 导入用户定义的功能模块:

from pyspark.sql.functions import udf

然后我们将把上面的代码转换成一个函数:

def apply_blob(sentence):
    temp = TextBlob(sentence).sentiment[0]
    if temp == 0.0:
        return 0.0 # Neutral
    elif temp >= 0.0:
        return 1.0 # Positive
    else:
        return 2.0 # Negative

此后,我们将把该函数注册为火花 UDF:

sentiment = udf(apply_blob)

然后,为了将该函数应用于整个数据帧,我们需要编写:

clean_tweets.withColumn("sentiment", sentiment(clean_tweets['tweet'])).show()

我们会看到:

情感分析,程序员的好方法(使代码模块化)

这实际上不是质量代码。让我们把它转换成函数来反复使用。

第一部分是设置一切:

%load_ext autoreload
%autoreload 2# Import twint
import sys
sys.path.append("twint/")# Set up TWINT config
import twint
c = twint.Config()# Other imports
import seaborn as sns
import os
from optimus import Optimus
op = Optimus()# Solve compatibility issues with notebooks and RunTime errors.
import nest_asyncio
nest_asyncio.apply()# Disable annoying printingclass HiddenPrints:
    def __enter__(self):
        self._original_stdout = sys.stdout
        sys.stdout = open(os.devnull, 'w') def __exit__(self, exc_type, exc_val, exc_tb):
        sys.stdout.close()
        sys.stdout = self._original_stdout

最后一部分是一个类,它将删除 Twint 的自动打印,所以我们只看到数据帧。

以上所有的东西都可以用这些函数来概括:

from textblob import TextBlob
from pyspark.sql.functions import udf
from pyspark.sql.types import DoubleType# Function to get sentiment 
def apply_blob(sentence):
    temp = TextBlob(sentence).sentiment[0]
    if temp == 0.0:
        return 0.0 # Neutral
    elif temp >= 0.0:
        return 1.0 # Positive
    else:
        return 2.0 # Negative# UDF to write sentiment on DF
sentiment = udf(apply_blob, DoubleType())# Transform result to pandas
def twint_to_pandas(columns):
    return twint.output.panda.Tweets_df[columns]def tweets_sentiment(search, limit=1):
    c.Search = search
    # Custom output format
    c.Format = "Username: {username} |  Tweet: {tweet}"
    c.Limit = limit
    c.Pandas = True
    with HiddenPrints():
        print(twint.run.Search(c))

    # Transform tweets to pandas DF
    df_pd = twint_to_pandas(["date", "username", "tweet", "hashtags", "nlikes"])

    # Transform Pandas DF to Optimus/Spark DF
    df = op.create.data_frame(pdf= df_pd)

    # Clean tweets
    clean_tweets = df.cols.remove_accents("tweet") \
                 .cols.remove_special_chars("tweet")

    # Add sentiment to final DF
    return clean_tweets.withColumn("sentiment",    sentiment(clean_tweets['tweet']))

因此,为了获取推文并添加情感,我们使用:

df_result = tweets_sentiment("data science", limit=1)df_result.show()

就这样:)

让我们看看情绪的分布:

df_res_pandas = df_result.toPandas()
sns.distplot(df_res_pandas['sentiment'])
sns.set(rc={'figure.figsize':(11.7,8.27)})

利用 Twint 做更多事情

To see how to do this check: https://amueller.github.io/word_cloud/auto_examples/masked.html

我们可以做更多的事情,这里我将向你展示如何创建一个简单的函数来获取 tweets,以及如何从它们构建一个单词云。

所以通过简单的搜索就能得到推文:

def get_tweets(search, limit=100):
    c = twint.Config()
    c.Search = search
    c.Limit = limit
    c.Pandas = True
    c.Pandas_clean = Truewith HiddenPrints():
        print(twint.run.Search(c))
    return twint.output.panda.Tweets_df[["username","tweet"]]

有了这个,我们可以很容易地获得成千上万条推文:

tweets = get_tweets("data science", limit=10000)tweets.count() # 10003

要生成单词云,我们需要做的就是:

from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
import matplotlib.pyplot as plt
%matplotlib inlinetext = tweets.tweet.values# adding movie script specific stopwords
stopwords = set(STOPWORDS)
stopwords.add("https")
stopwords.add("xa0")
stopwords.add("xa0'")
stopwords.add("bitly")
stopwords.add("bit")
stopwords.add("ly")
stopwords.add("twitter")
stopwords.add("pic")wordcloud = WordCloud(
    background_color = 'black',
    width = 1000,
    height = 500,
    stopwords = stopwords).generate(str(text))

我添加了一些与分析无关的常用词。为了说明这一点,我们使用:

plt.imshow(wordcloud, interpolation=’bilinear’)
plt.axis(“off”)
plt.rcParams[‘figure.figsize’] = [10, 10]

您将获得:

很漂亮,但没那么漂亮。如果我们想要好的代码,我们需要模块,那么让我们把它转换成一个函数:

def generate_word_cloud(tweets):

    # Getting the text out of the tweets
    text = tweets.tweet.values

    # adding movie script specific stopwords
    stopwords = set(STOPWORDS)
    stopwords.add("https")
    stopwords.add("xa0")
    stopwords.add("xa0'")
    stopwords.add("bitly")
    stopwords.add("bit")
    stopwords.add("ly")
    stopwords.add("twitter")
    stopwords.add("pic")wordcloud = WordCloud(
        background_color = 'black',
        width = 1000,
        height = 500,
        stopwords = stopwords).generate(str(text))

    plt.imshow(wordcloud, interpolation='bilinear')
    plt.axis("off")
    plt.rcParams['figure.figsize'] = [10, 10]

然后我们就跑:

tweets = get_tweets("artificial intelligence", limit=1000)
generate_word_cloud(tweets)

你自己试试

你可以利用图书馆做更多的事情。其他一些功能:

  • twint.run.Search() -使用搜索过滤器获取推文(正常);
  • twint.run.Followers()——获取一个 Twitter 用户的关注者;
  • twint.run.Following() -获取关注推特用户的人;
  • twint.run.Favorites() -获取 Twitter 用户喜欢的推文;
  • twint.run.Profile() -从用户的个人资料中获取推文(包括转发);
  • twint.run.Lookup() -从用户档案中获取信息(简历、位置等)。).

实际上,您可以从终端使用它。对于刚才运行:

pip3 install --upgrade -e git+https://github.com/twintproject/twint.git@origin/master#egg=twint

然后只需运行转到 twint 文件夹:

cd src/twint

最后你可以运行例如:

twint -u TDataScience --since 2019-01-01 --o TDS.csv --csv

在这里,我得到了本年度 TDS 团队的所有推文(迄今为止有 845 条)。如果你想要的话,下面是 CSV 文件:

[## FavioVazquez/Twitter _ Optimus _ twint

用 Twint,Optimus 和 Apache Spark 分析推文。-FavioVazquez/Twitter _ Optimus _ twint

github.com](https://github.com/FavioVazquez/twitter_optimus_twint/blob/master/TDS.csv)

奖金(缩放结果)

让我们获得 10k 条推文,并获得他们的情绪,因为为什么不。为此:

df_result = tweets_sentiment("data science", limit=100000)df_result.show()

这实际上花了将近 10 分钟,所以要做好预防措施。从 CLI 获取 tweets,然后应用该函数可能会更快。让我们看看有多少条推文:

df_results.count()

我们有 10.031 条带有情绪的推文!你也可以用它们来训练其他模型。

感谢您阅读本文,希望它能对您目前的工作和对数据科学的理解有所帮助。如果你想了解我更多,请在 twitter 上关注我:

[## 法维奥·巴斯克斯(@法维奥·巴斯克斯)|推特

Favio Vázquez 的最新推文(@FavioVaz)。数据科学家。物理学家和计算工程师。我有一个…

推特通讯](https://twitter.com/faviovaz)

通过自然语言处理技术分析 Twitter 领域

原文:https://towardsdatascience.com/analyzing-twitter-spheres-through-nlp-techniques-748b0df10b6c?source=collection_archive---------14-----------------------

使用情感分析、词云和递归神经网络探索 8 个类别 x 10 个账户 x 10000 条推文的数据集

由 Sejal Dua 和 Camille Bowman 创作

介绍

Twitter 是一个用于各种交流的平台:淋浴的想法、有趣的遭遇、严肃的新闻等等。我们很好奇不同类型的账户如何使用 Twitter。我们研究了 8 个类别的 10 个大客户:快餐、航空公司、体育联盟、大学、科技公司、流媒体服务、新闻媒体和名人。使用他们的推文,我们通过情感分析、词云、网络和递归神经网络检查了账户使用的词的模式。

数据收集

最初,我们的计划是使用 Twitter API 和 tweepy 库来获得一个数据集,该数据集主要由流行的标签和与这些标签的使用相对应的地理位置数据组成。然而,我们很快发现,使用我们的免费开发者帐户,Twitter REST API 将只允许我们挖掘过去 7 天的推文,即使我们付费,我们每天也只能获得 100 条推文。在做了更多的研究后,我们了解到有一些变通办法。例如,有一个页面滚动条可以超过我们的 API 查询的速度限制。但是,一旦我们开始收集热门推文数据,我们就面临另一个问题。Twitter 是一个平台,用户可以在这个平台上充分接触到无穷无尽的内容和庞大的用户网络,而不必提供任何位置数据。人们可以自愿入住一个地点,但这个地点往往是一些令人难以置信的模糊和古怪的东西(如“地球”)。我们评估了所有这些因素,并确定鉴于我们项目的时间表和整个首要目的,前面的障碍太难克服:收集数据,并使用强大的技术从中获得洞察力。从那时起,我们知道我们必须找到一种替代的数据收集方法,我们还必须重新定义我们的研究问题,使其不涉及在地图上可视化地理位置数据。

我们浏览了互联网和 GitHub,寻找 StackOverflow 上那些绝对的传奇人物,他们总是在你准备放弃和改变的时候拯救你。幸运的是,我们找到了继续这个 Twitter 项目所需要的东西。优化和修改的 GetOldTweets3 库(OMGOT) 可用于大量挖掘旧的和回溯的推文。我们使用这个 Python 库从特定用户那里提取了过去五年中发布的多达 10,000 条推文。如果你正在寻找 Twitter 上的公共账户,这个库比 Twitter API 简单得多(没有速率限制!),并且不需要 API 键。

鉴于我们的新刮刀的能力,我们认为进行我们的项目的最佳途径是进入分类分析的领域。我们选择了下面的 8 个类别,因为我们相信它们共同代表了 Twitter 作为一个与其他人、整个社区以及我们触手可及的更大世界进行互动的平台的独特用途。我们通过找到经常发微博并且在“推特世界”之外很受欢迎的用户,为每个类别选择了 10 个账户。我们选择的客户显示在下面的徽标图中:

categories = {fast food, airlines, sports leagues, colleges, tech giants, streaming platforms, news, celebrities}

我们不得不删除一些我们最初选择的账户,因为它们的推文太少了。最初,我们有一个歌手和演员类别,但我们决定将这两个类别合并成一个更加多样化的名人类别。这使得我们能够包括像艾米·舒默和克莉茜·泰根这样的人(两人都在 Twitter 上非常活跃),并淘汰了许多我们选择的在 Twitter 上更为分散的演员。

数据清理

一旦我们收集了数据,我们必须对其进行预处理,以便为我们的情感分析和词云创建构建一个语料库。我们执行了以下清洁措施:

  • 将所有推文改为小写
  • 删除所有停用词(由 nltk 定义)
  • 删除提及、链接和标签
  • 删除所有标点和括号
  • 删除所有单字符单词

这些清洗技术旨在去除在我们的分析中会导致无关信息或混淆信息的字符和单词。我们希望确保所有相同的单词看起来都一样——因此,小写和删除标点符号——我们还希望语料库中的所有单词都有意义,从而证明我们为什么删除特殊字符。如果你愿意,我们的清理,或者说去除谷壳,是为了让我们以后的分析更有信息和帮助。

方法 1:情绪分析

对于我们探索性数据分析的第一阶段,我们认为按类别查看推文的负面或正面程度,以及不同账户的平均负面或正面程度会很有趣。我们使用 affin 库来计算情感得分,并根据清理后的推文长度进行标准化。然后我们绘制了每个账户的平均情绪得分,按类别细分。

category-level subplots of average sentiment score for each Twitter account

新闻是所有账户中唯一平均情绪得分为负的类别。这是有道理的,因为大多数公司都在回应投诉(并试图保持一切积极的态度),名人也在努力维护自己的品牌。然而,新闻来源不断报道世界范围内的悲剧、战争和各种其他负面事件。我们确实期望看到更保守的新闻来源(福克斯、the Blaze 和《华尔街日报》)和更自由的新闻来源(华盛顿邮报、纽约时报和赫芬顿邮报)之间的差异。然而,新闻来源的积极性和它们在政治光谱中的位置之间没有明显的差异。《赫芬顿邮报》和《华尔街日报》是最不负面的两家推特,而 NBC 和 Blaze 是最负面的两家。

我们还分析了给定类别中所有推文的情绪直方图,没有考虑不同账户之间的情绪差异。

histogram subplots of average sentiment scores by category

preview of interactive Bokeh plot for sentiment score vs. category

如果你想和我们上面的散景直方图互动(强烈推荐),请访问我们的 GitHub repo 。不幸的是,目前你不能将散景图嵌入到媒体中(真的很遗憾,散景和 Codepen 应该合作,给人们他们想要的东西)。正如我们在前面的图表中观察到的,新闻比其他的要负面得多。这是唯一一个中位数小于 0 的类别,而其他类别都倾向于情绪谱的积极一面。也就是说,所有图表都以 0 为中心(在 0 处有一个巨大的峰值),因此这意味着账户发送的许多 tweets 都由均等分布的正面和负面单词组成。

我们发现有趣的是,航空公司和快餐公司为糟糕的服务或客户问题道歉的所有推文并没有更负面地扭曲结果,因为这些推文充满了像“不”和“对不起”这样的词。我们假设,这可能是因为这些推文经常包含许多其他中性和积极的词,例如“请”、“帮助”和“更好”,这些词抵消了更多的负面词。

尽管我们的发现很有趣,但总的来说,这些类别和许多账户都是中性的。我们想对按类别和按账户使用的词做更深入的探索,这样我们就能更好地了解他们真正在推特上谈论什么。

方法二:词频

就量化任何给定文本样本的情感负荷而言,情感分析可能非常有价值,但情感得分的可视化往往令人印象深刻,我们了解到,从高度集中在 0 附近的直方图中只能获得这么多见解。此外,当试图描述具有类似“快餐”的类别标签的数据集时,情感分析完全忽略了可能看起来很有趣的名词的高流行率。出于这个原因,我们决定转向并深入一种不同类型的分析:词频。我们假设,通过以词云的形式可视化语料库,我们将能够识别扩大的高频词,这些词对于它们来自的类别来说很有意义。

word cloud GIF with 1 custom-shaped word cloud per category

我们的假设在很多方面都是正确的。正如你在上面的 GIF 中看到的,单词云似乎反映了你在查看 8 个类别的推文时可能观察到的单词内容。

以下是通过视觉观察单词 clouds 得出的一些观察结果:

快餐 : us,please,thank,sorry,dm,contact,info,hear,phone
航空公司 : please,thank,dm,us,hi,sorry,hear,flight,number
联赛:游戏,比赛,pt,跑步,进球,获胜,观看,领先,团队,球员,运动
院校:学生,新生,年,美国,via,杜克,研究,学习,世界
科技巨头【T13 感谢、使用、爱、现在、听、确认、宣传片、内容
新闻:川普、新、总统、人、年、说、美国、弹劾
名人:爱、感谢、今晚、快乐、人、朋友、时间、乐趣、年

令人着迷的是,仅仅记下一列出现在人眼中的单词,我们就能够在某种程度上隐含地综合这些数据。一些跨多个类别的常用词包括“请”、“谢谢”。“我们”、“新”、“年”等。有趣的是,从客户服务的角度来看,快餐连锁店和航空公司似乎都在使用 Twitter,并向经常对产品不满的特定用户提供大量回复推文。这种直觉可能解释了为什么这两个类别共享“请”、“谢谢”、“dm”、“我们”、“抱歉”和“听到”等词。一家快餐公司可以索要顾客的联系信息,并以一顿免费餐来“弥补”,而一家航空公司却不能提供这样的友好姿态。只是精神食粮!

新闻和名人是有趣的类别,因为推文选择在本质上是如此多样化。每个单独的新闻提供者关注的是时事新闻,因此我们观察不到多少纵向趋势来阐明某个集中的主题。以类似的方式,名人在推特上发布与他们的生活和他们自己的生活相关的内容。瑞安·雷诺兹经常提到“死侍”,但毫不奇怪,数据集中的其他名人都没有提到这部电影。这里的要点是,由于语料库中充满了如此多的罕见名词,高频词的数量似乎减少了。我们看到高度通用的词,如“新”、“年”、“说”和“我们”,然后用最大的字体,我们看到“特朗普”、“总统”和“弹劾”。说够了…

单词 clouds 作为一个很好的刺激来收集每个类别的语料库的初步印象,但是我们渴望数字和数据!不仅如此,单词 clouds 还让我们好奇,我们如何通过账户获得每个类别中最常见单词的洞察力,而不仅仅是一般的分类比较。因此,我们进一步研究了词频数据,提取了每个账户中最常见的 10 个词,并按类别显示出来。结果可以在下面的 GIF 中看到。

top 10 words per account for each category and their occurrences

快餐、航空和科技 Twitter 账户说了很多“请”、“对不起”和“联系”(IHOP 的客户服务热线是他们第三常用的词)。正如我们前面提到的,这些账户的大多数推文都是发给不满意的客户的,帮助他们解决问题。这意味着他们的热门词汇都有令人难以置信的高计数,并且在某个点上有一些下降,因为他们的许多推文都有类似的前提(处理客户投诉)。

星巴克、特斯拉和 Snapchat 似乎是这些账户中唯一主要使用它做广告的账户,它们的每个词的计数要低得多,可能是因为对客户的重复回复最少。星巴克的前两个词是“啜饮”和“快乐”,特斯拉的是“增压器”和“模型”,Snapchat 的是“介绍”和“见面”。所有这些高频词都是非通用的,它们也不是对公司名称或产品的明确引用。人们可以看看这些词频见解,并声称这三家科技公司正在有效或最佳地使用 Twitter 平台,因为它们在太多直接回复用户和太多推广内容之间取得了完美的平衡。然而,相对于竞争对手,Snapchat 并不是一个特别活跃的 Twitter 用户:它的第七到第十热门词汇都只被使用了 5 次。也许他们应该分配更少的时间来开发新的变声和面部变形过滤器,而应该分配更多的时间来破坏人们的 Twitter 时间轴!也许他们在 Twitter 上的存在对他们作为一个年轻公司实现目标没有起到任何重要作用。谁知道呢?

体育联盟的推特使用了许多适合他们运动的行话,许多词指向用于广告游戏的推特(像“今晚”、“观看”和“游戏”这样的词很常见)。

看起来,大学的推特们喜欢谈论他们自己。除了普林斯顿和 UMiami,所有的账户都把他们的大学名称(以某种形式)作为他们最常用的词。其他常见的词是“学生”、“研究”和“校园”,表明他们的推特经常被用来谈论各自大学发生的事情。大多数科技公司和一些流媒体公司的名字都出现在他们的常用词汇列表中。这在其他类别中相当少见。

流媒体网站似乎大多使用他们的 Twitters 来推广新的发布,因为“首映”、“推广”、“新闻”和“今晚”都是跨帐户的常用词。与其他一些面向客户的类别不同,很少有词暗示了与快餐、科技和航空公司同等水平的解决客户问题的能力。

由于 9/10 的新闻推特是美国网站,许多词与美国政治和时事密切相关,如“总统”、“特朗普”和“弹劾”。有趣的是,BBC(唯一的国际新闻来源)的列表中也有“特朗普”和“总统”。唯一一个明显与非美国时事有关的词是“洪”,这是《华尔街日报》排名第十的最常用词。我们打赌他们第 11 个最常用的词是“孔”。有人要吗?

名人账户似乎主要是为了感谢他们的粉丝。“爱”、“感谢”和“快乐”都是流行词汇。不同名人的推特账户之间似乎也有明显的重叠。尽管类别内和类别间的字数差异很大,但名人的最高字数往往要少得多。与许多一天发多次推特、处理投诉和提及各种商品或销售的公司不同,名人的推特量要小得多。这导致热门词的使用更少,推文内容的变化更多。

我们还想看看前 10 个词在类别上的重叠情况。因为我们认为 10 路维恩图会有点忙乱,所以我们选择使用网络。较大的橙色节点代表类别,较小的蓝色节点代表单词,连接表示单词在该类别的前 10 名中。

network visualization of top 10 words per category

我们发现有趣的是,体育是唯一一个与其他类别完全没有重叠的类别。在 55 个不同的单词中,有 13 个至少被两个类别共享:“我们”、“请”、“dm”、“对不起”、“你”、“谢谢”、“喜欢”、“嗨”、“谢谢”、“我们很好”、“新的”、“爱”和“一”。单词节点的平均度为 1.45,这意味着平均排名靠前的单词通常是不止一个类别的常用单词。当只看跨多个类别共享的常用词时,平均程度为 2.92(大幅增加)。许多这样的共享词反映了消费者在 Twitter 上寻求帮助解决他们的问题或负面经历的流行,以及公司发出解决这些问题的推文数量。许多只用于一个类别的单词对该类别来说更加具体,比如所有的体育行话,“飞行”、“教授”和“特朗普”。

总之,本节中的自然语言处理技术帮助我们熟悉了来自不同账户和 Twitter 领域的推文内容。令人惊讶的是,我们随机选择了一些类别和账户,以为我们正在构建一个足够多样化的数据集来发现一些有趣的东西,而我们实际上确实收集了数据驱动的见解。现在我们知道我们的研究范围足够丰富,可以进一步研究,这就像我们已经验证了我们的概念设计证明,我们可以细化我们的研究问题,使其更窄,更有价值。

方法 3:递归神经网络(RNNs)

如果你已经做到了这一步,把这一步想象成喝完一碗可可脆饼后喝巧克力牛奶。这与我们开始这个项目的最初原因没有太大关系,但它无疑增加了我们的体验。

你可能想知道,为什么在过去的 10 分钟里,我们一直在不停地谈论 NLP 技术,如情感分析、词云可视化和词频分解,而我们现在提出了 RNNs。或者你可能想知道 RNN 是什么?这是完全正确的。

我们决定包括这一部分,因为,让我们面对现实吧,了解到吉米·法伦在他过去 5 年的推文中使用了 1303 次“今晚”这个词,这很酷,也很准确,但是你和我应该怎么处理这些信息呢?我们如何以最大限度地提供信息的方式来检测模式。好吧,你猜怎么着。答案就在我们心中。人类特别擅长综合信息。我们的神经元有点像野生的。但是,即使我们擅长综合信息,我们表达我们观察到的模式的能力也是相当糟糕的。

那么,我们为什么不训练一个神经网络模型来从数据中学习东西,就像人类会做的那样?对于这种类型的应用,RNNs 是神经网络的一种非常有用的变体。与依赖于两个连续输入相互独立的假设的普通神经网络不同,试图推断与基于语言的数据相关的模式需要某种“记忆”。网络必须捕捉、保留和积累信息。必须考虑对先前观测的依赖。

建筑

RNN model architecture

代码

stripped down, uncommented RNN code in case you want to borrow it for your own usage

运行中的网络

video of our celebrities RNN training and generating sample tweets with varying diversities

我们重新利用了在丹麦留学学院(DIS)学习的“人工神经网络和深度学习”课程的代码,以便训练四个不同的神经网络,每个网络都适合一个独特类别的数据。我们训练了 50 个纪元,获得了 60%的准确率。我们还生成了具有不同多样性(0.2、0.5 和 1.0)的 tweet 样本。在下面的四个部分中,我们将嵌入一些使用 0.2 多样性生成的样本 tweets,我们将比较网络在早期和后期学到了多少。

快餐——生成的 Tweet 样本

epoch 1/50: accuracy = 44.18%, "to make it right? Very mysterious!"

去弥补吗?非常神秘!重要的事情。你能告诉我们具体的决定吗?你能告诉我们怎么想吗?你能告诉我们具体的决定吗?你能告诉我们怎么想吗?你能告诉我们如何思考吗?你能不能不要介意?你能给我们讲讲吗

在训练的第一个时期,我们的 RNN 模型开始生成一条 tweet (280 个字符),带有一个起始种子(40 个字符),内容是“让它正确?很神秘!”。当它开始偏离输入序列时,显然是非常混乱的。由于短语“你能给我们发短信吗”在数据集中的流行度很高,它反复尝试以该表达开始构建句子,但无法产生超出该表达的真实英语单词。

epoch 50/50: accuracy = 84.27%, "Please send us a DM if you're interested"

安吉拉,如果你对辣鸡块感兴趣,请给我们发一封 DM!请告诉我们餐厅的位置和你的电话号码,这样我们就能解决这个问题了。谢谢!那不行!请告诉我们餐厅的位置和你的电话号码,这样我们就能解决这个问题了。谢谢!那不行!

在精确度提高了近一倍后,神经网络的表现好了很多。我们看到连贯的英语句子,甚至可以发现这条推文中提到的快餐领域的“辣块”,这正是我们希望看到的内容类型。我们还看到网络试图加入一些标签。诚然,没有必要在推文中说#so,但它知道“#”字符在数据集中出现的频率很高,并且它积极地试图与时俱进,这一事实足以成为值得骄傲的理由。我们的神经网络总是把客户放在第一位,反复承诺“把这件事做好”,反复说“那不行!”。这表明它已经理解并能够反刍它从训练数据中观察到的语言模式。

联赛——生成的推文样本

epoch: 3/50, accuracy = 51.7, "ty @Jamal_Carter6! What him scrape by t"

ty @Jamal_Carter6!看着他从第一名到第一名,从第一名到第一名,从第一名到第一名,从第一名到第一名,从第一名到第一名,从第一名到第一名,从第一名到第一名

虽然,就像快餐一样,网络似乎陷入了一个无限循环,试图一遍又一遍地使用短语“第一”,但它发现了体育推特的一些重要方面。它试图提及一名球员和一支球队,并使用了“损失”一词。

epoch: 50/50, accuracy = 62.46%, "professionals for their impact on the game"

职业球员因其对@ national 比赛的影响而在@ LAClippers # PGA champ | @ BKoepka(22 分,6 次 REB,11 次 AST)和@SheffieldUnited 中的@Lakers 和@ ConnecticutSun 赢得@ national:# NFL 100 最伟大的球队@NFLNetwork №1: 1997 @NCAADII 女子高尔夫和 the

这条最大准确度的推文不如它的快餐同行好(可能是因为不同账户之间的同质化程度较低),但它提到了真实的团队,并使用了真实的标签。“@BKoepka”是 Brooks Koepka 的真实 Twitter 句柄,“(22 PT,6 REB,11 AST)”是一个篮球运动员的合法统计报告,但当这两个部分在推文中相邻放置时没有意义。虽然国家队(一支棒球队)永远不会出现在 PGA 村(高尔夫球员),但我们可以看到体育推特的一些重要方面:胜利公告、球员统计数据和提及次数。这意味着许多体育推特包含关于即将发生的比赛和过去比赛结果的信息。

新闻-生成的推文样本

epoch: 3/50, accuracy = 51.40%, "dispatcher is being lauded for recognizi"

调度员因为在弹劾调查中认识到了比总统更多的东西而受到称赞,学生们认为各州和各州的总统和检察官是市长,这将是一场竞争。

再说一遍,虽然这条推文没有太多意义。它采用了我们在频率分析中注意到的一些流行语,比如“总统”和“弹劾”。尽管它的结构很荒谬,但它能够复述新闻媒体经常使用的词汇。

epoch: 46/50, accuracy = 58.74%, "Sen. Warren on Bloomberg entering the ra"

参议员沃伦对彭博进入比赛的呼吁法院为国家的法院的总统的情况下。这个州使得一个派了一个媒体被一个接收到的州去看弹劾案的听证会,他们已经想站在竞选的那一边了

这条推文比第一时代更接近真实的新闻推文。它能够提取推文中常见的信息(如“弹劾听证会”和“竞选”),我们可以推断新闻机构的许多推文目前正在讨论美国政治的两个最大方面:特朗普的弹劾听证会和即将到来的总统选举。

名人—生成的推文样本

epoch: 2/50, accuracy = 42.48%, "/Bv13d8lFHjc/?utm_source=ig_twitter_shar"

/Bv13d8lFHjc/?UTM _ source = ig _ Twitter _ share&igshid = 1 ric 6 ctn 7 ZZ UX #不负责任# TheMich # the good # hustle hart # the miller # Fallon tonight 感谢你们的演出感谢过去的演出感谢工作感谢看演出的眼神最美好的演出最美好的未来和最美好的父亲

这条推文的标签比任何其他类别都多,并且来自各种不同的账户。我们可以再次看到,频率分析中的前 10 个词中的一些被纳入进来,因为最后一部分使用了大量的“谢谢”、“展示”和“最好的”——我们认为这些语言意味着名人感谢他们的粉丝。

epoch: 47/50, accuracy = 56.88%, "nstagram.com/p/BopWlA6lP_e/?utm_source=i"

nstagram.com/p/BopWlA6lP_e/?UTM _ source = ig _ Twitter _ share&igshid = 1 zdttsjz 2 poo #今晚的法伦之夜:@ NBC world DOF dance #法伦之夜感谢@ HobbsAndShaw # TheNextLevel #法伦之夜感谢@ RealHughJannyMario&@ NBC world DOF dance #法伦之夜:@ NBC world DOF dance #法伦之夜感谢@TheEllenShow 今晚

这条推文包含一连串的提及和标签。由此,我们可以假设,比起体育账户,名人更热衷于给别人贴标签和包含标签。这最有可能提高他们推文的受欢迎程度,促进他们正在进行的各种项目,希望他们使用的一些标签能够爆炸,成为 Twitter 的趋势。这条特定的 RNN 生成的推文包含“今晚”、“谢谢”和“#FallonTonight”,这向我们表明,这个特定的 RNN 可能已经过度了,因为吉米·法伦在演出后发出了大量的“谢谢”(他需要冷静下来,不要歪曲我们的数据集)。

我们相信我们训练的四个 rnn 以一种真正有价值的方式帮助我们观察语言模式。不一定有生成推文的需求,因为大多数 Twitter 用户不难拿出仅 280 个字符的内容与世界分享,但这些递归神经网络能够合成大量推文并返回一些揭示原始数据特征的内容,这一事实非常酷!

未来方向

这个项目将来可以向许多潜在的方向扩展。由于 GetOldTweets3 使收集 Twitter 数据变得如此容易,我们很乐意检查更多的类别和每个类别的更多帐户,看看是否会出现更多的模式。同样,我们希望有时间在所有类别上训练一个递归神经网络,以便从数据中提取更多的模式。这将有助于我们进一步分析每一类 Twitter 讨论的一般话题,并更好地理解不同帐户组之间的一些趋势。

此外,引入一些不同类型的图表会非常有趣。我们的数据看起来是这样的,因为我们采用了最多 10,000 条推文,GetOldTweets3 是按时间倒序排列的,我们的数据集并没有完全设置为查看一段时间内的推文量。如果我们有时间,我们会取消我们的推文数量限制,重新搜索每个帐户,以获得过去 5 年的所有推文,然后我们会按类别绘制推文的时间序列分析。我们很想知道在过去的五年中是否有任何趋势,特别是在相对于时间的推文内容方面。我们可以设想这种时间序列分析启动另一个关于使用 NLP 和 ML 技术预测新闻趋势的大数据项目。

如果有时间,我们最想做的一件事就是创建一个机器学习模型,来预测给定推文的标签会有多流行。我们认为这是可行的,因为 Twitter API 和 UI 搜索字段使得查询带有趋势标签的推文变得非常容易,并且我们在整个项目中调查的所有账户都很受欢迎并且得到了验证。我们很想研究给定推文中使用的标签与该推文的病毒传播程度之间的关系,这可以通过赞数和转发数来量化。这个模型有可能被用来帮助公司决定他们应该利用哪些趋势,哪些趋势不值得花费精力。能够在一定程度上准确预测一条给定推文的成功将是一个有用和有趣的工具,尤其是在这个互联网营销的时代。

代码库

如果这个项目以任何方式、形状或形式让你感兴趣,我们强烈建议你使用我们的代码。采用我们在本文中使用的一种技术,用它来构建一些很酷的东西。然后写一个故事,让大家跟你学习,跟你一起学习。

[## sejaldua/Twitter-sphere

使用 8 x 10 x 10000 的推特数据集和大数据技术对推特内容进行分类分析…

github.com](https://github.com/sejaldua/twitter-spheres)

承认

感谢我们的 Lucian Leahu 教授,感谢他对这个项目的帮助,感谢他教给我们这么多关于大数据领域的知识。感谢 Ulf Aslak Jensen 创建了这个课程和练习,帮助我们学习一些基本技能,我们现在可以用这些技能来处理令人敬畏的项目。感谢 GetOldTweets3,与 Twitter 的 API 相比,它就像是一个大大的拥抱。像往常一样,向开源社区和 StackOverflow 大声欢呼,感谢他们一路上帮助我们解决所有有趣的问题。还有像你这样的读者,激励你不断创造,不断用数据讲述故事!

参考

[## Twitter 数据挖掘:挖掘没有 API 键的 Twitter 数据。

使用一行命令获取旧的 Twitter 大数据进行分析。

medium.com](https://medium.com/@IrekponorVictor/twitter-data-mining-mining-twitter-data-without-api-keys-a2a2bd3f11c) [## 用 python 创建单词云

在最近的一个 NLP 项目中,我发现单词云可以用遮罩来创建。在本文中,我将介绍如何…

towardsdatascience.com](/creating-word-clouds-with-python-f2077c8de5cc) [## netwulf

Python 中简单的交互式网络可视化。网络可视化是一个不可或缺的工具,探索…

pypi.org](https://pypi.org/project/netwulf/) [## 理解神经网络。从神经元到 RNN、CNN 和深度学习

神经网络是目前最流行的机器学习算法之一。它已经被决定性地证明了…

towardsdatascience.com](/understanding-neural-networks-from-neuron-to-rnn-cnn-and-deep-learning-cd88e90e0a90)

分析 R 中的视频游戏数据

原文:https://towardsdatascience.com/analyzing-video-games-data-in-r-1afad7122aab?source=collection_archive---------13-----------------------

作为一名游戏玩家,我从分析这个数据集中获得了很多乐趣。实际上,这个数据集是由两个不同的数据集合并而成的: Tidytuesday 和 Kaggle 。使用两个数据集的原因是因为 Tidytuesday 数据集没有足够的信息来进行有趣的分析。这就是为什么我合并了这两者,以便从中获得更多有趣的数据和见解。这也是我第一篇使用 Tidymodels 元包应用一些机器学习的文章。

***Loading Libraries***library(tidyverse) ## For data wrangling and visualization
library(lubridate) ## To work with dates
library(ggpubr)    ## Extra visualizations and themes
library(patchwork) ## Patch visualizations together
library(hrbrthemes)## Extra themes and formatting
library(ggalt)     ## Extra visualizations
library(vapoRwave) ## Retro themes
library(extrafont) ## Exta fonts***Loading Data*****video_games** <- read_csv("[https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-07-30/video_games.csv](https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-07-30/video_games.csv)") %>%
  mutate(release_date = as.Date(release_date, "%b %d, %Y")) %>%
  distinct(game, developer, publisher, .keep_all = TRUE)**metacritic_games** <- read_csv("C:\\Users\\ACER\\Downloads\\metacritic-games-stats-20112019\\metacritic_games.csv",trim_ws = TRUE) **Cleaning and mergin the datasets together**games_final <- metacritic_games %>%
  filter(platform=="PS4") %>% 
  inner_join(video_games,by = "game") %>%
  mutate(owners=parse_number(owners,trim_ws = TRUE)) %>%
  mutate(publisher = case_when(str_detect(publisher,pattern = "Warner Bros|WB")~"Warner Brothers",TRUE~publisher)) %>% 
  select(-c(release_date.x,developer.y,number_players,number,metascore.y))
  • 在读入 video_games 数据后,我使用 mutate 函数将 release_date 列转换为日期类型
  • 由于一些游戏有多个开发者和流派,我使用了 distinct 函数来获得每行的唯一游戏
  • 对于这个分析,我只对 PS4 游戏感兴趣。这就是为什么我在对 video_games 数据集进行 inner_join 之前,将 metacritic_games 数据集过滤为仅 PS4 游戏
  • 使用 parse 函数从 owners 列中获取每个游戏的数值上限
  • 由于有多家华纳兄弟出版社,我使用了 case_when 函数将它们合二为一
  • 最后,我取消选择了重复的列

进一步修整

经过一些调查,我意识到数据中有太多的垃圾,为了在游戏层面上做一个有见地的分析,我决定只根据拥有他们游戏的总人数来看前 50 名发行商

**Calculating top 50 publishers**top_50_publishers <- games_final %>% 
  group_by(publisher) %>% 
  summarise(Owners=sum(owners)) %>% 
  top_n(50)Filtering **games_final** based on top 50 publisherstop_50_filtered <- games_final %>% 
  semi_join(top_50_publishers)
  • 首先,我在 games_final 数据集中按发行商分组,以获得每个发行商的所有者总数,然后使用 top_n 函数获得基于所有者的前 50 名发行商
  • 然后我在 games_finaltop_50_publishers 数据集之间使用 semi_join 函数。它的作用是根据前 50 名发行商中的前 50 名发行商过滤出游戏 _ 决赛数据
  • 这个数据集比原来的小很多,但它允许我只看主流游戏
  • 请注意,这个过滤后的数据只到 2018 年,以防你想知道为什么你最喜欢的游戏没有在 2019 年上市,如战神蜘蛛侠红色死亡救赎 2

This is what the final dataset looks like

前 50 名出版商是谁?

top_50_filtered %>%
  filter(!is.na(publisher)) %>% 
  group_by(publisher) %>% 
  summarise(owners=sum(owners)) %>% 
  ggplot(aes(reorder(publisher,owners),owners))+
  geom_bar(fill="#8B2E8B",stat = "identity",color="black")+
  coord_flip()+
  geom_text(aes(label=paste0(round(owners/1000000,digits = 1)," ","M")),color="white",fontface="bold",hjust=1)+
  new_retro()+
  scale_color_hotlineBling()+
  labs(x=" ")+
  scale_y_comma()+
  theme(legend.position = "none",axis.text.y = element_text(colour = "white",family = "SF Alien Encounters")) 
  • 从删除 NA 发布者开始
  • 执行相同的 group by 函数来获得每个发布者的所有者总数
  • 使用 ggplotgeom_bar 制作标准条形图,并使用 coord_flip 功能翻转轴。注意:ggplot 中的重新排序功能允许绘制从最大值到最小值的排序柱状图
  • 由于 owners 变量是以百万为单位的,所以我将它除以一百万,并在末尾连接一个“M ”,使用 paste0 来标记每个发布者的所有者总数,而不会影响美观

  • 那里有很多熟悉的面孔,比如育碧、摇滚明星游戏等等,但是老实说,我不知道数字极端公司 T21——坐在最上面
  • 他们实际上是一款非常受欢迎的在线免费角色扮演射击游戏的负责人,这款游戏名为 Warframe ,于 2013 年问世

用户评分和 Metascore 有什么关系?

top_50_filtered %>% 
  ggplot(aes(user_score,metascore.x))+
  geom_point(color="green")+
  geom_text(aes(label=game),check_overlap = TRUE,color="turquoise",size=3)+
  vapoRwave::new_retro()+
  scale_color_newRetro()+
  labs(title = "Relationship between Userscore and Metascore",x="USERSCORE",y="METASCORE")

  • 用户评分Metascore 之间有大致趋势。像《巫师 3》、《GTA V》、《雷曼传奇》、《火箭联盟》(《T30》、《T31 》)这样的游戏在这两方面都获得了高分,这是理所应当的
  • 圈出的游戏是那些被大肆宣传但未能达到预期的游戏。虽然我很惊讶战争阴影的用户评分这么低,但是那个游戏有病啊!
  • 一个引起我注意的游戏是疯狂的麦克斯。评论家对它的评价不冷不热,但用户喜欢它。因为前者,我实际上从来没有玩过,但这可能会改变我的想法

用户得分排名前 30 的游戏

top_50_filtered %>%
  top_n(30,user_score) %>% 
  ggplot(aes(reorder(game,user_score),user_score))+
    geom_lollipop(color="white")+
  coord_flip()+
  geom_text(aes(label=user_score),color="white",hjust=-1)+
  new_retro()+
  scale_y_continuous(limits = c(0,100))+
  labs(x=" ",title = "Top 30 Games by User Score")
  • 使用 top_n 函数根据 user_score 筛选出前 30 个游戏
  • 重新排序 ggplot 中的功能,从最大值到最小值对图形进行排序
  • geom_lollipop 制作棒棒糖图

  • 毫不奇怪看到巫师 3 在顶端。这场比赛是一个杰作
  • 虽然我很惊讶地看到内邪 2 排在第二位。这是一个非常好的游戏,但我没有意识到它会获得如此高的分数,超过了像《GTA V》这样的游戏
  • 因此,的续集《战争阴影,中土世界:魔多阴影》在用户中获得了更好的分数。我个人更喜欢前传,但两者都是不错的游戏
  • 我很惊讶地看到蝙蝠侠:阿卡姆骑士低于预期。这是我在 PS4 上最喜欢的游戏之一,也是我认为蝙蝠侠阿卡姆三部曲中最好的。我认为低分可能是因为人们被蝙蝠战车的机制和乏味的老板战斗所激怒

Metascore 的 op 30 游戏

top_50_filtered %>%
  top_n(30,metascore.x) %>% 
  ggplot(aes(reorder(game,metascore.x),metascore.x))+
    geom_lollipop(color="light blue")+
  coord_flip()+
   geom_text(aes(label=metascore.x),color="light blue",hjust=-1)+
  new_retro()+
  scale_y_continuous(limits = c(0,100))+
  labs(x=" ",y=" ",title = "Top 30 Games by Meta Score")
  • 和以前一样的代码。刚刚用 metascore 替换了用户分数

  • 你可以清楚地看到,当我们从用户分数转移到 Metascore 时,许多游戏都发生了变化。使用 anti_join 函数,我们可以看到哪些游戏出现在用户分数排名前 30 的游戏中,而没有出现在元分数排名前 30 的游戏中
top_50_filtered %>%
  top_n(30,user_score) %>%
  anti_join(top_50_filtered %>% 
              top_n(30,metascore.x))
  • 这里的 anti_join 函数自动检测两个数据框之间的公共列— 游戏,并显示 metascore 排名前 30 的游戏中没有的前 30 个用户游戏

  • 除了邪恶 2疯狂的麦克斯之外,这些游戏中的大多数在用户评分和 Metascore 之间没有太大的区别

按发布者的用户分数分布

top_50_filtered %>%
  filter(!is.na(publisher)) %>% 
  ggplot(aes(reorder(publisher,user_score,FUN = mean),user_score))+
  geom_boxplot(color="purple")+
  geom_hline(yintercept = 80,color="white")+
  coord_flip()+
  new_retro()+
  labs(x=" ")
  • 绘制箱线图以可视化前 50 名出版商的用户分数分布
  • 使用重新排序功能根据平均用户分数对箱线图进行排序
  • 在 80 处增加了一条垂直线,作为一个伟大游戏的门槛

  • 我明白为什么育碧在这里得分这么低了。他们最近在《孤岛惊魂》和《刺客信条》系列中的游戏表现平平
  • 摇滚明星从不让人失望。他们制作的每一款游戏都是杰作
  • 动视遍地都是。也许人们终于厌倦了使命召唤系列
  • Capcom 真的很低。这很可能是由于发布了一款不完整的街霸 V 游戏并对其收取全价。但是 2019 年对卡普空来说是令人惊讶的一年,像怪物猎人、生化危机 2:翻拍和鬼泣 5 这样的游戏对他们来说都是巨大的成功

发布者的 Metascore 分发

top_50_filtered %>%
  filter(!is.na(publisher)) %>% 
  ggplot(aes(reorder(publisher,metascore.x,FUN = mean),metascore.x))+
  geom_boxplot(color="green")+
  geom_hline(yintercept = 80,color="white")+
  coord_flip()+
  new_retro()+
  labs(x=" ",y="Metascore")

似乎出版商在 Metascore 方面比他们的用户得分做得更好

平均游戏时间最长的游戏

top_50_filtered %>%
  top_n(30,average_playtime) %>% ggplot(aes(reorder(game,average_playtime/60),average_playtime/60))+
  geom_lollipop(color="purple")+
  coord_flip()+
  geom_text(aes(label= round(average_playtime/60)),color="white",hjust=-1)+
  vapoRwave::new_retro()+
  scale_y_continuous(limits = c(0,40))+
  labs(x=" ",y="Average playtime in 2 weeks -  (hrs)")
  • 每款游戏的平均游戏时间(T47)以分钟为单位来衡量用户两周平均玩游戏的时间
  • 使用 top_n 函数只查看前 30 个最长的游戏
  • 绘图时,将 average_playtime 除以 60,换算成小时
  • geom_text 以小时为单位标注平均播放时间

  • 排名靠前的最长游戏大多是开放世界的比如正义事业 4、孤岛惊魂 5、疯狂的麦克斯、刺客信条、GTA V、巫师 3
  • 惊讶地看着号猎物号。我没有玩,但我不认为这是开放世界

用户正面评价的百分比

top_50_filtered **%>%**  **mutate**(percentage_positive_users=positive_users/(positive_users+negative_users+neutral_users),
         percentage_positive_critics =positive_critics/(positive_critics+negative_critics+neutral_critics)) **%>%**
  **filter**(positive_users>=10,percentage_positive_users>=0.5) **%>%**
  **top_n**(30,percentage_positive_users) **%>% ** **ggplot**(aes(**reorder**(game,percentage_positive_users),percentage_positive_users))+
  **geom_lollipop**(color="white")+
  **coord_flip**()+
  **labs**(x=" ")+
 ** new_retro**()
  • 使用 mutate 函数创建两个新列:percentage _ positive _ userspercentage _ positive _ critics
  • 由于有些游戏获得的总分很少,我使用了过滤器功能,只显示那些至少有 10 个正面用户分数,并且正面用户总百分比≥ 50%的游戏
  • Rest 与我们在之前的棒棒糖图表中使用的代码相同

  • 哇!看到 GTA V 这么低很惊讶吧
  • 《疯狂的麦克斯》和《死亡之光》是其中一款非常好但却不为人知的游戏
  • 《剑术在线》收到了来自评论家的可怕评论,但是看起来用户们喜欢它

评论家的正面评论百分比

top_50_filtered **%>%**  **mutate**(percentage_positive_users=positive_users/(positive_users+negative_users+neutral_users),
         percentage_positive_critics =positive_critics/(positive_critics+negative_critics+neutral_critics)) **%>%**
  **filter**(positive_critics>=10,percentage_positive_critics>=0.5) **%>%**
  **top_n**(30,percentage_positive_critics) **%>% ** **ggplot**(aes(**reorder**(game,percentage_positive_critics),percentage_positive_critics))+
  **geom_lollipop**(color="white")+
  **coord_flip**()+
  **labs**(x=" ")+
 ** new_retro**()

  • NBA 2k16 和 NBA 2k17 得到了评论家的好评,但用户的评分很低

老实说,我没有听说过排名前四的游戏,但由于它们的规模小,所以不被认为是 AAA 级游戏

预测分析

预测元得分是不实际的,因为它是基于数据集中提供的所有数值变量的公式计算的。预测用户评分更有意思。为此,我将使用 Tidymodels 元包。它是一个软件包的集合,允许您创建一个无缝的数据管道,从预处理您的数据、调整您的模型、建模您的数据、做出预测和测量您的模型性能,同时遵守 Tidyverse 的“整洁”原则

数据准备

**library(tidymodels)**ratings_data <- top_50_filtered %>% 
  **mutate**(percentage_positive_users=positive_users/(positive_users+negative_users+neutral_users),
         percentage_negative_users =negative_users/(positive_users+negative_users+neutral_users),
         percentage_positive_critics =positive_critics/(positive_critics+negative_critics+neutral_critics),
         percentage_negative_critics =negative_critics/(positive_critics+negative_critics+neutral_critics)) %>% 
  **drop_na()****Splitting the data**split <- initial_split(ratings_data,prop = 0.6,)train_games <- split %>% training() %>%
test_games <- split %>% testing()
  • 使用 mutate 函数创建新变量,这些变量将用作 user_score 的预测值
  • 删除任何缺少的值
  • 使用 rsample 库中的 intial_split 函数为我们的训练和测试分割创建一个分割参数
  • 将它与来自 rsample训练测试函数链接起来,创建我们的训练和测试数据集

创建预处理管道

**Creating Recipe**norm_recipe <-
  **recipe**(user_score~percentage_positive_critics+percentage_negative_critics+percentage_positive_users+
           percentage_negative_users+price+genre+rating+publisher,data = train_games) %>%
  **step_naomit**(all_numeric(),all_nominal()) %>%
  **step_dummy**(all_nominal(),,one_hot = TRUE) %>% 
  **step_normalize**(all_predictors(),na_rm = TRUE) %>%
 ** step_corr**(all_predictors()) %>%
  **prep**()**Applying Recipe on Train and Test sets**train_prepped <- juice(norm_recipe)
test_prepped <- norm_recipe %>% bake(test_game)
  • 使用配方包,我正在创建一个“配方”,它基本上是我想要如何处理我的数据中的变量的管道
  • 我们从定义因变量和自变量之间的关系开始
  • “步进”功能是数据转换功能
  • step_naomit 删除名义变量和数值变量中的缺失值
  • step_dummy 对所有分类变量进行一次性编码
  • step_normalize 归一化所有数值预测值
  • step_corr 删除任何彼此高度相关的独立变量
  • 准备功能基本完成并准备配方
  • juice 函数,应用于 norm_recipe,给出了训练集的转换版本
  • 烘焙函数与定额 _ 配方链接在一起,应用于测试数据,给出了转换后的版本

建模

ranger <- rand_forest(trees = 100,mode = "regression") %>% 
  set_engine("ranger") %>% 
  fit(user_score~.,data=train_prepped)
  • 为了定义我们的模型,我们使用了 Parsnip 包来定义一个 randomforest 回归模型
  • 将发动机设置到档位
  • 使用拟合函数来定义我们的公式,并提供转换后的训练数据

预测

**Converting NAs to 0**test_prepped <- test_prepped %>% 
  mutate_all(~replace(.,is.na(.),0)) **Making predictions**ranger %>% 
  predict(test_prepped) %>% 
   bind_cols(test_games) %>% 
   select(game,.pred,user_score)**Measuring Model Accuracy**ranger %>% 
  predict(test_prepped) %>%
  bind_cols(test_games) %>% 
  metrics(truth=user_score,estimate=.pred)
  • 在对准备好的测试集应用预测之前,我必须将一些 NAs 转换为 0,否则 randomforest 模型将抛出错误
  • 最后,我们使用 ranger 模型对我们准备好的测试集进行预测,并将预测与原始测试数据结合起来,以查看每个游戏的预测和实际用户分数

Sample of predicted vs actual user scores

  • 一旦我们做出了预测,我使用标尺包中的度量函数,通过提供实际和预测的用户分数来计算模型的准确性

  • rsq 衡量因变量 user_score 的变化在多大程度上可以由数据集中的自变量来解释。在我们的案例中,考虑到我们拥有的数据类型,这还不算太糟糕,而且它是一个非常小的数据集
  • 它可以通过超参数调优和交叉验证来改进,但这超出了本文的范围。此外,这些功能目前仍在 Tidymodels 中开发,在我们的分析中还没有无缝集成它们

结论

我在对这些数据进行端到端分析时获得了很多乐趣,并且能够使用 Tidymodels 包应用一些基本的机器学习是很好的实践。尽管如此,重要的是要注意不要从这些数据中得出任何重要的结论,因为我们只查看了原始数据源的一个非常小的子集。我认为,如果我们收集更多关于所有不同视频游戏的数据,这种分析会变得更加有趣。

使用 Python 中的自然语言工具包分析葡萄酒描述

原文:https://towardsdatascience.com/analyzing-wine-descriptions-using-the-natural-language-toolkit-in-python-497ac1e228d5?source=collection_archive---------23-----------------------

为外行描述葡萄酒

几个月前,我创建了一个 web 应用,它允许用户输入一个查询,并根据语义相似度返回葡萄酒推荐。它是使用 Tensorflow 实验室通用句子编码器构建的。当我将该工具投入生产时,我添加了将用户输入写入数据库的代码,这样我就可以分析人们用来寻找葡萄酒的词语。根据我对目前记录的内容的分析,似乎大多数人都和我一样:我几乎没有评论葡萄酒的经验,我不知道在搜索葡萄酒时应该使用哪些词。我记录的大多数查询都是两三个简单的词,比如“容易喝”为了帮助我自己和我的用户,我正在钻研葡萄酒描述,看看我能从描述葡萄酒的语言中学到什么。滚动到文章底部,查看完整的代码。

数据和依赖关系

原始数据可以在 Kaggle 上找到;然而,本文中的例子使用了我的工程数据。对于那些感兴趣的人,我在我的原始文章中讨论了一些数据工程。为了分析文本,我使用了 WordCloud 和 nltk(自然语言工具包) python 包。我从加载依赖项和检查数据开始:

#dependencies
import pandas as pd
import sqlite3
from sqlite3 import Error
import refrom wordcloud import WordCloud
import matplotlib.pyplot as pltimport nltk
from nltk.tokenize import RegexpTokenizer
from nltk.stem.snowball import SnowballStemmer
#nltk.download('wordnet')
from nltk.stem.wordnet import WordNetLemmatizer#nltk.download('stopwords')
from nltk.corpus import stopwordsfrom sklearn.feature_extraction.text import CountVectorizer#force output to display the full description
pd.set_option('display.max_colwidth', -1)#create connection to database
conn = sqlite3.connect('db\wine_data.sqlite')
c = conn.cursor()#create the pandas data frame
wine_df = pd.read_sql('Select title, description, rating, price, color from wine_data', conn)#display the top 3 records from the data frame
wine_df.head(3)

Top 3 results from wine_df

字数和分布

从关于数据的一些基本信息开始,很容易向数据框添加一个字数统计列,并使用 pandas 的 describe 方法来处理一些基本统计数据:

#inline function to produce word count, splitting on spaces
wine_df['word_count'] = wine_df['description'].apply(lambda x: len(str(x).split(" ")))wine_df.word_count.describe()

wine_df.word_count.describe()

使用 matplotlib 中的图可以很容易地直观显示字数的分布:

#set x for the histogram and set bins based on max
x = wine_df['word_count']
n_bins = 140#plot histogram
plt.hist(x, bins=n_bins)
plt.show()

Distribution of description word count

停用词和频率

在依赖项中,我导入了 NLTK 库中包含的停用词列表。停用字词是最常见的字词列表,如“the”和“of”将它们从描述中移除可以突出更相关的常用词。我通过词频来判断是否应该将额外的词添加到停用词表中。在计算字数之前,我使用正则表达式清除描述,删除标点符号、标签和特殊字符:

stop_words = set(stopwords.words("english"))#show how many words are in the list of stop words
print(len(stop_words))
#179#loops through descriptions and cleans them
clean_desc = []
for w in range(len(wine_df.description)):
    desc = wine_df['description'][w].lower()

    #remove punctuation
    desc = re.sub('[^a-zA-Z]', ' ', desc)

    #remove tags
    desc=re.sub("&lt;/?.*?&gt;"," &lt;&gt; ",desc)

    #remove digits and special chars
    desc=re.sub("(\\d|\\W)+"," ",desc)

    clean_desc.append(desc)#assign the cleaned descriptions to the data frame
wine_df['clean_desc'] = clean_desc#calculate the frequency
word_frequency = pd.Series(' '.join(wine_df['clean_desc']).split()).value_counts()[:30]
word_frequency

25 most frequent words

查看最常用单词的列表,我决定将“葡萄酒”和“饮料”添加到停用单词列表中,这样它们就不会显示在单词云中。

#add single word to stoplist
#stop_words.add("wine")#add list of words to stoplist
add_stopwords = ["wine", "drink"]
stop_words = stop_words.union(add_stopwords)print(len(stop_words))
#181

词干化还是词干化?

两者都是规范化语言的技术,但是变元化和词干化之间的主要区别在于变元化将单词简化为词根形式,同时保持它是一个真实的单词。词干化通过去除后缀将单词还原为词根形式,并将其转化为真实单词的表示形式。例如,词干“body”和“body”都会导致“bodi”我相信共识是,引理满足优于一些词干算法;然而,词干仍然是一项需要理解的重要技术。比较这两个词云:第一个用词干处理,第二个用词条解释:

Stemming (left) v.s. Lemmatisation (right)

尽管大体相似,但请注意词干是如何影响单词后缀的。你可以看到包括“dri”、“complex”和“medium bodi”在内的几个词之间的明显区别

stem_desc = []
for w in range(len(wine_df['clean_desc'])):split_text = wine_df['clean_desc'][w].split()

    ##Stemming
#     stm = SnowballStemmer("english")
#     split_text = [stm.stem(word) for word in split_text if not word in stop_words] 
#     split_text = " ".join(split_text)
#     stem_desc.append(split_text)

    #Lemmatisation
    lem = WordNetLemmatizer()
    split_text = [lem.lemmatize(word) for word in split_text if not word in stop_words] 
    split_text = " ".join(split_text)
    stem_desc.append(split_text)
stem_desc

生成单词云

词云是可视化文本数据的一种有用方式,因为它们使理解词频变得更容易。在葡萄酒描述中出现频率更高的词在云中会显得更大。这是一种提取和可视化关键词的方法。

#set the word cloud parameters
wordcloud = WordCloud(width = 800, height = 800, background_color = 'black', stopwords = stop_words, max_words = 1000,                  min_font_size = 20).generate(str(stem_desc)) #plot the word cloud
fig = plt.figure(figsize = (8,8), facecolor = None)
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
#fig.savefig("wordcloud.png")

Word Cloud

分析 n 元语法

观察排名靠前的单词序列有助于理解描述葡萄酒的语言。三元模型分析三个单词的组合,可以让我们深入了解描述葡萄酒的常见方式,因为它保持了单词的顺序。通常,n-gram 模型用于帮助预测序列中的下一个项目,并帮助在文本分析期间维护上下文。

因为目的是分析如何描述葡萄酒,所以我需要基于频率分析创建一个新的停用词列表。我使用 scikit-learn CountVectorizer 创建一个函数来生成三元模型,然后将它们放入一个数据框中,看看我的停用词列表是否需要调整。

def get_trigrams(descriptions, n=None):

    vec = CountVectorizer(ngram_range = (3,3), max_features = 20000).fit(descriptions)
    bag_of_words = vec.transform(descriptions)
    sum_words = bag_of_words.sum(axis = 0) 
    words_freq = [(word, sum_words[0, i]) for word, i in vec.vocabulary_.items()]
    words_freq =sorted(words_freq, key = lambda x: x[1], reverse = True)

    return words_freq[:n]#run the function on the processed descriptions
trigrams = get_trigrams(clean_desc, n=15)#create a trigram data frame
trigram_df = pd.DataFrame(trigrams)
trigram_df.columns=["Trigram", "Freq"]#output top 15 rows
trigram_df.head(15)

top 15 trigrams

在分析了顶级三元模型之后,我决定使用一个定制的停用词表。我去掉了“葡萄酒”和“饮料”以及几个顶级品种,所以我只剩下 n_grams 来帮助我理解如何描述葡萄酒。

stops = ['wine','the', 'drink', 'an', 'cabernet', 'sauvignon', 'black', 'cherry']stem_desc = []
for w in range(len(wine_df['clean_desc'])):split_text = wine_df['clean_desc'][w].split()

    #Lemmatisation
    #lem = WordNetLemmatizer()
    split_text = [lem.lemmatize(word) for word in split_text if not word in stops] 
    split_text = " ".join(split_text)
    stem_desc.append(split_text)trigrams = get_trigrams(clean_desc, n=15)#create a trigram data frame
trigram_df = pd.DataFrame(trigrams)
trigram_df.columns=["Trigram", "Freq"]#output top 15 rows
trigram_df.head(15)

可以使用条形图来可视化三元模型。

fig = sns.set(rc = {'figure.figsize':(12,8)})
bp = sns.barplot(x = "Trigram", y = "Freq", data = trigram_df)
bp.set_xticklabels(bp.get_xticklabels(), rotation = 75)
plt.show()

Top 15 trigrams

通过查看三元模型,我可以深入了解应该如何查询葡萄酒。例如,我可以看到描述中包含像“带有暗示”和“有点”这样的描述符是很常见的结合“云”这个词,我现在对关键词、顶级品种和用于描述葡萄酒的语言有了更好的理解。以下是所有代码:

#dependencies
import pandas as pd
import sqlite3
from sqlite3 import Error
import re
from wordcloud import WordCloud
import matplotlib.pyplot as plt
import nltk
from nltk.tokenize import RegexpTokenizer
from nltk.stem.snowball import SnowballStemmer
#nltk.download('wordnet')
from nltk.stem.wordnet import WordNetLemmatizer
#nltk.download('stopwords')
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import CountVectorizer
#force output to display the full description
pd.set_option('display.max_colwidth', -1)
#create connection to database
conn = sqlite3.connect('db\wine_data.sqlite')
c = conn.cursor()#create the pandas data frame
wine_df = pd.read_sql('Select title, description, rating, price, color from wine_data', conn)#display the top 3 records from the data frame
wine_df.head(3)#inline function to produce word count, splitting on spaces
wine_df['word_count'] = wine_df['description'].apply(lambda x: len(str(x).split(" ")))wine_df.word_count.describe()#set x for the histogram and set bins based on max
x = wine_df['word_count']
n_bins = 140#plot histogram
plt.hist(x, bins=n_bins)
plt.show()stop_words = set(stopwords.words("english"))#show how many words are in the list of stop words
print(len(stop_words))
#179#loops through descriptions and cleans them
clean_desc = []
for w in range(len(wine_df.description)):
    desc = wine_df['description'][w].lower()

    #remove punctuation
    desc = re.sub('[^a-zA-Z]', ' ', desc)

    #remove tags
    desc=re.sub("&lt;/?.*?&gt;"," &lt;&gt; ",desc)

    #remove digits and special chars
    desc=re.sub("(\\d|\\W)+"," ",desc)

    clean_desc.append(desc)#assign the cleaned descriptions to the data frame
wine_df['clean_desc'] = clean_desc#calculate the frequency
word_frequency = pd.Series(' '.join(wine_df['clean_desc']).split()).value_counts()[:30]
word_frequency#add single word to stoplist
#stop_words.add("wine")#add list of words to stoplist
add_stopwords = ["wine", "drink"]
stop_words = stop_words.union(add_stopwords)print(len(stop_words))
#181stem_desc = []
for w in range(len(wine_df['clean_desc'])):
split_text = wine_df['clean_desc'][w].split()

    ##Stemming
#     stm = SnowballStemmer("english")
#     split_text = [stm.stem(word) for word in split_text if not word in stop_words] 
#     split_text = " ".join(split_text)
#     stem_desc.append(split_text)

    #Lemmatisation
    lem = WordNetLemmatizer()
    split_text = [lem.lemmatize(word) for word in split_text if not word in stop_words] 
    split_text = " ".join(split_text)
    stem_desc.append(split_text)
stem_desc#set the word cloud parameters
wordcloud = WordCloud(width = 800, height = 800, background_color = 'black', stopwords = stop_words, max_words = 1000, min_font_size = 20).generate(str(stem_desc))#plot the word cloud
fig = plt.figure(figsize = (8,8), facecolor = None)
plt.imshow(wordcloud)
plt.axis('off')
plt.show()
#fig.savefig("wordcloud.png")def get_trigrams(descriptions, n=None):

    vec = CountVectorizer(ngram_range = (3,3), max_features = 20000).fit(descriptions)
    bag_of_words = vec.transform(descriptions)
    sum_words = bag_of_words.sum(axis = 0) 
    words_freq = [(word, sum_words[0, i]) for word, i in vec.vocabulary_.items()]
    words_freq =sorted(words_freq, key = lambda x: x[1], reverse = True)

    return words_freq[:n]stops = ['wine','the', 'drink', 'an', 'cabernet', 'sauvignon', 'black', 'cherry']
stem_desc = []for w in range(len(wine_df['clean_desc'])):
split_text = wine_df['clean_desc'][w].split()

    #Lemmatisation
    lem = WordNetLemmatizer()
    split_text = [lem.lemmatize(word) for word in split_text if not word in stops] 
    split_text = " ".join(split_text)
    stem_desc.append(split_text)trigrams = get_trigrams(clean_desc, n=15)#create a trigram data frame
trigram_df = pd.DataFrame(trigrams)
trigram_df.columns=["Trigram", "Freq"]#output top 15 rows
trigram_df.head(15)fig = sns.set(rc = {'figure.figsize':(12,8)})
bp = sns.barplot(x = "Trigram", y = "Freq", data = trigram_df)
bp.set_xticklabels(bp.get_xticklabels(), rotation = 75)
plt.show()

谢谢大家!

  • 如果你喜欢这个, 在 Medium 上关注我 获取更多
  • 通过订阅 获得对我的内容的完全访问和帮助支持
  • 我们连线上 LinkedIn
  • 用 Python 分析数据?查看我的 网站

—埃里克·克莱本

有关分析文本和自然语言处理的更多信息,请查看以下链接:

[## 自然语言工具包- NLTK 3.4.5 文档

NLTK 是构建 Python 程序来处理人类语言数据的领先平台。它提供了易于使用的…

www.nltk.org](https://www.nltk.org/) [## NLTK 图书

Steven Bird、Ewan Klein 和 Edward Loper 这本书的 NLTK 版本针对 Python 3 和 NLTK 3 进行了更新。第一个…

www.nltk.org](http://www.nltk.org/book/) [## 使用自然语言处理从文章中自动提取关键词

背景

medium.com](https://medium.com/analytics-vidhya/automated-keyword-extraction-from-articles-using-nlp-bfd864f41b34)

robotsdodream.com

利用散点文本空间分析 Yelp 数据集

原文:https://towardsdatascience.com/analyzing-yelp-dataset-with-scattertext-spacy-82ea8bb7a60e?source=collection_archive---------20-----------------------

使用 NLP 对文本数据进行探索性数据分析和可视化

Scattertext spaCy

文本挖掘领域最关键的工作之一是可视化地呈现文本数据的内容。使用自然语言处理(NLP),数据科学家可以总结文档,创建主题,从不同角度和细节范围探索内容的故事情节。

这篇文章将探索 Yelp 数据集,然后使用散点图来可视化和分析文本数据。

什么是分散文本?

Scattertext 是一种工具,旨在可视化哪些单词和短语比其他单词和短语更具类别特征。

数据源

对于这个例子,我们将关注 Yelp 数据集中与 RV 相关的类别。完整的 Yelp 数据集包含 1000 多个类别和 600 万条评论。我们编辑过的 CSV 文件可以在我的 GitHub repo 中找到,还有关于我如何将 Yelp 数据集 JSON 文件转换成 CSV 文件的 Jupyter 笔记本。一篇媒体文章也贴出来了,对转换过程给出了更详尽的解释。

这个编辑过的 csv 由 Yelp 数据集中的 5 个类别组成:
RV Repair``RV Dealers``RV Rental``RV Parks``Campgrounds

加载并清理数据集

import pandas as pddf = pd.read_csv('yelp_reviews_RV_categories.csv')

在开始之前,我们想知道如何对评级进行分组。通过使用 seaborn distplot,我们可以检查评级在该数据集中的分布情况。

import seaborn as sns
sns.distplot(df['review_stars']);

A seaborn distplot plots a univariate distribution of observations

该图显示大多数评论被评为 1 星或 5 星,而我们只能比较 5 星和 1 星之间的评论,这将忽略 2-4 星的评论。相反,让我们将评级合并为高或低。

df['rating'] = df['review_stars'].replace(
               {1:'Low Rating', 2:'Low Rating', 3:'Low Rating',
                4:'High Rating', 5:'High Rating'})

因为我们知道这个数据集有 5 个不同的类别,我们可以进一步将相似的类别组合在一起。让我们只使用RV parksCampgrounds,暂时忽略RV RepairRV DealersRV Rental

df_Parks_Camp = df[df['categories'].str.contains(
                'RV Parks|Campgrounds', na=False)]

NLP 分析—使用散点图和空间

既然我们已经预处理了数据集,我们可以开始一些分析了。确保你已经在你的内核中下载了一个空间英语模型。

en_core_web_sm 是一个在书面网络文本(博客、新闻、评论)上训练的小型英语模型,包括词汇、向量、句法和实体。

import spacy
import scattertextnlp = spacy.load('en_core_web_sm')

如果没有,可以下载!

!python -m spacy download en_core_web_sm

接下来,我们将使用下面的函数来:

  • 建立我们的语料库,从数据集中收集文本
  • 获取术语频率和比例 f 值
  • High Rating & Low Rating按降序创建数据帧
Parks_Camp_high, Parks_Camp_low = term_freq(df_Parks_Camp)

Left — Sorted by High Rating. Right — Sorted by Low Rating

了解评分系统

Scattertext 使用缩放的 f-score ,它考虑了类别特定的精度和术语频率。虽然一个术语可能在两个类别中频繁出现(HighLow评级),但是缩放的 f 分数确定该术语是否比其他术语更具有类别特征(HighLow评级)。

例如,虽然术语parkHighLow评级中出现频率很高,但缩放后的 f 分数得出的结论是parkHigh 0.90 的关联度高于Low 0.10 的评级。因此,当评论包含术语park时,它更具有High评级类别的特征。

停止言语

请注意,有些术语不在列表中,如in theof theto theit was,这些是可以删除的停用词的一些示例。

在进行自然语言处理时,停用词是一些非常常见的词,这些词在帮助选择文档时似乎没有什么价值,它们被完全排除在词汇表之外,例如thethemthey

remove_terms(nlp.Defaults.stop_words, ignore_absences=True)

spaCy 有 326 个默认停用词,我们已经使用上面的代码从语料库中删除了这些词,但我们可以添加更多。

我们可以从自然语言工具包(NLTK)中添加更多的停用词。

from nltk.corpus import stopwords
stopWords = set(stopwords.words('english'))
nlp.Defaults.stop_words |= stopWords

我们也可以通过创建一个stopwords.txt文件来设置我们自己的停用词。
将文本文件中的任何内容(包括符号、数字、术语)作为停用词从语料库中删除。
随意使用我的 GitHub repo 里面的stopwords.txt文件。

with open('stopwords.txt', 'r') as f:
    str_f = f.read()
    set_stopwords = set(str_f.split('\n'))
nlp.Defaults.stop_words |= set_stopwords

每当我们完成文本文件的更新时,记得通过运行上面的代码来保存它,以便它更新到原始的停用词集。

一旦添加了更多的停用词,我们可以再次运行term_freq功能。

Parks_Camp_high, Parks_Camp_low = term_freq(df_Parks_Camp)

Term frequency and score after removing more stop words.

分散文本可视化

数据表很好,但是可视化更好!
我们可以创建一个散点图,直观显示 Yelp 数据集中评论的高评分和低评分之间的术语关联。

corpus_dataframe = df_Park_Camp
html = scattertext.produce_scattertext_explorer(
                   corpus,
                   category='Low Rating',
                   category_name='Low Rating',
                   not_category_name='High Rating',
                   width_in_pixels=1000,
                   metadata=corpus_dataframe['name'])

交互式 HTML

https://gyhou . com/RV-Parks-Campgrounds-Yelp-Reviews-scattertext . html

Searching for a term will show the name of the business and reviews.

理解散点图

在散点图的右侧,我们有一个评级最高的术语的概述和一个无序的术语列表(在特征下)。如果我们点击该术语,它将向我们显示数据集中的特定评论,显示为LowHigh评级。我们也可以在左下角手动搜索一个术语。

从散点图中,我们可以快速浏览一下评论中使用的术语。图右侧的红点表示与High评级更相关的术语,而左侧的蓝点表示与Low评级更相关的术语。

有了这个散点图,我们可以很容易地搜索可能对 Yelp 业务有用的术语。我们不仅可以看到一个术语是否与正面或负面评价更密切相关,还可以阅读每个单独的评论。

保存并共享为 HTML 文件

我们现在可以将它保存为 HTML 文件,以便在浏览器上查看和共享!

html_file_name = "RV-Parks-Campgrounds-Yelp-Review-Scattertext.html"
open(html_file_name, 'wb').write(html.encode('utf-8'))

感谢阅读!我很乐意听到你的想法,在这里评论或给我发消息。用于此的代码位于我的 GitHub 库中。

数据科学面试剖析

原文:https://towardsdatascience.com/anatomy-of-data-science-interview-fa9ff7caa37d?source=collection_archive---------18-----------------------

在数据科学行业拥有近十年的经验,我经常扮演面试双方的角色。在这篇文章中,我的意图是展示典型数据科学面试的一般结构,以及如何接近这个过程以取得成功。

免责声明:这是基于我的个人经验,可能与你的有有限的重叠,让我们看看我们的经验和重叠程度有多相似吧!!!!!!!!!!!!

在文章的最后,我列出了一些给寻找数据科学工作的新生的特别提示。

破冰:

在一次典型的面试中,在进入任何技术性/非技术性的讨论之前,首先你应该让自己对这个过程感到舒服。介绍部分给你一个与面试官建立融洽关系并展示你的沟通技巧的机会,千万不要错过!!!

你可以对面试官说一句非常简单的话“嗨,x 先生/女士,你好吗”?有许多你可以使用的班轮,这是一个候选线开始。随着我们的发展,我将解释如何处理“谈谈你自己”这个问题!!

面试结构:

根据我的观察,我觉得数据科学面试的各个部分及其权重可以大致通过下面的饼图来表示

让我们分别讨论每一部分。

项目-30%

简历中提到的项目是你在面试中成功的关键。参加面试的人应该对这些项目有很好的掌握。在解释项目时,确保你很好地解释了整个流程,并强调了你声称已经完成的部分。预期问题如下

  • 你为什么用兰登森林,而不是 SVM?
  • 为什么你认为精度不能进一步提高?
  • 请解释您遇到的一两个实时问题,以及您是如何解决的?
  • 这个模型对商业有什么用处(你应该用美元数量来回答这个问题)?

等等。等等。

一般来说,除了人力资源面试,项目讨论将是所有面试的一部分。一些回合可能只是项目的表面概述,而一些回合可能对项目进行深入讨论。除了接受资深数据科学家的采访,有时你可能需要与非常资深的人进行项目讨论,如董事、分析主管等。对你的期望很简单,你应该亲自动手,而不仅仅是“训练有素”的人,你应该了解数据科学项目如何通过向业务/客户交付价值来工作。

总结:对你的项目有很好的掌控力。

机器学习——20%

有一句名言,大致意思是“你的知识和面试官的知识重叠度越大,你在面试中被选中的几率就越高”。

话虽如此,在我的职业生涯中,我还没有见过任何一位数据科学家研究过所有领域/算法。有人对“自然语言处理”有很好的了解,但在“回归模型”方面做了有限的工作。有人擅长“时间序列预测”,但不擅长“无监督学习技术”。这些都是完全可以接受的场景。你不需要主宰一切。如果你的简历上说你做过《随机森林》,那你应该对随机森林有很好的了解。然而,这里有一些机器学习讨论的通用要点。擅长这些:

  • 线性回归和逻辑回归(深入理解这两种技术、分类与回归、假设、系数含义、β值和截距的商业解释、误差类型、对数似然函数、损失函数、套索和岭回归等)
  • 决策树和随机森林(什么和为什么,偏差方差权衡,修剪,过拟合和欠拟合,模型预测能力与模型解释能力,装袋,提升概念等。)
  • 主成分分析、线性判别分析、监督与非监督学习、变量缩减技术、多重共线性、方差膨胀因子、模型性能测量等。
  • 对 K 近邻、K 均值聚类、推荐引擎、支持向量机、神经网络、朴素贝叶斯等的高级理解。

带走——对重要的技术有高层次的理解,对简历中提到的技术有深入的理解。

统计-20%

非统计背景的人害怕从事数据科学职业的一个原因——是吗??😃

在我看来,在统计部分只会对你的一项技能进行评估——“你知道解决一个数据科学问题需要什么吗”??

统计学本身是一个巨大的知识和研究领域,有很多东西需要了解和理解,但是如果你擅长以下几点,你会被认为足够优秀!

  • 变量:名词性/分类性/序数
  • 取样技术——什么、为什么和什么时候
  • 集中趋势的测量——均值、中值、众数、绞合偏差、方差、百分位数、对盒须图和其他图的理解
  • 正态、泊松、均匀等概率分布及其在数据中的意义
  • 降维——需求和方法
  • 估计技术和假设检验

拿走——如果你是这个领域的新手,我的建议是不要打破一切关于统计的东西。知道需要什么就行了。

编程-10%:

“非编程背景”的人开始他们的数据科学之旅的另一个恐惧的原因。

需要多少编程技能?简单回答“多多益善”。然而,从面试的角度来看,我们将评估你是否能够将你的知识应用到给定的数据科学问题上。要做到这一点,需要编码。它可能不是非常高效、智能、高端的编码,但它应该服务于这个目的。换句话说,你知道统计学,你知道机器学习技术,你面前有数据。当且仅当你知道如何编码,你将苹果应用你的知识给定的数据。关于编码的几个要点:

  • SQL——这必须有技巧——无处可逃
  • 了解数据类型和结构,如变量、常数、字符串、数组、数据帧、数据表、矩阵、列表等。
  • 理解条件语句和循环,如 if else、嵌套 if else、while do while、switch、for loop、break、continue 语句等。
  • R 语言特有的 —安装和加载包、旋转表、聚合、汇总、过滤、合并、rbind、cbind、RDS、R 环境、dplyr、tidyr、caret、data.table、sqldf、ggplot2、googleVis 等包
  • Python 特有的 语言—pandas、NumPy、scikit-learn、matplotlib、seaborn 等包的功能和用法。元组、集合、字典、列表、列表理解、范围函数、可变与不可变、何时使用哪种数据类型、聚合、汇总、过滤、合并、内存管理等。

现在,很少有组织在数据科学面试中进行书面编程测试。它可以是选择题测试或要编写的代码片段。为了通过这一轮,你应该对代码很在行。

拿走——让你的手弄脏编码——没有其他的选择会有很大的帮助。

逻辑思维——10%

无论是数据科学面试还是 java 面试,逻辑思维都是有经验的面试官在讨论中试图触及的问题之一。期望也是直截了当的——“在一个给定的情况下/关于一个给定的问题陈述,你能有多逻辑地思考”。从数据科学的角度来看,它可以细分为以下两个部分:

  • 基于场景的 —基于场景的评估将通过给你一个假想的情况或问题陈述,并检查你的思考过程来进行。举个例子——如果我正在面试一个人 A,我会问他/她类似这样的问题—“我们的一个消费品(CPG)客户 ABC 希望我们建议他们在下一季度增加 5%收入的方法” 你将如何处理这个问题陈述。我希望 A 的回答是 “为了增加收入,他们应该卖得更多,他们能为卖得更多做些什么?他们能做交叉销售/追加销售吗?他们能做联合采矿吗?
  • 谜题 —面试官可以向你抛谜题,检验你的逻辑思维能力。这里提到了一些著名的

带走——不断提高自己的分析思维能力。

行为-5%:

几年前,我有这样的印象,如果你在上面提到的方面做得好,那么你肯定会被录用。然而,我最近的一次经历迫使我也给行为 5%的权重。

我的求职面试经历——在人力资源部将我的资料列入候选名单,并邀请我参加第一轮面试时,她在邮件中给我发了 YouTube 视频链接。在该视频中,该组织的首席执行官谈到了组织价值观、文化和宗旨等。我没有太在意,参加了面试。这是一个“很难破解”的面试,但我设法通过了多轮。贴那个,资深 HR 来讨论,她问我为什么要加入这个组织,对这个组织了解多少?我对这个组织了解不多,因此不能很好地回答。我不知道这将成为一个大问题!招聘 HR 给我打电话,她很不高兴我没有去过她分享过的 you-tube 视频。在进行了一次很好的技术面试后,我必须再进行两轮行为测试,在测试中我必须让他们相信我了解他们的组织、文化和价值观,并且我会融入其中。

从上述经历中学到的是——“了解你要去面试的地方”,并期待类似于“你为什么想加入我们”、“你能适应我们的文化/价值观吗”、“我们做什么工作”、“我们的 CEO/年收入”等问题。

带走——对你将要参加面试的组织进行调查。

简历/CV-5%:

这基本上是“告诉我关于你自己的情况”部分,你应该在简历中浏览一下。没有硬性规定它可以怎样,应该怎样。这又是一个展示你的沟通技巧和额外成就的好机会。尽量涵盖事情的广度,不要在项目或任何领域走得太深,而是给出概况。试着强调你独特的技能、奉献和成就。

举几个例子,在你的专业总结之后,加上这样的句子

  • 我入选了国家级数学奥林匹克第二名
  • 我是州足球队的一员
  • 我在图像编辑软件上的博客有 5 万次阅读

您还可以添加一些有趣的事实,让环境变得不那么酷:):

  • 我害怕……
  • 我爱……
  • 我隐藏的才能是……..
  • 我罪恶的快乐是……

带走——正常地展示自己,保持舒适,因为这通常是讨论的第一个问题。

新生特别提示:

  • 展示你的学习能力——很有可能你会错过一些问题、场景,或者在被问到时你会对一些概念感到困惑。在这些情况下,保持冷静,不要紧张。只要专注于展示一种学习的能力。你可以很简单地说“我没有机会做这件事,如果有机会,我会学着去做”
  • 不要把事情看得太重——有时面试官可能会为了测试你的反应而把你推到不舒服的地方。记住,他或她与你没有任何私人恩怨。这只是对你态度的测试。有些面试官可能很有礼貌,有些可能很难相处。试着和两组人都保持平稳。
  • 学习行业语言— 这是我观察到的 60–70%的大一新生的问题之一。我给他们的建议是努力学习工业语言,你不能粗鲁,现在就忘记你的大学语言。我想分享的一条黄金法则是——“记住名字”。这是我经历过的最神奇的事情之一。假设你是大卫,我打电话给你说“你好”而另一个人打电话给你说“你好大卫”哪个更好听?你有答案了!!它适用于我们所有人。任何时候你接到招聘公司/咨询公司/人力资源部等的电话。,他们会提名字,认真听,马上用。A 先生,你好,我是 ABC 公司的丹尼尔。你的回答应该是“你好丹尼尔”而不是“你好”。这可能听起来很简单,但相信我,它在各个方面都很神奇。做了就明白了。这个概念也适用于电子邮件通信。
  • 带着微笑——我们都希望身边有快乐的环境。好人,有趣的人都喜欢,谁不喜欢微笑呢:)

带走——冷静、沉着、切题、舒适。你将成为雇佣你的组织的一笔财富。 牢记这一点,自信满满。

总结:

感谢您的阅读。我很高兴与你分享我的经验,并祝你一切顺利。我的意图是看到你马上得到一份工作,如果你获得正确的技能并遵循正确的道路,这是可能的。

您还可以在此阅读从零开始成为数据科学家的途径。

请随意评论你对这篇文章的看法,或者你想让我更详细讨论的任何事情。

在 Quora 上关注我,获取关于数据科学的常规答案这里

加入我们的数据科学社区脸书, Twitter , Instagram , LinkedIn

谢谢你

Aman(amanrai77@gmail.com)

多模态回归——超越 L1 和 L2 损失

原文:https://towardsdatascience.com/anchors-and-multi-bin-loss-for-multi-modal-target-regression-647ea1974617?source=collection_archive---------13-----------------------

深度学习最著名的用例是图像分类,目标是训练神经网络从 N 个预定义的可能性中选择一个。例如,经过训练的神经网络可以从许多类别中辨别出图像块中的对象类型(例如,猫)。在这种简单的情况下,softmax 损失函数将为您提供很好的服务。然而,有时我们必须回归一个连续的目标。这就是事情开始变得复杂的地方。

Regression vs Classification (source)

当你面对一个连续的回归目标时,很容易将 L1 或 L2 损失直接应用到原始目标上,看看效果如何。如果一个回归目标是单峰(或者在分布中只有一个明显的峰值,非常像高斯分布),L2 范数应该很有效。然而,如果你的目标是单峰的,你可能会发现 L2 损失产生不良后果。这篇文章旨在讨论回归连续目标的更有原则的方法,特别是在大范围和超越高斯型目标分布的情况下。

Unimodal distribution and beyond

为什么 L2 损失在某些情况下会失败?

从概率的角度来看,L2 损失假设基础目标分布是高斯分布(因此是单峰的)。最小化 L2 损失或均方误差(MSE)与最大化高斯对数似然相同。L2 损耗促使网络最小化所有模式上的损耗,这导致对任何单一模式的估计可能较差。特别是,在图像重建应用中,使用 L2 损失通常会导致图像模糊。这是由于假设噪声是高斯分布的失败造成的。

Failure to use L2 loss to regress a bimodal data distribution

请注意,L1 损失没有更好。L2 损失采用高斯先验,L1 损失采用拉普拉斯先验,这也是一种单峰分布。直观地说,平滑 L1 损失,或称胡伯损失,是 L1 和 L2 损失的组合,也呈现单峰基础分布。

通常,首先可视化回归目标的分布是一个好主意,并考虑除 L2 之外的其他损失函数,它们可以更好地反映和适应目标数据分布。例如,如果您的目标分布是双峰的,一种直观的方法是找到目标属于哪个模式(或“仓”),然后回归模式中心的偏移。

这正是所谓的多面元损失(或混合分类/回归损失,离散/连续损失)所做的。这个损失在 CVPR 2017 论文 使用深度学习和几何 的 3D 包围盒估计中首次提出用于角度回归。原上下文是在单目 3D 车辆检测中回归一个[-π,π]范围内的连续方向角。此后,它被广泛应用于三维物体检测中的汽车方向回归,包括仅使用单目图像的方法(如多级融合、monosr和 FQNet )和使用点云的方法(如锥台点网和 AVOD )。

多仓损失前

由于回归目标的范围很广,以及周期性造成的角度模糊,方位估计可能是回归中最棘手的问题之一。在论文 制作用于视点估计的多任务 CNN(BMVC 2016)为 CNN 渲染:使用用渲染的 3D 模型视图训练的 CNN 在图像中进行视点估计(CVPR 2015) 中,作者总结了几种用于方向预测的方法。这个问题有不同的表述:

  1. 预测 cos(θ)和 sin(θ)
  2. 预测 cos(θ-π/3)、cos(θ)和 cos(θ+π/3)
  3. 利用 softmax 交叉熵损失,直接分类到 n 个离散箱中
  4. 具有加权交叉熵损失的几何结构感知分类(GSA cls)

3 和 4 的主要区别在于,传统的交叉熵只考虑了一个面元(包含地面真相的面元)的预测,而几何感知交叉熵损失考虑了所有面元由地面真相到每个面元中心的距离加权。3 和 4 都只将得分最高的 bin 作为最终预测。

Different ways to orientation prediction

原始多面元损失(用于角度回归)

原多面元损失将目标范围离散化,分成 n 个重叠的面元。对于每个箱,神经网络模型估计输出目标位于第 i 个箱内的置信概率 Ci 和需要应用于箱中心以获得输出目标的剩余项。总多仓损失本质上是分类损失项(通常是 softmax)和位置回归项(通常是 L2 或 L1 或平滑 L1 损失)的加权平均值。

Multi-bin loss = classification loss + regression loss

请注意,在训练和推断过程中存在差异。在训练期间,覆盖地面真实角度的所有箱被强制估计正确的目标。在推断期间,选择具有最大置信度的仓,并且通过将该仓的估计残差应用于该仓的中心来计算最终输出。

这一思想可以推广到角度回归以外的许多其他情况。关于重叠箱的快速说明:这对均匀分布更重要,但对多模态分布不太重要,因为后者的箱边界上的样本要少得多。

车辆尺寸回归

这个想法可以扩展到许多其他应用,如车辆大小回归。FQNet ( 基本思想是首先对训练数据集进行 k-means 聚类,找出维度的 K 个聚类中心,并将这些聚类中心作为 3D 长方体。在训练期间,回归模块分别输出每个 3D 锚点长方体的置信度和偏移量。在推理过程中,最终的回归结果是置信度最高的锚点长方体加上相应的偏移量。

对于车辆尺寸回归,他们似乎没有使用重叠箱,因为维度分布可以很好地聚集到 k 箱中,并且很少样本位于边界上。

箱子宽度选择

如果回归目标中没有清晰的聚类模式,并且目标范围较宽,也建议使用标准差作为 bin 大小,如 GS3D:一种高效的自动驾驶 3D 对象检测框架 (CVPR 2019)所推荐的。据报道,这比直接回归目标要好得多。

改进的多仓损失

3D-RCNN:通过渲染和比较 (CVPR 2018),作者提出了不同的多面元损失。它还将连续的目标范围离散化为条柱,但不是使用 softmax 挑选出唯一正确的条柱,而是使用条柱中心的加权平均值(期望值)作为最终预测,并使用 L1 对其进行正则化。以这种方式,不需要将偏移回归到面元中心。

回想起来,这非常接近 GSA(几何结构感知)分类的公式,在推理性能上有一点扭曲。

对象检测中的锚盒

现在让我们转到一个更大的话题,对象检测中的锚盒。目标检测领域的新手可能会对锚盒的想法感到困惑,锚盒在许多现代目标检测网络架构中很流行,例如更快的 RCNN、RetinaNet 和 YOLOv2。几篇无主播的论文里有几个很好的主播总结我想在这里引用一下(你得对某件事有足够的了解才能排除,嗯?):

Anchor 方法建议将盒子空间(包括位置、比例、长宽比)划分为离散的 bin,并在相应的 bin 中细化对象盒子。(来自黄斑盒,https://arxiv.org/abs/1904.03797)

锚盒设计用于将所有可能的实例盒的连续空间离散化为具有预定义位置、比例和纵横比的有限数量的盒。(来自 https://arxiv.org/abs/1903.00621FSAF)

看待 anchor 的一种方式是,它类似于深度学习时代之前的滑动窗口。DL 中的锚盒只是以卷积方式应用滑动窗口的一种方式。

Sliding window method for face detection in pre-DL era (from one of my favorite blog PyImageSearch)

Anchor boxes in DL is a way to apply the sliding window in a convolutional manner (source)

从另一个角度看,锚箱和多仓亏损背后的哲学极其相似。锚箱和多仓损失都通过对锚(或多仓损失中的“仓”)进行分类并将残差回归到锚/仓来解决非常复杂的多峰回归问题。也许对象检测中的锚箱以某种方式启发了多箱损失的产生。

实际上,锚盒被设计成基于训练数据集来捕捉比例和纵横比(如果你想使用非均匀锚平铺,甚至是空间集中度),正如在 YOLOv2 中仔细解释的那样(见下图)。这非常类似于 FQNet 中多箱损失的车辆规模回归中的 k 均值聚类。

YOLOv2 explains how to select anchor sizes and aspect ratios based on training data

外卖

  1. 视觉化:在盲目应用 L2 规范之前,总是检查目标分布。
  2. 分而治之:将目标范围分成仓(重叠或不重叠),对目标落入哪个仓/锚进行分类,然后对残差进行回归。

PS,我发现的另一个有用的技巧是执行目标标准化以获得目标的零均值和单位方差。虽然标准化通常用在传统机器学习的特征中,并且对于 target 来说不是必需的,但是我发现它很有用,并且如果我们也执行 target 标准化,会使训练更容易。

这个节目的明星是——PYTHON

原文:https://towardsdatascience.com/and-the-star-of-the-show-is-python-51909c894390?source=collection_archive---------29-----------------------

2019 年十月世界的亮点

介绍

又到了一年中的这个时候,最大的开源项目 Github 发布了它的年度报告。GitHub 每年都会对开发者进行调查,并制作一份调查结果报告。

每年都有令人惊讶的消息传来。它揭示了一些新的成长中的技术,热门话题和项目等。

今年无疑是 Python 之年。

今年,Github 社区已经接触了来自世界各地的 4000 多万开发者,并且拥有超过 1 亿个存储库。在这里,我们将看到来自 2019 年十月状态的亮点。

出类拔萃,成为明星

全球团队

为开源项目做出贡献的 GitHub 用户有 20%来自美国,80%来自美国以外。

开源社区在美国以外的地区越来越受欢迎。来自中国的开发人员在克隆和分叉项目上取得了 48%的增长。

这是美国以外前 20 个地区的图表

从各大洲来看,对开源项目的总体贡献是最大的,其中亚洲的贡献最大,来自中国。

下图显示了各大洲对我们的贡献。

互联社区

每个语言生态系统中的前 50 个包都有大量的依赖项目。Javascript 语言的顶级 npm 包有大约 350 万个依赖项目。

Top 10 open source projects with most dependent projects

Tensorflow 是 GitHub 上最受欢迎的项目之一,它展示了这些小项目如何连接在一起构建一个大型软件社区。它拥有超过 25,000 名社区贡献者,在这一年中为 TensorFlow 依赖项做出了贡献。

是时候证明自己了

社区趋势

2019 年,开发人员的工作效率比以往任何时候都高。下图显示了开发人员正在从事的顶级项目。

Octoverse 2019 最引人注目的事实是 Python 第一次超过了 Java ,成为 GitHub 上第二大最受欢迎的语言,基于知识库贡献者。除此之外,Javascript 照常戴着皇冠。

Most Popular Programming Languages on GitHub

像深度学习、机器学习、自然语言处理这样的主题已经变得很流行,它们在知识库中也很流行。

该图显示了数据科学 Jupyter 笔记本和自然语言处理中存储库的增长。

今年我们看到了语言发展的新趋势。该报告向我们展示了增长最快的 10 种编程语言。Dart 正以 532%的惊人速度增长。开发者社区喜欢统计类型语言,比如 Rust、Kotlin 和 Typescript。

包扎

每年来自 GitHub 的见解都有助于开发者分析新趋势和获取信息。今年,我们观察了开源社区是如何由全球开发者构建的,顶级开源项目依赖于数百万个其他项目,python 取代了 java。IT 行业是一个快速增长的行业,将继续向前发展,我们将看到更多的趋势和技术变化。

现在轮到你翻盘了

吴恩达的 Python(异常检测)机器学习课程

原文:https://towardsdatascience.com/andrew-ngs-machine-learning-course-in-python-anomaly-detection-1233d23dba95?source=collection_archive---------1-----------------------

Machine Learning — Andrew Ng

T 这是吴恩达的机器学习课程 python 实现的最后一部分,我很高兴终于完成了这个系列。为了给你们一些视角,我花了一个月的时间将这些代码转换成 python,并为每个作业写了一篇文章。如果你们中的任何人正在犹豫要不要用 Python、R 或 Java 来实现,我强烈建议你们去做。从头开始编写这些算法不仅可以强化所教授的概念,还可以用自己熟悉的语言练习数据科学编程技能。

说了这么多,让我们进入最后一个编程作业

在这部分作业中,我们将使用高斯模型实现异常检测算法,首先检测 2D 数据集中的异常行为,然后检测高维数据集中的异常行为。

加载相关的库和数据集

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmatmat = loadmat("ex8data1.mat")
X = mat["X"]
Xval = mat["Xval"]
yval = mat["yval"]

可视化数据

plt.scatter(X[:,0],X[:,1],marker="x")
plt.xlim(0,30)
plt.ylim(0,30)
plt.xlabel("Latency (ms)")
plt.ylabel("Throughput (mb/s)")

估计高斯模型的参数(均值和方差)

def estimateGaussian(X):
    """
     This function estimates the parameters of a Gaussian distribution using the data in X
    """

    m = X.shape[0]

    #compute mean
    sum_ = np.sum(X,axis=0)
    mu = 1/m *sum_

    # compute variance
    var = 1/m * np.sum((X - mu)**2,axis=0)

    return mu,varmu, sigma2 = estimateGaussian(X)

多元高斯分布是本课程的选修课,并给出了计算概率密度的代码。然而,为了让我继续这个任务,我需要从头开始编写multivariateGaussian 函数。

def multivariateGaussian(X, mu, sigma2):
    """
    Computes the probability density function of the multivariate gaussian distribution.
    """
    k = len(mu)

    sigma2=np.diag(sigma2)
    X = X - mu.T
    p = 1/((2*np.pi)**(k/2)*(np.linalg.det(sigma2)**0.5))* np.exp(-0.5* np.sum(X @ np.linalg.pinv(sigma2) * X,axis=1))
    return pp = multivariateGaussian(X, mu, sigma2)

我们在这里使用的一些有趣的函数来自 numpy 线性代数类。官方文件可以在这里找到。

一旦我们估计了高斯参数并获得了数据的概率密度,我们就可以可视化拟合。

plt.figure(figsize=(8,6))
plt.scatter(X[:,0],X[:,1],marker="x")
X1,X2 = np.meshgrid(np.linspace(0,35,num=70),np.linspace(0,35,num=70))
p2 = multivariateGaussian(np.hstack((X1.flatten()[:,np.newaxis],X2.flatten()[:,np.newaxis])), mu, sigma2)
contour_level = 10**np.array([np.arange(-20,0,3,dtype=np.float)]).T
plt.contour(X1,X2,p2[:,np.newaxis].reshape(X1.shape),contour_level)
plt.xlim(0,35)
plt.ylim(0,35)
plt.xlabel("Latency (ms)")
plt.ylabel("Throughput (mb/s)")

我之前没有解释过创建等高线图的过程,因为大多数都很简单。如果你理解起来有困难,这里的这篇文章可能会有所帮助。简单地说,我们首先在数据区域周围创建一个网格,并计算 Z 轴。plt.contour然后使用 3 个轴(X,Y,Z)创建等高线图。

现在选择一个阈值,将一个示例标记为异常。

def selectThreshold(yval, pval):
    """
    Find the best threshold (epsilon) to use for selecting outliers
    """
    best_epi = 0
    best_F1 = 0

    stepsize = (max(pval) -min(pval))/1000
    epi_range = np.arange(pval.min(),pval.max(),stepsize)
    for epi in epi_range:
        predictions = (pval<epi)[:,np.newaxis]
        tp = np.sum(predictions[yval==1]==1)
        fp = np.sum(predictions[yval==0]==1)
        fn = np.sum(predictions[yval==1]==0)

        # compute precision, recall and F1
        prec = tp/(tp+fp)
        rec = tp/(tp+fn)

        F1 = (2*prec*rec)/(prec+rec)

        if F1 > best_F1:
            best_F1 =F1
            best_epi = epi

    return best_epi, best_F1pval = multivariateGaussian(Xval, mu, sigma2)
epsilon, F1 = selectThreshold(yval, pval)
print("Best epsilon found using cross-validation:",epsilon)
print("Best F1 on Cross Validation Set:",F1)

如果您没有注意到,这里使用 F1 分数而不是准确性,因为数据集是高度不平衡的。为了了解更多关于评估机器学习模型性能的各种方法,这篇文章很好地总结了这个主题。

可视化最佳阈值

plt.figure(figsize=(8,6))# plot the data
plt.scatter(X[:,0],X[:,1],marker="x")# potting of contour
X1,X2 = np.meshgrid(np.linspace(0,35,num=70),np.linspace(0,35,num=70))
p2 = multivariateGaussian(np.hstack((X1.flatten()[:,np.newaxis],X2.flatten()[:,np.newaxis])), mu, sigma2)
contour_level = 10**np.array([np.arange(-20,0,3,dtype=np.float)]).T
plt.contour(X1,X2,p2[:,np.newaxis].reshape(X1.shape),contour_level)# Circling of anomalies
outliers = np.nonzero(p<epsilon)[0]
plt.scatter(X[outliers,0],X[outliers,1],marker ="o",facecolor="none",edgecolor="r",s=70)plt.xlim(0,35)
plt.ylim(0,35)
plt.xlabel("Latency (ms)")
plt.ylabel("Throughput (mb/s)")

对于高维数据集,我们只需遵循与之前完全相同的步骤

mat2 = loadmat("ex8data2.mat")
X2 = mat2["X"]
Xval2 = mat2["Xval"]
yval2 = mat2["yval"]# compute the mean and variance
mu2, sigma2_2 = estimateGaussian(X2)# Training set
p3 = multivariateGaussian(X2, mu2, sigma2_2)# cross-validation set
pval2 = multivariateGaussian(Xval2, mu2, sigma2_2)# Find the best threshold
epsilon2, F1_2 = selectThreshold(yval2, pval2)
print("Best epsilon found using cross-validation:",epsilon2)
print("Best F1 on Cross Validation Set:",F1_2)
print("# Outliers found:",np.sum(p3<epsilon2))

作业的第二部分包括实现一个协作过滤算法来建立一个电影分级推荐系统。

电影分级数据集的加载和可视化

mat3 = loadmat("ex8_movies.mat")
mat4 = loadmat("ex8_movieParams.mat")
Y = mat3["Y"] # 1682 X 943 matrix, containing ratings (1-5) of 1682 movies on 943 user
R = mat3["R"] # 1682 X 943 matrix, where R(i,j) = 1 if and only if user j give rating to movie i
X = mat4["X"] # 1682 X 10 matrix , num_movies X num_features matrix of movie features
Theta = mat4["Theta"] # 943 X 10 matrix, num_users X num_features matrix of user features# Compute average rating 
print("Average rating for movie 1 (Toy Story):",np.sum(Y[0,:]*R[0,:])/np.sum(R[0,:]),"/5")

打印语句将打印:Average rating for movie 1 (Toy Story): 3.8783185840707963 /5

plt.figure(figsize=(8,16))
plt.imshow(Y)
plt.xlabel("Users")
plt.ylabel("Movies")

进入算法本身,我们从计算成本函数和梯度开始

def  cofiCostFunc(params, Y, R, num_users, num_movies, num_features, Lambda):
    """
    Returns the cost and gradient for the collaborative filtering problem
    """

    # Unfold the params
    X = params[:num_movies*num_features].reshape(num_movies,num_features)
    Theta = params[num_movies*num_features:].reshape(num_users,num_features)

    predictions =  X @ Theta.T
    err = (predictions - Y)
    J = 1/2 * np.sum((err**2) * R)

    #compute regularized cost function
    reg_X =  Lambda/2 * np.sum(Theta**2)
    reg_Theta = Lambda/2 *np.sum(X**2)
    reg_J = J + reg_X + reg_Theta

    # Compute gradient
    X_grad = err*R @ Theta
    Theta_grad = (err*R).T @ X
    grad = np.append(X_grad.flatten(),Theta_grad.flatten())

    # Compute regularized gradient
    reg_X_grad = X_grad + Lambda*X
    reg_Theta_grad = Theta_grad + Lambda*Theta
    reg_grad = np.append(reg_X_grad.flatten(),reg_Theta_grad.flatten())

    return J, grad, reg_J, reg_grad

与前面的方法类似,该任务要求我们在单独的步骤中计算成本函数、梯度、正则化成本函数,然后正则化梯度。只要你使用正确的索引,上面的代码块将允许你一步一步地跟随任务。

为了测试我们的成本函数,

# Reduce the data set size to run faster
num_users, num_movies, num_features = 4,5,3
X_test = X[:num_movies,:num_features]
Theta_test= Theta[:num_users,:num_features]
Y_test = Y[:num_movies,:num_users]
R_test = R[:num_movies,:num_users]
params = np.append(X_test.flatten(),Theta_test.flatten())# Evaluate cost function
J, grad = cofiCostFunc(params, Y_test, R_test, num_users, num_movies, num_features, 0)[:2]
print("Cost at loaded parameters:",J)J2, grad2 = cofiCostFunc(params, Y_test, R_test, num_users, num_movies, num_features, 1.5)[2:]
print("Cost at loaded parameters (lambda = 1.5):",J2)

一旦我们得到了我们的成本函数和梯度,我们可以开始训练我们的算法。

加载电影列表

# load movie list
movieList = open("movie_ids.txt","r").read().split("\n")[:-1]# see movie list
np.set_printoptions(threshold=np.nan)
movieList

你可以在这一步输入你自己的电影偏好,但我使用了与作业完全相同的评分来保持一致。

# Initialize my ratings
my_ratings = np.zeros((1682,1))# Create own ratings
my_ratings[0] = 4 
my_ratings[97] = 2
my_ratings[6] = 3
my_ratings[11]= 5
my_ratings[53] = 4
my_ratings[63]= 5
my_ratings[65]= 3
my_ratings[68] = 5
my_ratings[82]= 4
my_ratings[225] = 5
my_ratings[354]= 5print("New user ratings:\n")
for i in range(len(my_ratings)):
    if my_ratings[i]>0:
        print("Rated",int(my_ratings[i]),"for index",movieList[i])

为了在输入到算法中之前准备我们的数据,我们需要标准化评级,设置一些随机的初始参数,并使用优化算法来更新参数。

def normalizeRatings(Y, R):
    """
    normalized Y so that each movie has a rating of 0 on average, and returns the mean rating in Ymean.
    """

    m,n = Y.shape[0], Y.shape[1]
    Ymean = np.zeros((m,1))
    Ynorm = np.zeros((m,n))

    for i in range(m):
        Ymean[i] = np.sum(Y[i,:])/np.count_nonzero(R[i,:])
        Ynorm[i,R[i,:]==1] = Y[i,R[i,:]==1] - Ymean[i]

    return Ynorm, Ymeandef gradientDescent(initial_parameters,Y,R,num_users,num_movies,num_features,alpha,num_iters,Lambda):
    """
    Optimize X and Theta
    """
    # unfold the parameters
    X = initial_parameters[:num_movies*num_features].reshape(num_movies,num_features)
    Theta = initial_parameters[num_movies*num_features:].reshape(num_users,num_features)

    J_history =[]

    for i in range(num_iters):
        params = np.append(X.flatten(),Theta.flatten())
        cost, grad = cofiCostFunc(params, Y, R, num_users, num_movies, num_features, Lambda)[2:]

        # unfold grad
        X_grad = grad[:num_movies*num_features].reshape(num_movies,num_features)
        Theta_grad = grad[num_movies*num_features:].reshape(num_users,num_features)
        X = X - (alpha * X_grad)
        Theta = Theta - (alpha * Theta_grad)
        J_history.append(cost)

    paramsFinal = np.append(X.flatten(),Theta.flatten())
    return paramsFinal , J_history

再次,我选择批量梯度下降作为我的优化算法。在 python 中完成所有编程任务教会我的一件事是,梯度下降很少出错。在这一点上,梯度下降的代码应该是相当熟悉的。

Y = np.hstack((my_ratings,Y))
R =np.hstack((my_ratings!=0,R))# Normalize Ratings
Ynorm, Ymean = normalizeRatings(Y, R)num_users = Y.shape[1]
num_movies = Y.shape[0]
num_features = 10# Set initial Parameters (Theta,X)
X = np.random.randn(num_movies, num_features)
Theta = np.random.randn(num_users, num_features)
initial_parameters = np.append(X.flatten(),Theta.flatten())
Lambda = 10# Optimize parameters using Gradient Descent
paramsFinal, J_history = gradientDescent(initial_parameters,Y,R,num_users,num_movies,num_features,0.001,400,Lambda)

绘制成本函数以确保梯度下降有效

plt.plot(J_history)
plt.xlabel("Iteration")
plt.ylabel("$J(\Theta)$")
plt.title("Cost function using Gradient Descent")

对你没有评级的电影进行预测

# unfold paramaters
X = paramsFinal[:num_movies*num_features].reshape(num_movies,num_features)
Theta = paramsFinal[num_movies*num_features:].reshape(num_users,num_features)# Predict rating
p = X @ Theta.T
my_predictions = p[:,0][:,np.newaxis] + Ymeanimport pandas as pd
df = pd.DataFrame(np.hstack((my_predictions,np.array(movieList)[:,np.newaxis])))
df.sort_values(by=[0],ascending=False,inplace=True)
df.reset_index(drop=True,inplace=True)print("Top recommendations for you:\n")
for i in range(10):
    print("Predicting rating",round(float(df[0][i]),1)," for index",df[1][i])

最后,我结束了吴恩达的 Python 机器学习课程。我希望这对你和我写这篇文章一样有益,我感谢你们所有人的支持。

Jupyter 笔记本会上传到我的 GitHub 上(https://GitHub . com/Ben lau 93/Machine-Learning-by-Andrew-Ng-in-Python)。

对于本系列中的其他 python 实现,

  • 线性回归
  • 逻辑回归
  • 正则化逻辑回归
  • 神经网络
  • 支持向量机
  • 无监督学习

感谢您的阅读。

吴恩达的 Python (Kmeans-Clustering,PCA)机器学习课程

原文:https://towardsdatascience.com/andrew-ngs-machine-learning-course-in-python-kmeans-clustering-pca-b7ba6fafa74?source=collection_archive---------12-----------------------

Machine Learning — Andrew Ng

本系列的倒数第二部分,我们来看看由无标签数据组成的无监督学习算法。让我们直接进入作业,因为我们今天要学习两个算法。

K-意思是聚类是一种聚类分析技术,允许将数据分组到称为聚类的组中。因为没有为每个训练数据提供标签,所以通过数据彼此的相似性来确定聚类。

我们将从实现 K-means 算法开始。由于 K-means 是一个迭代过程,它将训练样本分配给它们最近的质心,然后重新计算质心,我们需要两个主要函数来完成这一任务。

import numpy as np
import matplotlib.pyplot as plt
from scipy.io import loadmatmat = loadmat("ex7data2.mat")
X = mat["X"]

findClosestCentroids通过评估训练样本与每个质心之间的距离来找到最近的质心,并将质心分配给具有最小距离的训练样本。

def findClosestCentroids(X, centroids):
    """
    Returns the closest centroids in idx for a dataset X where each row is a single example.
    """
    K = centroids.shape[0]
    idx = np.zeros((X.shape[0],1))
    temp = np.zeros((centroids.shape[0],1))

    for i in range(X.shape[0]):
        for j in range(K):
            dist = X[i,:] - centroids[j,:]
            length = np.sum(dist**2)
            temp[j] = length
        idx[i] = np.argmin(temp)+1
    return idx# Select an initial set of centroids
K = 3
initial_centroids = np.array([[3,3],[6,2],[8,5]])
idx = findClosestCentroids(X, initial_centroids)
print("Closest centroids for the first 3 examples:\n",idx[0:3])

np.argmin找出距离最小的指标,赋给训练样本。这里使用+1 从 1 而不是 0 开始对质心进行编号。

print 语句将打印:

前三个例子的最近质心:
[[1。】
【3。】
【2。]]

为了计算分配后的质心平均值,我们将分配给特定质心的训练样本相加,然后除以每个质心中的样本数。

def computeCentroids(X, idx, K):
    """
    returns the new centroids by computing the means of the data points assigned to each centroid.
    """
    m, n = X.shape[0],X.shape[1]
    centroids = np.zeros((K,n))
    count = np.zeros((K,1))

    for i in range(m):
        index = int((idx[i]-1)[0])
        centroids[index,:]+=X[i,:]
        count[index]+=1

    return centroids/countcentroids = computeCentroids(X, idx, K)
print("Centroids computed after initial finding of closest centroids:\n", centroids)

print 语句将打印:

在最初找到最近的质心之后计算的质心:
[[2.42830111 3.15792418]
[5.81350331 2.63365645]
[7.11938687 3.6166844]]

现在,为了可视化整个过程,我为算法的每次迭代创建了一个子图,以监控质心的移动和训练示例的分配。

def plotKmeans(X, centroids, idx, K, num_iters):
    """
    plots the data points with colors assigned to each centroid
    """
    m,n = X.shape[0],X.shape[1]

    fig, ax = plt.subplots(nrows=num_iters,ncols=1,figsize=(6,36))

    for i in range(num_iters):    
        # Visualisation of data
        color = "rgb"
        for k in range(1,K+1):
            grp = (idx==k).reshape(m,1)
            ax[i].scatter(X[grp[:,0],0],X[grp[:,0],1],c=color[k-1],s=15)# visualize the new centroids
        ax[i].scatter(centroids[:,0],centroids[:,1],s=120,marker="x",c="black",linewidth=3)
        title = "Iteration Number " + str(i)
        ax[i].set_title(title)

        # Compute the centroids mean
        centroids = computeCentroids(X, idx, K)

        # assign each training example to the nearest centroid
        idx = findClosestCentroids(X, centroids)

    plt.tight_layout()m,n = X.shape[0],X.shape[1]
plotKmeans(X, initial_centroids,idx, K,10)

因为 K-means 算法并不总是给出最优解,所以随机初始化很重要。

def kMeansInitCentroids(X, K):
    """
    This function initializes K centroids that are to beused in K-Means on the dataset X
    """
    m,n = X.shape[0], X.shape[1]
    centroids = np.zeros((K,n))

    for i in range(K):
        centroids[i] = X[np.random.randint(0,m+1),:]

    return centroidscentroids = kMeansInitCentroids(X, K)
idx = findClosestCentroids(X, centroids)
plotKmeans(X, centroids,idx, K,10)

上面的代码将再次运行可视化,但会进行随机初始化。您可以多次运行代码来查看随机初始质心的影响。

现在我们完成了算法的编码,我们可以开始用其他数据集实现它了。在本练习中,我们将使用该算法选择 16 个聚类来代表图像(从数千种颜色中选择)以压缩图像。

mat2 = loadmat("bird_small.mat")
A = mat2["A"]# preprocess and reshape the image
X2 = (A/255).reshape(128*128,3)def runKmeans(X, initial_centroids,num_iters,K):

    idx = findClosestCentroids(X, initial_centroids)

    for i in range(num_iters):

        # Compute the centroids mean
        centroids = computeCentroids(X, idx, K)# assign each training example to the nearest centroid
        idx = findClosestCentroids(X, initial_centroids)return centroids, idx

现在对数据集运行 k-means 算法

K2 = 16
num_iters = 10
initial_centroids2 = kMeansInitCentroids(X2, K2)
centroids2, idx2 = runKmeans(X2, initial_centroids2, num_iters,K2)m2,n2 = X.shape[0],X.shape[1]
X2_recovered = X2.copy()
for i in range(1,K2+1):
    X2_recovered[(idx2==i).ravel(),:] = centroids2[i-1]# Reshape the recovered image into proper dimensions
X2_recovered = X2_recovered.reshape(128,128,3)# Display the image
import matplotlib.image as mpimg
fig, ax = plt.subplots(1,2)
ax[0].imshow(X2.reshape(128,128,3))
ax[1].imshow(X2_recovered)

这是原始图像和只有 16 种颜色的压缩图像的并排比较。

Machine Learning — Andrew Ng

作业的下一部分利用 2D 数据集来获得对主成分分析(PCA)过程的直觉,然后在人脸图像数据集上进行 PCA 以执行降维。

加载并可视化 2D 数据集

mat3 = loadmat("ex7data1.mat")
X3 = mat3["X"]plt.scatter(X3[:,0],X3[:,1],marker="o",facecolors="none",edgecolors="b")

为了实现 PCA 算法,PCA 还包括两个计算步骤,我们将对其中一个步骤进行编码以计算协方差矩阵,并对另一个步骤使用 numpy 库以获得特征向量。

在此之前,需要进行特征归一化,以确保数据在同一范围内。

def featureNormalize(X):
    """
    Returns a normalized version of X where the mean value of each feature is 0 and the standard deviation is 1.
    """
    mu = np.mean(X,axis=0)
    sigma = np.std(X,axis=0)

    X_norm = (X - mu)/sigma

    return X_norm, mu , sigmadef pca(X):
    """
    Computes eigenvectors of the covariance matrix of X
    """
    m,n = X.shape[0], X.shape[1]

    sigma = 1/m * X.T @ X

    U,S,V = svd(sigma)

    return U,S,V

np.linalg.svd类似于 matlab 中的svd函数,返回相同的 U、S、V 矩阵。官方文档可以在这里找到。

from numpy.linalg import svd
X_norm,mu,std = featureNormalize(X3)
U,S = pca(X_norm)[:2]plt.scatter(X3[:,0],X3[:,1],marker="o",facecolors="none",edgecolors="b")
plt.plot([mu[0],(mu+1.5*S[0]*U[:,0].T)[0]],[mu[1],(mu+1.5*S[0]*U[:,0].T)[1]],color="black",linewidth=3)
plt.plot([mu[0],(mu+1.5*S[1]*U[:,1].T)[0]],[mu[1],(mu+1.5*S[1]*U[:,1].T)[1]],color="black",linewidth=3)
plt.xlim(-1,7)
plt.ylim(2,8)

上面的代码块在数据集上实现 PCA,并可视化数据上的特征向量。我发现维基百科为大多数学习算法提供了很好的信息来源,如果你想更深入地研究算法,绝对值得一看。

print("Top eigenvector U(:,1) =:",U[:,0])`

打印报表打印:Top eigenvector U(:,1) =: [-0.70710678 -0.70710678]

为了减少数据集的维度,我们将数据投影到找到的主成分(特征向量)上。

def projectData(X, U, K):
    """
    Computes the reduced data representation when projecting only on to the top k eigenvectors
    """
    m = X.shape[0]
    U_reduced = U[:,:K]
    Z = np.zeros((m,K))

    for i in range(m):
        for j in range(K):
            Z[i,j] = X[i,:] @ U_reduced[:,j]

    return Z# Project the data onto K=1 dimension
K=1
Z = projectData(X_norm, U, K)
print("Projection of the first example:",Z[0][0])

打印语句将打印:Projection of the first example: 1.4963126084578515

也可以通过将数据投影回原始维度空间来近似重构数据。

def recoverData(Z, U, K):
    """
    Recovers an approximation of the original data when using the projected data
    """
    m,n = Z.shape[0],U.shape[0]
    X_rec = np.zeros((m,n))
    U_reduced = U[:,:K]

    for i in range(m):
        X_rec[i,:] = Z[i,:] @ U_reduced.T

    return X_recX_rec  = recoverData(Z, U, K)
print("Approximation of the first example:",X_rec[0,:])

打印语句将打印:Approximation of the first example: [-1.05805279 -1.05805279]

为了可视化整个过程,

plt.scatter(X_norm[:,0],X_norm[:,1],marker="o",label="Original",facecolors="none",edgecolors="b",s=15)
plt.scatter(X_rec[:,0],X_rec[:,1],marker="o",label="Approximation",facecolors="none",edgecolors="r",s=15)
plt.title("The Normalized and Projected Data after PCA")
plt.legend()

最后,我们转向更复杂的数据集——人脸图像数据集。为了加载和可视化数据,

mat4 = loadmat("ex7faces.mat")
X4 = mat4["X"]fig, ax = plt.subplots(nrows=10,ncols=10,figsize=(8,8))
for i in range(0,100,10):
    for j in range(10):
        ax[int(i/10),j].imshow(X4[i+j,:].reshape(32,32,order="F"),cmap="gray")
        ax[int(i/10),j].axis("off")

这些图像包含 32 X 32 像素的灰度,导致 1,024 个特征的维度,我们的任务是将维度减少到大约 100 个最能描述我们数据的主成分。

X_norm2 = featureNormalize(X4)[0]# Run PCA
U2 =pca(X_norm2)[0]#Visualize the top 36 eigenvectors found
U_reduced = U2[:,:36].T
fig2, ax2 = plt.subplots(6,6,figsize=(8,8))
for i in range(0,36,6):
    for j in range(6):
        ax2[int(i/6),j].imshow(U_reduced[i+j,:].reshape(32,32,order="F"),cmap="gray")
        ax2[int(i/6),j].axis("off")

上面是描述数据集中最大变化的 36 个主成分的可视化。

接下来,我们将数据投射到前 100 个主成分上,有效地将维度降低到 100,恢复数据并尝试理解在维度降低过程中丢失了什么。

K2 = 100
Z2 = projectData(X_norm2, U2, K2)
print("The projected data Z has a size of:",Z2.shape)# Data reconstruction
X_rec2  = recoverData(Z2, U2, K2)# Visualize the reconstructed data
fig3, ax3 = plt.subplots(10,10,figsize=(8,8))
for i in range(0,100,10):
    for j in range(10):
        ax3[int(i/10),j].imshow(X_rec2[i+j,:].reshape(32,32,order="F"),cmap="gray")
        ax3[int(i/10),j].axis("off")

这是无监督学习的终结。请期待该系列的最后一篇文章。Jupyter 笔记本会上传到我的 GitHub 上(https://GitHub . com/Ben lau 93/Machine-Learning-by-Andrew-Ng-in-Python)。

对于本系列中的其他 python 实现,

  • 线性回归
  • 逻辑回归
  • 正则化逻辑回归
  • 神经网络
  • 支持向量机
  • 异常检测

感谢您的阅读。

吴恩达的 Python(支持向量机)机器学习教程

原文:https://towardsdatascience.com/andrew-ngs-machine-learning-course-in-python-support-vector-machines-435fc34b7bf9?source=collection_archive---------11-----------------------

Machine Learning — Andrew Ng

继续这个系列,我们将继续学习编程作业 6 的支持向量机。如果你注意到了,我没有写作业 5,因为大多数任务只需要绘制和解释学习曲线。不过你还是可以在我的 GitHub 里找到代码,网址是https://GitHub . com/Ben lau 93/Machine-Learning-by-Andrew-Ng-in-Python/tree/master/Bias _ Vs _ Variance。

T4:这个作业有两个部分。首先,我们将在几个 2D 数据集上实现支持向量机(SVM ),以直观地了解算法及其工作原理。接下来,我们将在电子邮件数据集上使用 SVM 来尝试对垃圾邮件进行分类。

为了加载数据集,使用来自 scipy.io 的 loadmat 来打开 mat 文件

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.io import loadmatmat = loadmat("ex6data1.mat")
X = mat["X"]
y = mat["y"]

数据集的绘图

m,n = X.shape[0],X.shape[1]
pos,neg= (y==1).reshape(m,1), (y==0).reshape(m,1)
plt.scatter(X[pos[:,0],0],X[pos[:,0],1],c="r",marker="+",s=50)
plt.scatter(X[neg[:,0],0],X[neg[:,0],1],c="y",marker="o",s=50)

我们从一个简单的数据集开始,它在训练示例之间有一个清晰的线性边界。

正如讲座中所建议的,我们尽量不从头开始编写 SVM,而是利用高度优化的库,如 sklearn 来完成这项任务。官方文档可以在这里找到。

from sklearn.svm import SVC
classifier = SVC(kernel="linear")
classifier.fit(X,np.ravel(y))

由于这是一个线性分类问题,我们将不会为这个任务使用任何内核。这相当于在 SVC 中使用线性核(注意 SVC 的默认核设置是“rbf”,代表径向基函数)。这里的ravel()函数返回一个大小为(m)的数组,这是 SVC 所需要的。

plt.figure(figsize=(8,6))
plt.scatter(X[pos[:,0],0],X[pos[:,0],1],c="r",marker="+",s=50)
plt.scatter(X[neg[:,0],0],X[neg[:,0],1],c="y",marker="o",s=50)# plotting the decision boundary
X_1,X_2 = np.meshgrid(np.linspace(X[:,0].min(),X[:,1].max(),num=100),np.linspace(X[:,1].min(),X[:,1].max(),num=100))
plt.contour(X_1,X_2,classifier.predict(np.array([X_1.ravel(),X_2.ravel()]).T).reshape(X_1.shape),1,colors="b")
plt.xlim(0,4.5)
plt.ylim(1.5,5)

C=1, kernel = “linear”

在默认设置为 C = 1.0(记住 C = 1/λ)的情况下,这就是我们得到的决策边界。

# Test C = 100
classifier2 = SVC(C=100,kernel="linear")
classifier2.fit(X,np.ravel(y))

plt.figure(figsize=(8,6))
plt.scatter(X[pos[:,0],0],X[pos[:,0],1],c="r",marker="+",s=50)
plt.scatter(X[neg[:,0],0],X[neg[:,0],1],c="y",marker="o",s=50)# plotting the decision boundary
X_3,X_4 = np.meshgrid(np.linspace(X[:,0].min(),X[:,1].max(),num=100),np.linspace(X[:,1].min(),X[:,1].max(),num=100))
plt.contour(X_3,X_4,classifier2.predict(np.array([X_3.ravel(),X_4.ravel()]).T).reshape(X_3.shape),1,colors="b")
plt.xlim(0,4.5)
plt.ylim(1.5,5)

C= 100, kernel =”linear”

更改 C=100,给出一个超过训练示例的决策边界。

接下来,我们将看一个不能线性分离的数据集。这就是内核发挥作用的地方,为我们提供非线性分类器的功能。对于那些理解内核概念有困难的人来说,我找到的这篇文章给出了一个很好的关于内核的直觉和一些数学解释。对于这部分作业,我们需要完成函数gaussianKernel来帮助实现高斯核的 SVM。我将跳过这一步,因为 SVC 包含它自己的径向基函数(rbf)形式的高斯核实现。这里的是维基百科的页面,上面有 rbf 的方程,正如你看到的,它与课程中的高斯核函数相同。

示例数据集 2 的加载和绘图

mat2 = loadmat("ex6data2.mat")
X2 = mat2["X"]
y2 = mat2["y"]m2,n2 = X2.shape[0],X2.shape[1]
pos2,neg2= (y2==1).reshape(m2,1), (y2==0).reshape(m2,1)
plt.figure(figsize=(8,6))
plt.scatter(X2[pos2[:,0],0],X2[pos2[:,0],1],c="r",marker="+")
plt.scatter(X2[neg2[:,0],0],X2[neg2[:,0],1],c="y",marker="o")
plt.xlim(0,1)
plt.ylim(0.4,1)

用高斯核实现 SVM

classifier3 = SVC(kernel="rbf",gamma=30)
classifier3.fit(X2,y2.ravel())

对于径向基函数核的 SVM 的参数,它使用 gamma 代替 sigma。参数文档可以在这里找到。我发现 gamma 类似于 1/σ,但不完全是,我希望一些领域专家能给我解释这个 gamma 项的见解。至于这个数据集,我发现 gamma 值为 30 表示与作业中的优化参数最相似(课程中 sigma 为 0.1)。

plt.figure(figsize=(8,6))
plt.scatter(X2[pos2[:,0],0],X2[pos2[:,0],1],c="r",marker="+")
plt.scatter(X2[neg2[:,0],0],X2[neg2[:,0],1],c="y",marker="o")# plotting the decision boundary
X_5,X_6 = np.meshgrid(np.linspace(X2[:,0].min(),X2[:,1].max(),num=100),np.linspace(X2[:,1].min(),X2[:,1].max(),num=100))
plt.contour(X_5,X_6,classifier3.predict(np.array([X_5.ravel(),X_6.ravel()]).T).reshape(X_5.shape),1,colors="b")
plt.xlim(0,1)
plt.ylim(0.4,1)

C = 1, gamma = 30, kernel = “rbf”

对于本部分的最后一个数据集,我们执行一个简单的超参数调整,以确定要使用的最佳 C 值和 gamma 值。

示例数据集 3 的加载和绘图

mat3 = loadmat("ex6data3.mat")
X3 = mat3["X"]
y3 = mat3["y"]
Xval = mat3["Xval"]
yval = mat3["yval"]m3,n3 = X3.shape[0],X3.shape[1]
pos3,neg3= (y3==1).reshape(m3,1), (y3==0).reshape(m3,1)
plt.figure(figsize=(8,6))
plt.scatter(X3[pos3[:,0],0],X3[pos3[:,0],1],c="r",marker="+",s=50)
plt.scatter(X3[neg3[:,0],0],X3[neg3[:,0],1],c="y",marker="o",s=50)

def dataset3Params(X, y, Xval, yval,vals):
    """
    Returns your choice of C and sigma. You should complete this function to return the optimal C and 
    sigma based on a cross-validation set.
    """
    acc = 0
    best_c=0
    best_gamma=0
    for i in vals:
        C= i
        for j in vals:
            gamma = 1/j
            classifier = SVC(C=C,gamma=gamma)
            classifier.fit(X,y)
            prediction = classifier.predict(Xval)
            score = classifier.score(Xval,yval)
            if score>acc:
                acc =score
                best_c =C
                best_gamma=gamma
    return best_c, best_gamma

dataset3Params遍历函数中给出的vals列表,将 C 设置为 val,将 gamma 设置为 1/val。使用每个参数组合构建 SVC 模型,并计算验证集的准确度。基于精度,选择最佳模型,并返回相应的 C 和 gamma 值。

vals = [0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30]
C, gamma = dataset3Params(X3, y3.ravel(), Xval, yval.ravel(),vals)
classifier4 = SVC(C=C,gamma=gamma)
classifier4.fit(X3,y3.ravel())

plt.figure(figsize=(8,6))
plt.scatter(X3[pos3[:,0],0],X3[pos3[:,0],1],c="r",marker="+",s=50)
plt.scatter(X3[neg3[:,0],0],X3[neg3[:,0],1],c="y",marker="o",s=50)# plotting the decision boundary
X_7,X_8 = np.meshgrid(np.linspace(X3[:,0].min(),X3[:,1].max(),num=100),np.linspace(X3[:,1].min(),X3[:,1].max(),num=100))
plt.contour(X_7,X_8,classifier4.predict(np.array([X_7.ravel(),X_8.ravel()]).T).reshape(X_7.shape),1,colors="b")
plt.xlim(-0.6,0.3)
plt.ylim(-0.7,0.5)

C = 0.3, gamma = 100, kernel =”rbf”

C 的最佳值是 0.3,γ的最佳值是 100,这导致了与分配相似的决策边界。

继续垃圾邮件分类。这个问题是独特的,因为它更侧重于数据预处理,而不是实际的建模过程。电子邮件需要以一种可以用作模型输入的方式进行处理。一种方法是根据常用词汇列表获取电子邮件中所有单词的索引。

加载数据

import re
from nltk.stem import PorterStemmerfile_contents = open("emailSample1.txt","r").read()
vocabList = open("vocab.txt","r").read()

Content of the email

给出了词汇列表及其相应的索引,我将该列表存储为字典,以词汇作为键,索引作为值。你也许可以用另一种方式来做,但是我想让访问词汇更容易(比如用 if keys in dict)

vocabList=vocabList.split("\n")[:-1]vocabList_d={}
for ea in vocabList:
    value,key = ea.split("\t")[:]
    vocabList_d[key] = value

至于邮件的预处理,作业中为我们概述了几个步骤。

def processEmail(email_contents,vocabList_d):
    """
    Preprocesses the body of an email and returns a list of indices of the words contained in the email. 
    """
    # Lower case
    email_contents = email_contents.lower()

    # Handle numbers
    email_contents = re.sub("[0-9]+","number",email_contents)

    # Handle URLS
    email_contents = re.sub("[http|https]://[^\s]*","httpaddr",email_contents)

    # Handle Email Addresses
    email_contents = re.sub("[^\s]+@[^\s]+","emailaddr",email_contents)

    # Handle $ sign
    email_contents = re.sub("[$]+","dollar",email_contents)

    # Strip all special characters
    specialChar = ["<","[","^",">","+","?","!","'",".",",",":"]
    for char in specialChar:
        email_contents = email_contents.replace(str(char),"")
    email_contents = email_contents.replace("\n"," ")    

    # Stem the word
    ps = PorterStemmer()
    email_contents = [ps.stem(token) for token in email_contents.split(" ")]
    email_contents= " ".join(email_contents)

    # Process the email and return word_indices

    word_indices=[]

    for char in email_contents.split():
        if len(char) >1 and char in vocabList_d:
            word_indices.append(int(vocabList_d[char]))

    return word_indicesword_indices= processEmail(file_contents,vocabList_d)

正则表达式的使用在这里非常方便,python 大师的这个教程可以帮助你开始 re。这里另一个有用的库是 nlkt,其中的PorterStemmer() 函数有助于词干化。另一个好的教程是 pythonprogramming.net 的。

在得到单词的索引后,我们需要将索引转换成一个特征向量。

def emailFeatures(word_indices, vocabList_d):
    """
    Takes in a word_indices vector and  produces a feature vector from the word indices. 
    """
    n = len(vocabList_d)

    features = np.zeros((n,1))

    for i in word_indices:
        features[i] =1

    return featuresfeatures = emailFeatures(word_indices,vocabList_d)
print("Length of feature vector: ",len(features))
print("Number of non-zero entries: ",np.sum(features))

打印语句将打印:Length of feature vector: 1899Number of non-zero entries: 43.0。这与赋值略有不同,因为在赋值中,you’re被捕获为“你”和“re ”,而我的代码将它识别为“你的”,导致更少的非零条目。

训练 SVM 就像将特征作为输入传递一样简单。然而,这只是一个训练示例,我们需要更多的训练数据来训练分类器。

spam_mat = loadmat("spamTrain.mat")
X_train =spam_mat["X"]
y_train = spam_mat["y"]

训练示例在spamTrain.mat中给出,用于训练我们的分类器,而测试示例在spamTest.mat中给出,用于确定我们的模型可推广性。

C =0.1
spam_svc = SVC(C=0.1,kernel ="linear")
spam_svc.fit(X_train,y_train.ravel())
print("Training Accuracy:",(spam_svc.score(X_train,y_train.ravel()))*100,"%")

打印语句将打印:Training Accuracy: 99.825 %

spam_mat_test = loadmat("spamTest.mat")
X_test = spam_mat_test["Xtest"]
y_test =spam_mat_test["ytest"]spam_svc.predict(X_test)
print("Test Accuracy:",(spam_svc.score(X_test,y_test.ravel()))*100,"%")

打印语句将打印: Test Accuracy: 98.9 %

为了更好地理解我们的模型,我们可以查看每个单词的权重,并找出最能预测垃圾邮件的单词。

weights = spam_svc.coef_[0]
weights_col = np.hstack((np.arange(1,1900).reshape(1899,1),weights.reshape(1899,1)))
df = pd.DataFrame(weights_col)df.sort_values(by=[1],ascending = False,inplace=True)predictors = []
idx=[]
for i in df[0][:15]:
    for keys, values in vocabList_d.items():
        if str(int(i)) == values:
            predictors.append(keys)
            idx.append(int(values))print("Top predictors of spam:")for _ in range(15):
    print(predictors[_],"\t\t",round(df[1][idx[_]-1],6))

支持向量机就是这样!jupyter 笔记本会上传到我的 GitHub 上(https://GitHub . com/Ben lau 93/Machine-Learning-by-Andrew-Ng-in-Python)。

对于本系列中的其他 python 实现,

  • 线性回归
  • 逻辑回归
  • 正则化逻辑回归
  • 神经网络
  • 无监督学习
  • 异常检测

感谢您的阅读。

安卓智能手机使用分析,以减少手机成瘾

原文:https://towardsdatascience.com/android-smartphone-usage-analysis-in-r-to-reduce-phone-addiction-135bd0084e41?source=collection_archive---------16-----------------------

使用您的数据科学技能来改善您的日常生活会有多有趣?因此,我决定利用谷歌让我们下载的数据,开始挖掘我的 Android 手机应用程序的使用情况。我张贴这篇文章的原因是为了让其他人反省他们的用法并了解它。因此,如果有人想复制我的结果,我将在下面的步骤中解释如何下载数据。

如何下载您的 Android 手机使用数据:

  • 进入你的谷歌账户(使用你在安卓手机上用过的 Gmail id)——如果你已经登录,跳过这一步。
  • 去谷歌外卖
  • 点击选择无按钮,向下滚动查看我的活动
  • 选择我的活动(启用灰色/蓝色按钮)并单击向下箭头选择 JSON 格式,然后单击下一步(最底部的按钮)
  • 在下一个屏幕中,您可以选择您喜欢的下载方法和文件格式,然后单击 Create Archive。

一旦你的数据准备好下载,你会被通知下载。下载的文件将是一个压缩文件(最像 Zip —基于您在最后一个屏幕中的选择)。因此,解压缩它并保留 JSON 文件,以便我们继续进行下一步。

开始分析

使用的包

我们将使用下面的包进行分析。

library(jsonlite)
library(tidyverse)
library(lubridate)
library(ggrepel)
library(viridis)
library(gganimate)
library(cowplot)
library(ggthemes)

如果你还没有得到任何上述软件包,所有这些都可以在克兰。所以,使用install.packages()来安装缺失的包。

加载数据

我们有一个 JSON 输入文件,最好用 Dataframe 进行分析(因为它很适合 tidyverse)。但是这种数据处理在jsonlite的 omJSON()的帮助下简直易如反掌

接受 JSON 文件并输出扁平数据帧的函数。

me <- jsonlite::fromJSON("MyActivity.json")

有了上面的代码,我们就可以开始数据预处理了。

数据预处理

我们在分析中会用到的一列,时间

以字符串形式出现,其中包含数据和时间。但是对于我们来说,将时间作为时间处理—它必须是日期-时间格式,所以我们将使用函数 parse_date_time()将字符串转换为日期-时间,并使用 withtz()

更改时区。因为我住在印度,所以我把它转换成了印度标准时间。请使用您合适的时区进行转换。

# converting date-time in string to date-time format along with time-zone conversion
me$time_ist <- with_tz(parse_date_time(me$time),"Asia/Calcutta") 
# remove incomplete years and irrelevant years too - Kept 2019 to see just January if required
me <- filter(me, year(time_ist) %in% c(2017,2018,2019))

正如你在上面的代码中看到的,我们还过滤了我们的数据,只包括 2017 年、2018 年和 2019 年。这只是为了避免部分数据。尽管 2019 年也是部分数据,但我决定将其包含在主要数据中,以比较我在这三年中的应用。至此,我们已经做好了数据预处理,让我们开始分析。

数据注释

这里必须指出的一点是,这种活动数据包括您打开的应用程序和通知中显示的应用程序的所有内容,因此我们进一步假设每个通知也是我们交互的一部分(或者至少在我的情况下,每次弹出通知时,我都会检查它)。

样本/头部数据

# Sample
tibble::tibble(head(me))
*# A tibble: 6 x 1
  `head(me)`$header  $title   $titleUrl     $time  $products $details $time_ist          

1 OnePlus Launcher   Used On… https://play… 2019-…     2019-02-12 12:34:01
2 صلاتك Salatuk (Pr… Used صل… https://play… 2019-…     2019-02-12 12:34:01
3 Google Chrome: Fa… Used Go… https://play… 2019-…     2019-02-12 12:19:23
4 Firefox Browser f… Used Fi… https://play… 2019-…     2019-02-12 12:18:38
5 Hangouts           Used Ha… https://play… 2019-…     2019-02-12 12:18:15
6 Gmail              Used Gm… https://play… 2019-…     2019-02-12 12:17:50*

热门应用—每年

本节中的代码将绘制三个不同年份的三个不同的热门应用程序使用图,并最终将它们缝合在一起。

# Top apps
me_count <- me %>% 
  group_by(year = year(time_ist),header) %>% 
  count() %>% 
  arrange(desc(n)) %>% 
  ungroup() %>% 
  group_by(year) %>% 
  top_n(20,n) #%>% #View() 
#mutate(header = fct_reorder(header,n)) %>% me_count %>%  
  filter(year %in% "2017") %>% 
  ggplot(aes(fct_reorder(header,n),n, label = n)) +     
  geom_bar(aes(fill = n),stat = "identity") +
  #scale_y_log10() +
  coord_flip() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1,size = 8))  +
  scale_fill_viridis() +
  theme_minimal() +
  theme(legend.position="none") +
  labs(
    title = "Most used 20 Apps",
    subtitle = "2017",
    x = "App name"
  ) -> y1me_count %>%  
  filter(year %in% "2018") %>% 
  ggplot(aes(fct_reorder(header,n),n, label = n)) +  
  geom_bar(aes(fill = n),stat = "identity") +
  #scale_y_log10() +
  coord_flip() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1,size = 8))  +
  scale_fill_viridis() +
    theme_minimal() +
  theme(legend.position="none") +
  labs(
    subtitle = "2018",
    x = "App name"
  ) -> y2me_count %>%  
  filter(year %in% "2019") %>% 
  ggplot(aes(fct_reorder(header,n),n, label = n)) +  
  geom_bar(aes(fill = n),stat = "identity") +
  #scale_y_log10() +
  coord_flip() +
  theme(axis.text.y = element_text(angle = 0, hjust = 1,size = 8))  +
  scale_fill_viridis() +
  theme_minimal() +
  theme(legend.position="none") +
  labs(
    subtitle = "2019",
    x = "App name"
  ) -> y3
cowplot::plot_grid(y1,y2,y3, ncol = 3, scale = 0.7, vjust = 0, label_size = 8)

给出了这个图:

这张图清楚地告诉我,随着时间的推移,我的应用程序使用模式是如何变化或发展的。这也意味着我的手机从 HTC One(带有 Sense Launcher)换成了我最近的 Oneplus(带有 Oneplus Launcher)。你也可以注意到,我已经从 Whatsapp 转移到了 Signal messenger。

总体每日使用趋势

# Overall Daily usage trendme %&#x3E;%
filter(!str_detect(header,&#x22;com.&#x22;)) %&#x3E;%
filter(as.Date(time_ist) &#x3E;= as.Date(&#x22;2017-01-01&#x22;)) %&#x3E;% 
group_by(Date = as.Date(time_ist)) %&#x3E;%
count(n = n()) %&#x3E;%
ggplot(aes(Date,n, group = 1, color = &#x22;red&#x22;)) +
geom_line(aes(alpha = 0.8),show.legend = FALSE) +
stat_smooth() +
# Courtesy: [https://stackoverflow.com/a/42929948](https://stackoverflow.com/a/42929948)
scale_x_date(date_breaks = &#x22;1 month&#x22;, date_labels =  &#x22;%b %Y&#x22;) + 
labs(
    title = &#x22;Daily-wise usage&#x22;,
    subtitle = &#x22;2+ years (including some 2019)&#x22;,
    x = &#x22;Months&#x22;,
    y = &#x22;# of Interactions&#x22;
  ) + theme(axis.text.x=element_text(angle=60, hjust=1))+
  theme(legend.position=&#x22;none&#x22;) +
  ggthemes::theme_hc(style  = &#x22;darkunica&#x22;)

给出了这个图:

这个情节最让我害怕。自从我买了一部新手机后,我的手机使用量真的激增了,这似乎不是我工作效率的好迹象。

工作日与周末

这个情节是为了看看我是否真的是一个电话上瘾者,即使是在家里和家人在一起。

me %>% 
  filter(!str_detect(header,"com.")) %>% 
  group_by(Date = as.Date(time_ist)) %>% 
  count(n = n()) %>% 
  mutate(year = as.factor(year(Date)),
         weekday = weekdays(Date, abbr = TRUE)) %>% 
  mutate(what_day = ifelse(weekday %in% c("Sat","Sun"),"Weekend","Weekday")) %>% 
  filter(year %in% c(2017,2018)) %>% 
  group_by(year,what_day) %>% 
  summarize(n = mean(n)) %>% 
  ggplot(aes(fct_relevel(what_day, c("Weekday","Weekend")),
             n, group = year, color = year)) + 
  geom_line() +
  labs(
    title = "Weekday vs Weekend usage",
    subtitle = "For two years",
    x = "Weekday / Weekend",
    y = "# of Interactions"
  ) +
  ggthemes::theme_excel_new()

给出了这个图:

幸运的是,事实证明我并没有像我担心的那样上瘾。

消息使用

多年来,我使用过从普通短信到即时消息的各种消息应用。

# Messaging Usage
p <- me %>% 
  filter(str_detect(tolower(header), regex("signal|message|whatsapp"))) %>% 
  mutate(ym = as.Date(paste0(format(as.Date(time_ist),"%Y-%m"),"-01"))) %>% 
  group_by(ym) %>% 
  count() %>% 
  #https://community.rstudio.com/t/tweenr-gganimate-with-line-plot/4027/10
  ggplot(aes(ym,n, group = 1)) + geom_line(color = "green") +
  geom_point() +
  ggthemes::theme_hc(style = "darkunica") +
  theme(axis.text.x = element_text(colour = "white",
                                   angle = 60),
        axis.text.y = element_text(colour = "white")) +
  scale_x_date(date_breaks = "1 month", date_labels =  "%b %Y") + 
  labs(
    title = "Messaging usage",
    x = "Year-Month"
  ) +
  transition_reveal(ym) + 
  ease_aes('cubic-in-out')
animate(p, nframes = 20, renderer = gifski_renderer("msging.gif"), width = 800, height = 800)

给出此动画:

这张图表显示了这是我总体手机使用量的驱动因素之一。相似时期的相似峰值。

Youtube 的使用

# YouTube Usage
yt <- me %>% 
  filter(header %in% "YouTube") %>% 
  mutate(ym = as.Date(paste0(format(as.Date(time_ist),"%Y-%m"),"-01"))) %>% 
  group_by(ym) %>% 
  count() %>% 
  #https://community.rstudio.com/t/tweenr-gganimate-with-line-plot/4027/10
  ggplot(aes(ym,n, group = 1)) + geom_line(color = "red") +
  geom_point() +
  ggthemes::theme_hc(style = "darkunica") +
  theme(axis.text.x = element_text(colour = "white",
                                   angle = 60),
        axis.text.y = element_text(colour = "white")) +
  scale_x_date(date_breaks = "1 month", date_labels =  "%b %Y") + 
  labs(
    title = "YouTube usage",
    x = "Year-Month"
  ) +
  transition_reveal(ym) + 
  ease_aes('quintic-in-out')
#anim_save("yt.gif", yt , width = 600, height = 600)
animate(yt, nframes = 10, renderer = gifski_renderer("yt2.gif"), width = 800, height = 800)

给出此动画:

这是我在 Youtube 上的使用情况,我主要使用媒体内容,这也与我的总体手机使用情况非常一致,这意味着这可能是另一个潜在的驱动因素。可能是我的手机屏幕变大了,所以我喜欢看更多的视频😑我也不希望事情变成这样。

结论

虽然我一直认为自己是为数不多的数字极简主义者之一,但这份分析证明,我并不完全是数字极简主义者,但在减少手机使用和改善生活方式方面,我还有待努力。请注意,这篇文章是以烹饪书风格而不是教程风格写的,这样你就可以开始运行你的 Android 活动分析。如果您对代码(逻辑)有任何疑问,请随时在评论中提出,我很乐意澄清它们。希望这篇文章能帮助你进行数据驱动的自我反省——至少是 Android 手机的使用。

参考

  • 如果你对学习处理 web 数据感兴趣,可以看看这个关于处理 Web 数据的教程
  • 整个代码库(还有一些章节和情节)可以在我的 github 上找到。随意星/叉使用!

本帖最初发表于 DS+

角度和散景

原文:https://towardsdatascience.com/angular-and-bokeh-e8acd86e7ab1?source=collection_archive---------12-----------------------

我们最近遇到了在应用程序或网站中显示质量图表的问题。但是除此之外,您还希望能够从 python 后端发送更新事件,并拥有所有漂亮的交互,比如按钮按压和文本输入事件,对吗?

散景图组件可能并不总是最佳的解决方案,但是尽管如此,我们希望在 GitHub 知识库中与您分享我们认为是一个很好的、最小的例子,演示了如何将 python 后端集成到 angular 应用程序中。

起点

是我们集成到 Angular 项目中的 BokehJS 库。绘图数据由 websocket 服务提供,在我们的示例中,我们使用 aiohttp,但是您可以设置任何其他 websocket 连接。角度组件可以通过它的标签名集成到 html 中的任何地方,下面的代码片段显示了散景图组件

<bokeh-chart></bokeh-chart>

散景图组件是一个规则的角度组件,有一个 html 部分

<div [id]="id"></div>

和打字稿部分。图表组件只需要向它自己的 html 部件提供 id。图表的数据由一个服务提供,这个服务在 ngOnInit 中的组件初始化时被调用。散景图组件的相关 typescript 部分如下所示

...
export class BokehChartComponent implements OnInit {
  public id: string;

  constructor(
    private bokehService: BokehService) { }

 ngOnInit() {
     this.id = "chart";
     this.bokehService.getChart(this.id);
 }
}

由于 BokehJS 库没有可用的类型,angular 中的集成并不像它应该的那样简单。人们只能通过库的全局暴露对象来访问库,在这种情况下,它也被命名为 Bokeh ,并且它是嵌入图表所必需的唯一挂钩。

// this is the global hook to the bokehjs lib (without types)
declare var Bokeh: any;

只有当你将普通的 java 脚本插入 angular 应用程序index.html最顶层的 html 文件时,这种魔力才会如预期的那样发挥作用

<head>
 ...
  <link
    href="[https://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css](https://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css)"
    rel="stylesheet" type="text/css">
  <script src="[https://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js](https://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js)"></script>
 </head>

博客服务

通过 MessageService 为图表提供数据,MessageService 封装了与后端的连接,因此只需通过公开的方法 sendMsg(msg)发送适当格式的消息。

export class BokehService extends Connector {constructor(private msgService: MessageService) {
 super(‘BokehService’);
 this.msgService.register(this);
 }…public getChart(id: string) {
 const msg = {
 name: ‘addChart’,
 args: [id],
 action: ‘default’
 };
 this.msgService.sendMsg(msg);
 }

该服务还向后端公开了一个方法,该方法实际上将图表绘制到原生 DOM 元素中,我们首先必须删除之前的绘图。

public plot(msg: Message) {
      const id = msg.args.id;
      const el = document.getElementById(id);
      // first remove the previous charts as child
      // like this, bokeh does not let us update a chart
      while (el.hasChildNodes()) {
            el.removeChild(el.lastChild);
      }
      // be sure to include the correct dom-id as second argument
      Bokeh.embed.embed_item(msg.args.item, id);
    }

后端服务

在我们的例子中是用 python 写的。我们使用 aiohttp 作为 web 服务器的异步解决方案。在浏览器中启动 angular 应用程序后,angular WebsocketService 立即连接到服务器端的 python 后端。请记住,在生产中,您将在这一点上实现更多的安全性,比如身份验证。后端准备接收来自 angular 的事件,例如给我散景图的数据。

来自 angular 的消息调用的 addChart 将 chartItem 作为连接到 websocket 服务的 json 项发送

 async def addChart(self, id_, user):
        """
        Example for adding a bokeh chart from backend

        """
        chartItem = self.chartProvider.chartExample()
        print("try to add chart for dom-id %s" % id_)
        context = {"name": "BokehService",
                   "args": {"item": chartItem, "id": id_},
                   "action": "plot"}
        await self.send_event(json.dumps(context), user=user)

这里有趣的部分是 send_event 方法,它实际上是基于我们的 websocket 服务器的实现。如前所述,在您的具体实现中,该部分可能会有所不同。

图表的最小示例也是作为 ChartProvider 类的成员函数编写的,它看起来非常简单,只为散景中的普通正弦图生成数据

import time
import numpy as np
from bokeh.plotting import figure
from bokeh.embed import json_itemclass ChartProvider(): def chartExample(self):
        t0 = time.time()
        # prepare some data
        self.phi += 0.02
        x = np.arange(0., 10., 0.1)
        y = np.sin(x + self.phi)
        # create a new plot
        p = figure()
        p.line(x, y, legend="SIN")
        chart_item = json_item(p)
        print(time.time()-t0)
        return chart_item

动画图表:可视化 R 中的“变化”

原文:https://towardsdatascience.com/animated-charts-visualizing-changes-in-r-fee659fbabe5?source=collection_archive---------19-----------------------

改头换面周一发布了一项来自世界银行的关于世界发展指标的每周数据挑战:青少年生育率(每千名 15-19 岁女性的出生率) 三月份。有了这个数据集,首先我想看看这些数字是如何随时间变化的,以及在收入群体方面是否存在模式。本文反映了数据操作的过程以及图表是如何从静态发展到动态的。

线条的变化

当谈到随时间的变化时,折线图是查看结果的快速而清晰的解决方案。

setting <- ggplot(final, aes(Year, Rate, group = Country))setting+ 
 geom_line(alpha = 0.5, aes(color = factor(Income_group))) +
 scale_colour_manual(values = c(high, upmiddle, lowmiddle, low)) + 
 facet_grid(~Income_group) + 
 theme_minimal()

正如我所料,几乎每个国家的青少年生育率都在下降。不同收入群体之间的差异在于,高收入国家的青少年生育率在 20 世纪 90 年代下降得相当快;而低收入国家的失业率下降缓慢。情况正在好转,只是在世界的某些地方没有那么快。

视觉上强调“变化”

根据上面的观察,我在想如何将收入群体的快速和缓慢变化可视化。我以 10 年为间隔提取了 1960 年至 2016 年的数据集,并创建了直方图来查看逐年的变化。

# extract data for some years
data.someyears <- final %>% 
 filter(Year %in% c(2016, 2010, 2000, 1990, 1980, 1970, 1960))ggplot(data.someyears, aes(Rate, fill = factor(Income_group))) +
 geom_histogram() +
 scale_fill_manual(values = c(high, upmiddle, lowmiddle, low)) +
 facet_grid( ~Year) +
 theme_minimal() +
 coord_flip()

如直方图所示,随着时间的推移,越来越多的国家青少年生育率下降。高收入国家从高税率到低税率有显著的变化;低收入国家只取得一点点进步。然而,从 8 个独立的数据片段中想象这种运动并不容易。

制作动画图表

这一系列直方图让我想起了制作动画图表的想法,这样我们就可以直接“看到”变化。我找到了一篇关于使用 gganimate 库在 R 中制作动画的有用文章。

movinghist <- ggplot(final, aes(Rate, fill = factor(Income_group))) +
 geom_histogram() +
 scale_fill_manual(values = c(high, upmiddle, lowmiddle, low)) +
 theme_minimal() +
 coord_flip() +
 #animation setting
 labs(
 title = ‘Year: {frame_time}’,
 y = ‘Number of countries’, 
 x = ‘Adolescent Fertility Rate (births per 1000 woman between 15–19)’
 ) +
 transition_time(as.integer(Year)) + #show the Year as integer
 ease_aes(‘linear’)animate(movinghist, width = 600, height = 600)

动画很有帮助。我们可以看到不同收入群体的国家如何降低青少年生育率。

除了按组可视化变化,我还进一步可视化了单个国家的变化。这样,每个国家都有自己的地方,一个圆点就是一年的青少年生育率。由于有这么多国家,我一次制作了一个收入群体的动画图表。

下面是一组的结果:

移动的点显示了有趣的行为。一些国家的利率有升有降。有些有明显的下降。如果用彩色编码,图表会提供更多的信息。因此,我计算了每年数字的变化,用绿色表示减少(因为越少越好),红色表示增加,灰色表示没有变化(1960 年也是没有变化)

movingdots <- ggplot(filter(final, Income_group == ‘High income’), aes(Country, Rate, color = factor(Status))) +
 geom_point(alpha = 0.7, size = 2) +
 scale_color_manual(values = c(down, up, same)) +
 facet_grid(~Income_group, scales = ‘free’) +
 theme_minimal() +
 theme(axis.text.x = element_text(angle = 60, hjust = 1)) +
 #animation setting
 labs(
 title = ‘Year: {frame_time}’,
 x = ‘Country’, 
 y = ‘Adolescent Fertility Rate (births per 1000 woman between 15–19)’
 ) +
 transition_time(as.integer(Year)) + #show the Year as integer
 shadow_mark(alpha = 0.3, size = 0.5) +
 ease_aes(‘linear’)animate(movingdots, width= 1800, height=600)

我有点沉迷于这些点,继续看它们。

请随时与我分享反馈。

动画信息图形

原文:https://towardsdatascience.com/animated-information-graphics-4531de620ce7?source=collection_archive---------36-----------------------

使用 Python 和 Plotly

Image www.pexels.com

各种数据集的动画信息图形是 youtube 上的一个热门话题,例如频道

[## 数据是美丽的

这个频道是我的激情项目,带我们一起沿着记忆之路进行一次有趣的旅行,这样我们就可以重温多彩的…

www.youtube.com](https://www.youtube.com/channel/UCkWbqlDAyJh2n8DN5X6NZyg)

拥有近百万订户。在这篇文章中,我将展示我的数据集上的一些这样的信息图的例子,这些数据集是奥地利报纸上关于政治的新闻文章,以及如何用 Python 和 Plotly(【https://plot.ly/】)创建动画。

在文章https://medium . com/datadriveninvestor/topics-in-online-news-before-the-Austrian-elections-2019-d 981 fac BD 0 DD中,我分析了选举前的话题。在这篇文章中,我想回顾一下从 2019 年下半年开始的新闻,并用动画图形来分析一段时间内的新闻。我收集并分析了 12 家奥地利在线日报的 22,000 多篇新闻文章。

第一个视频显示了每一天每一方被命名的频率。从 7 月开始算,一直算到年底。最后,VP 就在 FP 的前面,“NEOS”显然在最后。

在第二个视频中,显示了每个政党每周在每份报纸上被提及的次数。这也显示了整个下半年的动画。值得注意的是,个别媒体对某些党派有明显的偏好,例如,NEOS 在 ORF 之外很少被提及。国民议会选举的那一周在越来越多的报道和提及中清晰可见。选举后的联合政府谈判时期可以从“绿党”越来越多的命名中看出来。其他很多方面往往要看几遍视频才能看出来。

为了不仅检查报告的数量,我还试图以进一步可视化的方式显示主要内容。最常见的单词每天都显示在“单词云”中。占主导地位的人物明显突出,但选举期间的用词变化也很明显。在这里,像“百分比”或“选举结果”这样的词占主导地位。

让我们看看动画是如何创作的?

我加载了一个包含文章的数据框和一些用于数据框操作和日期处理的包。

Dataframe with articles

在统计了文章中提到的政党之后,数据框架被扩展为每个政党一栏。

Extended data frame

然后一些政党、报纸和动画日的列表被创建。对每个政党(和报纸)的条目进行汇总,生成一个带有“Plotly”的条形图。这些都标有条目的数量。为了获得更平滑的动画过渡,在两天的条形图之间计算了 15 个中间步骤,这些步骤是线性插值的。

在对图形进行一些格式化和标记后,它们被保存为编号的 PNG 文件。然后可以使用 Adobe After Effects 等软件将这一系列图像组合成一部电影。

为了创建“文字动画”,我使用了 Python 包“文字云”(https://github.com/amueller/word_cloud)。这个包为每天计算一个“单词云”,并再次保存为一系列 PNG 文件。

Image by the author

最后,我使用 After Effects 合并了上面显示的视频,并添加了一些字幕。

带 tweenR 的 R 中的动画情节

原文:https://towardsdatascience.com/animated-plots-in-r-with-tweenr-80c48b9f5292?source=collection_archive---------18-----------------------

Photo by Markus Spiske on Unsplash

利用动画来展示数据趋势是一个很好的讲述工具。在 R 中有几个创建动画效果的包

我最近遇到了 tweenR,它允许你通过插值创建平滑的过渡。tweenr 包本身实际上并不执行任何动画;相反,它创建中间状态,使动画更流畅。

下面是一个使用一些虚拟数据的教程:

library(dplyr)
library(scales)
library(tweenr)
library(animation)
library(dplyr)
library(ggplot2)
library(ggthemes)# an example of a time series data frame
plot_data <- data.frame(Date =seq(as.Date("2010/1/1"), as.Date("2019/1/1"), "years"), Value=runif(10,0,1000)) # prepare  data for tween by creating columns for the time between points
df.all<-plot_data %>% 
  mutate(day=as.numeric(Date-min(Date)+1),ease="linear")# add rows to fill in the gaps
plot_data_tween<-tween_elements(df.all, time = "day",  group="ease", ease="ease", nframes = nrow(df.all)*20)
df_tween_appear <- tween_appear(plot_data_tween, time='day', nframes = nrow(df.all)*10) 

绘图功能:

make_plot <- function(i){
  plot_data <-  df_tween_appear %>% filter(.frame==i, .age> -3.5) 
  p<- plot_data %>%
    ggplot()+
    geom_line(aes(x=Date, y=Value),color="darkgray", size=0.7)+
    geom_point(data=. %>% 
              filter(Date==max(Date)),
              mapping=aes(x=Date, y=Value),
              size=3,color="pink",stroke=4)+
    geom_point(data=. %>% 
               filter(Date==max(Date)),
               mapping=aes(x=Date, y=Value), color="white", size=2)+
    geom_text(data=. %>% filter(Date==max(Date)),
              mapping=aes(x=Date,
              y=Value,label=round(Value,0)),
              color="black",
              nudge_x=7,hjust=1.5, size=6)+
    geom_line(data=df.all, aes(x=Date,y=Value),alpha=0.1)+
    theme_minimal(base_family = "sans")+
    scale_y_continuous(sec.axis=dup_axis())+
    theme(plot.subtitle=element_text(face="italic",size=14),
          plot.title=element_text(color="darkcyan",size=19),
          plot.caption=element_text(hjust=0),
          panel.grid.major.x = element_line(color="lightgray"),
          panel.grid.minor.x = element_line(color="lightgray"),
          panel.grid.major.y = element_line(color="lightgray"),
          panel.grid.minor.y = element_line(color="lightgray"),
          axis.text.x = element_text(angle = 90, hjust = 1, size=12))+
          labs(x="",y="Total Value",
          caption="All values- 2010-2019.")+
          ggtitle(("Yearly Trends of Values"))
  return(p)
} 

现在我们循环每一帧并创建情节,然后使用动画包的saveGIF函数保存它。

ani_settings<-ani.options(interval=1/10)  *# N*umber to set the time interval of the animation (unit in seconds); *adjust for speed of ani*saveGIF({for (i in 1:max(df_tween_appear$.frame)){
  g<-make_plot(i)
  print(g)
  print(paste(i,"out of",max(df_tween_appear$.frame)))
  ani.pause() # adds a pause the end of animation
}
},movie.name="gifs/yearlytrends.gif",ani.width = 500, ani.height = 350)

一个有趣的例子:时间覆盖了多年

我摆弄了一下 Kaggle 的‘时代杂志封面图片’数据集。

该数据包含每年登上封面的女性和男性人数。然后我给数据框添加了帧和渐变。

调整“make_plot”上方的函数,然后在 tween_elements 参数中按性别分组,以便每年创建一个帧。

结果图如下所示:

性别人口统计

我在 R 中找到了一些很棒的动画资源,特别是:tweenr github 有一些教程:https://github.com/thomasp85/tweenr

我使用了这里的优秀教程来学习和理解 tweenR:

http://lenkiefer.com/2018/03/18/pipe-tweenr/

使用 Javascript D3 库的动画讲故事

原文:https://towardsdatascience.com/animated-storytelling-using-the-javascript-d3-library-a1c2264142ad?source=collection_archive---------16-----------------------

D3 是可用的最灵活的数据可视化工具,允许你创建伟大的数据故事插图

在我发表这篇文章的当天,英国将在 12 月举行自 1923 年以来的首次大选。代议制政府非常有趣,关于投票的数据往往可以告诉我们一个不同的故事,从下议院席位的最终结果以及哪个政党(或政党联盟)组成政府来看。

受 Nathan Yau 的原创 viz 和这些人的一个奇妙项目的启发——我自由地窃取并调整了代码——我开始创作一个自 1918 年以来所有英国大选的故事(这被认为是第一次现代选举)。我想到了一个相当简单的布局,其中我将有一个由 1000 名合格的左翼选民组成的力导向气泡图,其中选民将从一次选举“移动”到另一次选举,显示大众投票是如何分布的。在右边,我会有一个简单的叙述,有一张当选总理的照片和一个关于发生了什么的简短叙述。这是我最初想做的事情的草图。

如果你不想看“如何做”,我的完整代码在这里是,可视化在这里是。

My initial sketch

我需要什么?

对于这个项目,我需要:

  1. 一些数据——我们需要做一些操作,并把它们放在一个data文件夹中。
  2. 一些图片——我从维基百科中提取了所有首相的照片,并把它们放在一个名为img的文件夹中。为方便起见,每个文件都按选举日期命名。
  3. 一些 Javascript,它们会放在一个js文件夹里。
  4. 一些用于造型的css,它们将放在css文件夹中。

准备数据

从英国议会图书馆,我能够得到关于各政党的投票百分比的数据,我能够将这些数据与投票率统计数据结合起来,这样我就可以在我的图表中包括那些没有投票的人。所以我的起始csv档是这里的。

我需要重新想象一下,如果有 1000 名选民,每个人都由气泡图上的一个小气泡代表,那会是什么样子。所以我需要做的是将这些统计数据转换成一个 1000 行 27 列的数据帧,每行代表一个选民,每列代表一个选举日期。然后我按照五个党派团体和‘没有投票’的团体给每张选票编码 0,1,2,3,4,5。在我的数据框的每个单元格中,都是那个人在那次选举中投票支持的政党的代码。

然后,我需要向数据中添加一些时间序列,因为它将用于说明人们在时间上的运动。利用启发这项工作的方法,我决定将 27 次选举想象成一天中的几分钟,并将时间平均划分为 1440 分钟,这样最终的可视化将在移动到下一次选举之前显示相同时间的每个选举结果。

最后,我需要将每个人的数据输出为逗号分隔的字符串,其中奇数元素表示政党代码,偶数元素表示时间,因为这将是输入 web 代码的格式。

我在 R 中完成了这个转换,并将输出写成一个tsv文件,稍后我会将它放入我的 web 代码中。我用的 R 代码是这里的这里的最后的tsv输出是这里的这里的。

在 D3 中设置 viz

我们需要在我们的js文件夹中有可用的 D3 v3.5.5。我取了美国时间使用 viz 中使用的 Javascript 代码,并根据我的目的进行了调整,创建了一个名为election_bubbles.js的文件。首先,我设置了起始速度和图表尺寸,创建了一个列表供以后使用,并将时钟设置为零:

var USER_SPEED = "fast"; var width = 750,    
    height = 750, 
    padding = 1, 
    maxRadius = 3, 
    sched_objs = [], 
    curr_minute = 0;

接下来,我将每个活动代码定义为一个政党:

var act_codes = [ 
    {"index": "0", "short": "Conservative", "desc": "Conservative"},     
    {"index": "1", "short": "Labour", "desc": "Labour"}, 
    {"index": "2", "short": "Liberal/Liberal Democrats", "desc": "Liberal Democrats"}, 
    {"index": "3", "short": "Other", "desc": "Other"}, 
    {"index": "4", "short": "Plaid Cymru/SNP", "desc": "Plaid Cymru/Scottish National Party"}, 
    {"index": "5", "short": "Did not vote", "desc": "Did not vote"},
];

我还以毫秒为单位设置了我的速度选项,供以后使用:

var speeds = { "slow": 200, "medium": 125, "fast": 75 };

现在我使用了一个名为time_notes的列表来保存可视化所需的所有显示信息。对于每个选举,我创建了如下的键值对:

  • start_minute:我们的“虚拟时钟”上开始每次选举显示的时间——53 的倍数加 1。(53 是 1440/27 的舍入版本)。
  • stop_minute:停止每次选择显示的时间——在start_minute之后 50 虚拟分钟。
  • year:选举日期显示在页面顶部。
  • img:当选首相的照片之路。
  • color:包围每个img的边框——对应总理所属政党的颜色。
  • note:要显示的文本叙述。

这是一个相当长的列表,所以我不会在这里显示它—您可以在链接的源代码中看到它。此外,我将设置一个变量notes_index = 0,在后面的代码中指示我想从列表的第一个元素开始——1918 年的选举。

接下来,我想将“没有投票”的位置设置在 viz 的中心,然后将五个政党分组均匀地分布在中心周围的一个圆圈中。我希望列表中的第一方位于圆圈的右上位置,并将使用我的索引来确保:

var center_act = "Did not vote", 
    center_pt = { "x": 380, "y": 365 }; var foci = {};
act_codes.forEach(function(code, i) { 
    if (code.desc == center_act) {  
        foci[code.index] = center_pt; 
    } else {  
         var theta = 2 * Math.PI / (act_codes.length-1);    
         foci[code.index] = {x: 250 * Math.cos((i - 1) * theta)+380, y: 250 * Math.sin((i - 1) * theta)+365 }; 
    }
});

现在我将开始初始的svg——我计划在最终将它放入 HTML 时,将它完全放在它的父节点中:

var svg = d3.select("#chart").append("svg")    
    .attr("width", width)    
    .attr("height", height)    
    .attr('position', 'absolute')    
    .attr('left', '200px')    
    .attr('top', '200px');

运行 viz

现在,我将编辑主要的 viz 函数,以在每次选举的原力导向网络中移动。本节中的所有代码都将封装在一个函数中,该函数将在我们的 1000 个投票者的tsv文件上运行,如下所示:

d3.tsv("data/elec_results.tsv", function(error, data) {}

首先,我们从tsv中获取投票活动和持续时间的键值对列表,这些将填充到sched_objs列表中:

data.forEach(function(d) {  
    var day_array = d.day.split(",");  

    var activities = [];  
    for (var i=0; i < day_array.length; i++) {   
        if (i % 2 == 1) {    
            activities.push({'act': day_array[i-1], 'duration': +day_array[i]});   
        }  
     }  
     sched_objs.push(activities); 
});

接下来,我们只是窃取代码来填充每次选举的 1000 个节点,并将它们与标签一起写在我们的初始svg上。我不会在这里全部复制,但您可以在第 99–175 行这里找到它。

现在,我们使用timer()函数在后台运行虚拟时钟时运行数据中的开关。你可以在第 179–294 行这里找到完整的timer()函数,但是在这个函数中,我想强调一些这个可视化特有的东西。

首先,我们使用 D3 的transition()函数滚动图表标题中的日期,通过从背景色淡入使文本快速显示(这是您第一次看到某些样式元素,如背景色和字体):

 if (true_minute == time_notes[notes_index].start_minute) {     
    d3.select("#year")          
    .style("color", "#fffced")          
    .style("text-align", "left")          
    .style("font-size", "300%")    
    .style("font-family", "adobe-caslon-pro")   
    .text(time_notes[notes_index].year)    
    .transition()    
    .duration(500)    
    .style("text-align", "center")    
    .style("color", "#000000");  
}

同样,我们可以通过转换图像的不透明度来淡入和淡出图像:

if (true_minute == time_notes[notes_index].start_minute + 10) {
d3.select("#image").append('img')
    .attr('src', time_notes[notes_index].img)
    .attr('width', 200)
    .attr('height', 250)
    .style('position', 'absolute')
    .style('top', '100px')
    .style('left', '150px')
    .style('opacity', 0)
    .style("display", "block")
    .style("background", time_notes[notes_index].color)
    .style("padding", "8px")
    .style("border", "1px solid #ccc")
    .style("box-shadow", "5px 5px 5px #999")
    .transition()
    .duration(1000)
    .style('opacity', 1);
}

我们也可以上下滚动音符:

if (true_minute == time_notes[notes_index].start_minute + 10) {
   d3.select("#note")
      .style("top", "500px")
      .style("color", "#fffced")
      .style("font-size", "150%")
      .style("font-style", "italic")
      .transition()
      .duration(500)
      .style("top", "370px")
      .style("color", "#000000")
      .text(time_notes[notes_index].note);
}

您将看到许多类似的代码段,它们根据力导向气泡图中运动的时间来处理文本和图像的出现和消失。此外,还有一个功能可以根据英国政党的官方颜色来设置节点的颜色。

建立 viz

我们的 Javascript 现在给了我们几个动画对象来插入我们的网页。

  • 一个选举日期(#year),我想把它放在顶部,居中,在其他标题文本的下面
  • 一个力导向的气泡图(#chart),我想在页面的左边。
  • 一个图像(#image),我想在右边,一些叙事文本上方居中
  • 一些叙事文本(#note),我想在右边,居中,图像下方。

一些简单的html和一些css样式可以在css文件夹中找到——这里是为我工作的一般设置:

<div class="container" style="width:1600px">
    <div class="row">
        <img src="img/commons_logo.png" width="400px" class="center">
    </div>
    <div class="row">
        <div style="text-align:center;font-family:adobe-caslon-pro;font-size:200%;font-weight:bold">A Century of UK General Elections</div>
    </div>
    <div class="row">
        <div id="year"></div>
    </div>
    <div class="row">
        <div id="chart" class="col-lg-2" style="position:relative;width:1000px"></div>
        <div class="col-lg-2" style="position:relative;width:500px">
           <div id="image"></div>
           <div id="note" style="text-align:center"></div>
        </div>
    </div>
    <div class="row">
        <footer style="font-size:25%;text-align:right">Created by @dr_keithmcnulty. Github: <a href="https://www.github.com/keithmcnulty/uk_election_bubble">keithmcnulty/uk_election_bubble</a>. Source: UK Parliament, Statistica, Wikipedia</footer>
    </div>
   <div class="row" style="text-align:center">
        <div id="speed">
        <div class="togglebutton slow" data-val="slow">Slow</div>
        <div class="togglebutton medium" data-val="medium">Med</div>
        <div class="togglebutton fast current" data-val="fast">Fast</div>
    </div>
    </div>
    </div>
</div>

我将它插入到electionvis.html中,这也调用了一些引导样式和我的 JS 脚本。然后将它作为一个iframe插入到主index.html中,如果需要的话,可以控制 viz 的整体高度和宽度。

成品

这是成品的样子:

See the full thing here

使用 Javascript 需要一些学习,但是 D3 是一个非常灵活的工具,可以构建数据驱动的故事,在我看来完全值得努力。此外,还有许多预先构建的代码可供您根据自己的目标重新使用,就像我在这里所做的一样。

最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在LinkedInTwitter上找我。

用 StyleGAN 制作 gAnime 动画:第 1 部分

原文:https://towardsdatascience.com/animating-ganime-with-stylegan-part-1-4cf764578e?source=collection_archive---------8-----------------------

介绍与创成式模型交互的工具

Figure 1: Modifying spatial map(s) at a single location to produce an animation

1.1:前言

这是一个关于我使用生成对抗网络进行的一个项目的技术博客。由于这是一个个人项目,我摆弄了一个我通常不会在专业环境中使用的动画数据集。以下是该数据集的链接以及关于使用该数据集的模型的详细介绍:

[## Danbooru2018:大规模众包、标签化的动漫插画数据集

用于计算机修订的深度学习依赖于大型标注数据集。分类/归类受益于…

www.gwern.net](https://www.gwern.net/Danbooru2018) [## 用 StyleGAN 制作动漫脸

生成神经网络,如 GANs,多年来一直在努力生成质量不错的动漫人脸,尽管…

www.gwern.net](https://www.gwern.net/Faces)

我做的大部分工作纯粹是为了学习,但我最终得到的一些更有趣的结果是矩形肖像的嘴部动画:

Figure 2: Quick/Smooth mouth animation. Due to lack of data, male portraits tend to be lower quality

我将详细介绍我所做的技术细节和我学到的一些经验。该项目的一部分是一个工具,使互动和学习的生成性敌对网络更容易,但在这一点上,它不是用户友好的。如果我继续这个项目,我的目标之一将是发布该工具的一个版本,任何人都可以立即开始使用它来创建如图 2 所示的动画,但现在它主要是一个研究工具:

Figure 3: A screenshot of part of the tool. The UI definitely needs work, but at this point it’s still a prototype that I’m adding and removing features from on a regular basis

我发现,将实验代码整合到这样的工具中,而不是使用 jupyter 笔记本,可以更容易地用不同的设置重复实验。有些概念只有通过重复才能真正坚持,所以如果没有这个工具,我觉得我会错过博客中提到的一些见解。如果你只是对示例动画感兴趣,而不是技术细节,你可以跳到结果:动画部分。

个人项目的一个主要问题是它们只涉及单一视角。我写这个博客的目的是获得其他人对这个话题的看法,详细描述我在这个项目上的工作经历,并接受建设性的批评/纠正。

1.2:简介和结果总结

几年来,我一直习惯于定期重新实现关于生成模型的论文,所以我在 StyleGAN 论文发表的时候开始了这个项目,从那以后一直断断续续地在做这个项目。它包括 3 个主要部分:

1.StyleGAN 的重新实现,做了一些调整

2.使用该实现训练的模型

3.一种用于可视化和与模型交互的工具

我开始重新实现 StyleGAN 作为学习练习,因为当时官方代码还不可用。结果比我使用的其他模型好得多,所以我想更深入地研究。让我兴奋的一个生成模型的应用是视频游戏的自动资产创建。StyleGAN 是我实现的第一个在视频游戏中可以接受的模型,所以我最初的步骤是尝试让 Unity 这样的游戏引擎加载该模型。为了做到这一点,我做了一个. NET DLL,它可以与模型交互,理论上可以导入到 Unity 中。为了测试 DLL,我创建了一个与它交互的工具。当我想到它们的时候,我最终给马具添加了越来越多的特性,直到它成为项目中最大的部分之一。总体架构如下:

Figure 4: From TensorFlow python implementation to generating images with the tool

我喜欢使用工具来可视化数字对象并与之交互,否则这些数字对象可能是不透明的(如恶意软件和深度学习模型),所以我添加了一个功能,即功能图(图 5)的可视化以及修改它们的能力。观察不同图像中不同层的特征地图最活跃的位置,有助于我理解模型在做什么,并使自动定位一些面部特征变得简单。当谈到修改时,我注意到在特定位置从特征图中增加或减去值可以用来进行有意义的改变——例如张开和闭上嘴(图 2)。结合自动面部特征检测,这可用于对所有生成的图像进行一致、有意义的修改,而无需标签(图 9,10)。

Figure 5: Feature maps can be used to identify meaningful locations (top: eyes, bottom: faces). Red squares indicate negative activations, green squares indicate positive activations, white squares indicate activations close to 0

总结一下:一个特征使用特征映射来修改面部特征。

以下是博客其余部分的结构:

  • 生成模型的应用
  • 工具生成的动画
  • 代码的简要讨论
  • 重新实施详细信息
  • 对数据的讨论
  • 培训程序的讨论

应用程序

总的来说,有几个应用让我对创成式模型感兴趣:

  • 更好的游戏资产生成过程
  • 让艺术创作变得更容易、更快速
  • 无监督学习的基本潜力与生成因素的解开相结合

游戏资产更好的程序生成

我对生成模型将程序生成带到下一个层次的可能性感到兴奋。据我所知,基于现代规则的过程化生成技术不能从高度复杂的分布中随机创建样本。例如,程序生成的关卡的一个子部分可以独立于该关卡的其余部分,并且仍然可以被玩家接受。随机生成图形(如人物肖像)要困难得多,因为好看的图像往往反映真实世界,而真实世界有如此多的相互依赖性,以至于每个像素都需要在每个其他像素的背景下考虑。即使是风格化/绘制的图像也需要一致的照明、解剖、纹理、透视、风格等。为了好看。这也适用于自动生成音频、对话、动画和故事情节。生成模型是目前我所知道的从如此复杂的发行版中可靠地创建样本的最佳方式。

让艺术创作更简单快捷

在生成模型的背景下,交互式工具也有可能允许外行创建图像,否则需要有经验的艺术家,或者允许艺术家加速他们工作中更常规的部分。我不认为生成模型会很快消除对创意艺术家的需求,因为生成模型(以及大多数机器学习模型)专注于对特定分布进行建模。这使得创建不同于训练分布中任何样本的高质量图像(创造性图像)变得困难。像这篇博客中使用的工具,允许人们添加定制的改变,可以帮助产生更独特的图像,特别是如果模型已经学习了一些基本的图形概念,如照明和透视。

无监督学习的基本潜力与生成因素的解开相结合

由于未标记的数据远远超过标记的数据,并且深度学习非常渴望数据,我认为无监督/半监督学习有可能在未来几年逐渐取代监督方法。特别是一些深度生成模型的方法已经被用来理清数据集中的变异因素:关于 StyleGAN 如何做到这一点(至少是部分做到)的例子,见图 7,8。实际上并没有一个一致同意的解纠缠的正式定义,我的理解是有限的实验证据表明它对下游任务有用。然而,与 GANs 一起工作使我乐观地认为这将是有用的。虽然生成器不能为它没有生成的图像生成传统的内部表示,但有几个其他类型的生成模型可以在视觉质量上与 GANs 竞争,并且可能更适合下游任务。

结果:动画

我能训练的最好的模型是在一个动漫数据集上(https://www.gwern.net/Danbooru2018)。我将在数据部分探讨这种做法的优点和缺点,其中一个主要缺点是缺乏多样性:很难塑造男性形象。以下所有示例都是使用该工具生成的。我最初在 jupyter 笔记本上创建了这样的图像,但是使用专用工具大大加快了速度,并让我从不同的角度了解了模型的工作原理。下面的图片根据制作的复杂程度大致排序:图 7/8 比图 6 需要更多的工作,如果没有工具,图 9/10 会比图 7/8 更难制作。

图 6 是几个图像的中间潜变量之间的插值的例子。GANs 可以实现的一个很酷的结果是确保插值图像具有与端点相似的质量。

Figure 6: Interpolating between random latent vectors

图 7 是通过在中间潜在空间中定位具有特定含义(在这种情况下是头发或眼睛颜色)的矢量并在该方向上移动来修改图像的例子。例如,黑头发的向量可以通过拍摄许多有黑头发的脸的图像并平均它们的潜在值,然后从所有其他图像的平均值中减去结果来找到。我将在培训/后处理部分详细讨论这一点。

Figure 7: Changing a latent vector in a meaningful direction

图 8 显示了应用于属性“mouth open”时用于生成图 7 的相同概念。这在某种程度上是可行的,但是属性并没有完全解开:图像的每个部分都可以看到变化,而不仅仅是嘴巴。常识告诉我们,一个人可以移动他们的嘴,而不会明显改变其他东西。一个简单的方法是将动画嘴部粘贴到其他静态图像上,但这在改变“嘴部张开”向量也会改变肤色或图像风格的情况下不起作用。

Figure 8: Vector to change mouth also changes other attributes

图 9 示出了修改靠近角色嘴的空间位置处的特定特征图以产生不会引起全局变化的说话(或咀嚼)动画的示例。只需一点手动工作,就可以找到需要修改以产生这种变化的要素地图,而只需要几个已标注数据的示例。所有这些都可以通过工具来完成。该过程的灵感来自于 DCGAN 论文如何通过修改特征图来演示窗口删除。修改是对特定特征地图的局部区域的简单增加或减少。我将在以后的博客中展示如何使用该工具实现这一点。

Figure 9: Spatially local modification to produce talking animation. Once feature map(s) that correspond to a meaningful change are found, they can be applied to most images, regardless of quality or style.

图 10 显示了与图 9 相同的内容,除了应用于发带的存在/不存在。这种技术可以应用于许多不同的属性。

Figure 10: Adding/subtracting hairband using local modifications

结果:代码

鉴于我有限的空闲时间和我的主要目标是学习,我把对大多数项目很重要的几个方面放在次要位置:

  • 规划/设计:我从尽可能少的规划开始,并根据我的想法添加功能/变化
  • UI 设计:我使用了贪婪的方法来添加我想到的特性。
  • 代码风格:我并没有带着让别人阅读代码的意图进入项目,相反,我的目标是尽可能快地得到结果。有了恶意软件逆向工程的背景,我并不特别担心需要自己调试低质量的代码。对于工具来说,快速运行效果很好,但对于实现深度学习模型来说,我要慢得多,因为错误很难捕捉和调试。代码质量远非专业项目所能接受的。

有了这些免责声明,这里是 gitub 链接。他们正在积极开发中,所以在一些提交中可能会有一些错误:

StyleGAN 重新实施:

[## Nolan-dev/style gan _ re implementation

这是 NVidia 的风格甘 https://github.com/NVlabs/stylegan 我出于学习目的的重新实现。我的…

github.com](https://github.com/nolan-dev/stylegan_reimplementation)

工具:

[## 诺兰·德夫/甘界面

这是一个与 StyleGAN 模型生成的图像进行交互的工具。它有 3 个部分:TensorflowInterface: Native…

github.com](https://github.com/nolan-dev/GANInterface)

1.3:实施细节

在这一节中,我将详细介绍我重新实现 StyleGAN 并使用它训练一个模型的技术细节

StyleGAN 重新实现

在论文发表后不久,我就开始重新实现 StyleGAN,这是在正式代码发布前的几个月。在本节中,我将讨论我遇到的一些挑战和采取的方法,前提是熟悉 StyleGAN 论文和 TensorFlow。

StyleGAN 基于 PGGAN ,我已经重新实现了它。这些模型使用“渐进式增长”,其中鉴别器和生成器在训练期间增长,以处理越来越高的分辨率。开发一个模型有点不常见——我实现的所有其他模型都不需要在训练期间改变它们的架构。幸运的是,TensorFlow 有一些方便的功能,例如能够只为模型的一部分加载保存的权重,并随机初始化其余部分。这也用于迁移学习。

我非常喜欢 TensorFlow 2.0 将模型创建为从 tf.keras.Model 继承的类的风格。我以这种方式创建了大多数层、生成器、鉴别器和映射网络。我还试图让它成为在急切执行和传统的基于图形的执行之间切换的一个选项。急切执行允许更容易的调试,我认为这是更好地理解程序的一种方式(恶意软件分析中的一种常见技术)。不幸的是,当时急切执行似乎比在图形模式下运行要慢得多,所以最终我停止了更新该功能。使用 tf.keras.Model 的一个好处是它对 eager 和 graph 模式都有效,所以理论上让 eager 再次工作应该不会太难。与此同时,我刚刚使用了 tfdebug 命令行界面和 TensorBoard,在这一点上我已经相当习惯了。

StyleGAN 与 PGGAN 有一些重要的不同。有一种名义上的方法,在使用“自适应实例规范化”操作时,将特定于图像的潜在数据作为样式(非空间属性)提供给特征地图。从概念上来说,这种方法实现起来很简单,如本文所述,但我选择使用 tf.nn.moments 来计算均值和方差,其效果不如官方实现版本,后者使用较低级别的运算来计算这些值。我的第一个猜测是,这是由于数字问题,这不是我当时想调试的东西,所以我没有进一步研究它。我通常很乐意更深入地研究这样的问题,因为它们显然是了解更多的机会,但由于这个项目是一个爱好,我必须优先考虑,以充分利用我的时间。

StyleGAN 还使用了一个中间的潜在空间,该空间通过增加潜在值范围的灵活性和依赖性,假设性地(本文中提供了一些经验证据)促进了解开。例如,如果我们假设一个人群中的男性从来没有长头发,那么对应于头发长度的潜在向量应该永远不会在“长头发”区域,而对应于性别的另一个潜在向量在“男性”区域。如果潜在向量是独立的,这是在没有映射网络的情况下发生的,并且我们最终在“男性”旁边采样“长发”,那么生成器将不得不创建一个不是男性或者是短发的图像,以欺骗鉴别者。这意味着即使潜在的头发长度在“长头发”区域,当其他潜在值在它们范围的正常部分时,我们可能最终创建一个短头发的图像。请注意,一些解缠结的定义需要轴对齐(修改单个潜在值会导致有意义的变化),而我的理解是,StyleGAN 的映射网络鼓励中间潜在空间是轴对齐解缠结的旋转(修改潜在值的向量会导致有意义的变化)。

在我看来,使用中间潜在价值就像通过风格将信息融入网络一样有趣。实现起来也很简单。除非另有说明,否则我在本系列博客中提到的潜在价值指的是中间潜在价值。

一篇论文中最初看起来很小的细节变成了最难实现的部分,这种情况非常普遍。StyleGAN 就是这种情况——style gan 和 PGGAN 之间的一个区别是使用双线性上采样(和下采样)和 R1 正则化(对鉴别器的梯度惩罚)。这两者单独实现起来都很简单,但是当我试图将它们结合起来时,结果是 TensorFlow 无法计算 tf.nn.depthwise_conv2d 操作的二阶导数。深度方向卷积用于对每个通道单独应用滤波器。这在卷积神经网络中通常是不需要的,因为(在一些用于移动设备的 CNN 之外)每个滤波器连接到前一层中的所有信道。通常用于实现双线性插值的模糊过滤器一次对一个特征地图进行操作,因此它需要深度方向的卷积。没有二阶导数,我不能计算 R1 罚函数,这需要对梯度求梯度。当时,我对自动微分的了解还不足以让自己轻松实现二阶导数。我花了一些时间试图得到一个更好的理解,然而在这一点上,我已经完成了一切,除了这一部分,不久之后,官方代码被释放。Nvidia 的团队在模糊滤镜中使用了两个 tf.custom_gradient 函数,很好地解决了这个问题。

我对 StyleGAN 做了几次实验性的调整,取得了不同程度的成功。

1.我测试了矩形图像,将初始分辨率改为 8x4,并在此基础上进行增长

2.我试着用 ACGAN 和 cGan 和投影鉴别器来调节 StyleGAN

矩形图像效果很好。用 ACGAN 和 CGAN 对标签进行处理则不会。这可能是由于我的超参数选择,但一般来说,结果比没有条件的训练差,然后在潜在空间中找到对应于有意义特征的向量(在训练/后处理部分讨论)。

数据

FFHQ 数据集——收集了 70,000 幅高分辨率图像——与 StyleGAN 论文一起发布。为了更接近生成整个人的目标,我尝试修改 Nvidia 提供的数据提取脚本,以提取 8:4 (h:w)纵横比的图像。除了提取面部,还从面部以下提取了相同数量的数据。将高度和宽度都加倍需要考虑 4 倍的输入尺寸,但是仅将高度加倍就需要 2 倍的尺寸。一个人面部以下的数据也应该比背景数据具有更少的差异(差异主要来自不同的服装),并且不捕捉背景数据意味着网络不需要将容量专用于不属于该人的数据。

不幸的是,在 FFHQ 数据集中的 70,000 幅图像中,只有 20,000 幅图像具有足够的人脸下方数据来创建具有理想纵横比的图像。从图 11 中可以看出,我无法用这个小数据集获得特别高质量的结果,但是可能有提高质量的方法(比如扩展包含图像的标准)。

Figure 11: Rectangular FFHQ images tended to be low quality

我也对甘斯在风格化的图画上表演的能力感兴趣,我看到https://www.gwern.net/Danbooru2018最近已经发行。该数据集包含大量高分辨率图像和非常丰富的标签数据。它确实有一些潜在的缺点,例如男性图像的数量少得不成比例,这大大降低了该类图像的质量(图 12)。该图中的男性图像是从生成的大约 1000 幅图像中精选出来的最高质量的图像。我确实认为这里有很大的改进潜力,特别是在普通男性形象周围使用截断技巧。

Figure 12: Most male portraits (top) are low quality due to dataset limitations. Even when minimally cherry-picked for quality, female portraits (bottom) tend to be higher quality. None of the images here use the truncation trick for higher quality

该数据集还包含 NSFW 图像的重要部分,尽管我认为生成模型的一个潜在用途是自动修改媒体,使其更适合不同的观众。

为了选择要包含的候选图像,我可以利用元数据,包括“收藏夹”(有多少人收藏了一张图像)、分辨率、标签和创建日期。为了减少差异和提高质量,我排除了很少有人喜欢的图像和 6 年前创建的图像。我还只保留了分辨率至少为 512x256 (HxW)的图像,这是我的模型目标分辨率。最后,我过滤掉了带有标签的图像,这些标签会增加肖像风格数据集中的差异,例如“躺下”和“从侧面”,或者暗示非常 NSFW 的图像。

为了生成数据,我结合使用了以下两种工具,并对其进行了修改,以提取所需纵横比的图像:

[## qhgz 2013/动漫人脸检测器

一种基于快速 RCNN 的动漫人脸检测器。该检测器对 6000 个训练样本和 641 个测试样本进行了训练…

github.com](https://github.com/qhgz2013/anime-face-detector) [## nagadomi/lbpcascade_animeface

使用 OpenCV 的动漫人脸检测器。原始版本自 2011 年起发布于…

github.com](https://github.com/nagadomi/lbpcascade_animeface)

这些工具并不总是正确地提取图像,所以我使用 illustration2vec 来过滤结果,因为无法检测到人的图像可能是坏的。

[## rezoo/illustration2vec

illustration2vec (i2v)是一个简单的库,用于估计一组标签并从标签中提取语义特征向量

github.com](https://github.com/rezoo/illustration2vec)

我还创建了一个工具,可以显示一个大的图像网格,从中我可以快速手动删除坏图像,但对于超过 30,000 张图像的数据集来说,这太耗时了。我最终得到了几个不同的数据集,包括各种质量和标签的图像,图像从 40,000 到 160,000 不等。所有这些都产生了比我构建的 20,000 幅图像 FFHQ 数据集更好的模型。

培训/后处理

我使用每个分辨率多达 80 个时期来训练该模型,其中 PGGAN 过渡阶段分解为 40 个时期,稳定阶段分解为 40 个时期。对于 160,000 的图像数据集来说,这需要一个多月的时间,可能有点过了。我使用 Horovod 在两个 Nvidia Titan RTX 显卡之间分配训练,这允许在早期步骤中的大批量大小,并使我永远不需要低于每批 16 个样本。

为了收集属性,我生成了成千上万的图像,并用 illustration2vec 扫描它们以获得属性估计值。对于有超过 1000 个对应图像的每个属性,我将潜在值平均在一起,并从整体平均图像中减去它们。这就产生了一个向量,当它被加到一个潜在的属性上时,会促进所期望的属性的表达。虽然这工作得很好(我解释为映射网络解开属性的进一步证据),我对改进过程感兴趣,可能通过使用 https://arxiv.org/abs/1907.10786 的中描述的技术。在某些情况下,我试图手动解开相关属性:例如,如果金发与蓝眼睛相关,从金发向量中减去对应于蓝眼睛的向量可能会有所帮助。然后,我将这些属性向量导出到一个 csv 文件中,该文件可以被工具加载。

结论/杂项说明

通过尝试重新实现那些依赖于我不理解的基本原理的论文,然后在清楚的背景下学习这些基本原理,我获得了很多经验。这个过程感觉很像反向传播,意味着我已经花了 30 多个小时试图完全理解早期的一篇论文。这是我第一次尝试创建一个工具来增强这种理解,我认为它可能会成为我前进的标准策略。

我相信视觉工具是提高对主题理解的一个很好的方法。作为一名恶意软件分析师,像 Hiew 这样的工具对我理解恶意软件的方式至关重要,尽管最初并不直观可视化分析如何有助于 windows 可执行文件。鉴于人类视觉系统可用的带宽和处理能力,我的假设是,当用图像表示时,我们可以从大多数具有空间局部结构的数据中快速获得许多洞察力。这也是卷积神经网络似乎能够很好地处理的数据类型(考虑到它们的生物学灵感,这并不令人惊讶)。这个概念也适用于卷积网络本身,这也是我从事这个项目的原因之一:希望可视化卷积神经网络的特征图可以帮助我更好地理解它们。

在这个博客系列的下一部分,我将更详细地介绍这个工具,以及如何用它来制作动画。我还分享了该工具的一个编译版本和一个训练有素的交互模型,因为目前只使用源代码进行交互的过程很复杂。

[## 使用 StyleGAN 制作 gAnime 动画:工具

开源 GAN 研究工具的深入教程

towardsdatascience.com](/animating-ganime-with-stylegan-the-tool-c5a2c31379d)

使用 StyleGAN 制作 gAnime 动画:工具

原文:https://towardsdatascience.com/animating-ganime-with-stylegan-the-tool-c5a2c31379d?source=collection_archive---------9-----------------------

开源 GAN 研究工具的深入教程

Visualization of feature map 158 at a layer with resolution 64x64

0.前言

这是我个人项目中的一个研究工具的教程/技术博客。虽然博客的很大一部分假设您在阅读时可以访问该工具,但我试图包括足够多的截图,即使您没有时间亲自尝试,也应该清楚它是如何工作的。

在本教程中,我们将与一个经过训练的 StyleGAN 模型进行交互,以创建如下动画(的帧):

Spatially isolated animation of hair, mouth, and eyes

在上面的动画中,改变嘴、眼睛和头发的变换大多是独立的。这通常比用 GANs 制作说话动画的其他方法(据我所知)更可取,这可能会导致脱发等副作用:

Another animation we’ll create to demonstrate how changes in the ‘mouth’ attribute can influence other parts of an image. Note the hair thickening and thinning along the edges.

我们还将通过使用网络中各层的特征图来构建简单的启发式面部特征检测器:

Using feature maps at various layers to detect mouths, eyes, and cheeks

然后,这些检测器可用于自动进行有意义的修改,以便隔离图像的各个部分:

These images generated were in a single batch without human intervention or a labeled dataset

这些步骤都不需要训练集的标签,但是需要一些手工操作。

1.介绍

您可以从以下链接之一下载该工具的编译版本:

[## GanStudio_x64_v1.zip

编辑描述

drive.google.com](https://drive.google.com/file/d/1cv2SiWQKtlC-XCAeAiGHh2C8XCAZe9xd/view?usp=sharing) [## 非常

MEGA 提供免费云存储,具有方便、强大的永远在线隐私功能。立即申领您的免费 50GB

mega .新西兰](https://mega.nz/#!VCIRyIRI!t_g2OQYkuqtPAdd5wgsSHUEYhYI47ip84jydGZMI-bg)

sha 256:ec2a 11185290 c 031 b 57 c 51 EDB 08 BF 786298201 EB 36 f 801 b 26552684 c 43 BD 69 c 4

它配备了一个在动画数据集(T2 的许多项目都基于该数据集)上训练的模型。不幸的是,由于数据集的性质,缺乏性别多样性。我目前正在尝试训练一个模型,以产生更高质量的男性形象,但这需要一段时间才能完成。数据集还包含 NSFW 影像,虽然我生成了数千幅影像,但从未遇到过任何 NSFW,我并没有检查训练集中的每一幅影像(对早期图层中的要素地图进行大规模修改可能会增加风险)。如果你遇到问题,你可以在 https://github.com/nolan-dev/GANInterface提出问题,我会尽力回应。

这个博客有两个部分:基础教程和高级教程。基础教程演示了如何使用该工具,并且不需要太多的技术知识就可以完成(尽管它为感兴趣的人提供了一些技术解释)。高级教程演示了如何定制工具,并且更具技术性——例如,您应该熟悉卷积神经网络中的特征映射。

我在以前的博客中介绍了这个工具,并分享了源代码,但是让它工作起来很复杂,需要一个用我的自定义 StyleGAN 实现训练的模型。我希望提供一个工具的编译版本和一个预先训练好的模型能让它更容易试用。该工具是上一篇博客讨论的更大项目(包括 StyleGAN 的重新实现)的一部分,但是阅读它并不是这篇博客的先决条件。如果你感兴趣,这里有一个链接:

[## 用 StyleGAN 制作 gAnime 动画:第 1 部分

介绍与创成式模型交互的工具

towardsdatascience.com](/animating-ganime-with-stylegan-part-1-4cf764578e)

由于这是一个研究工具,我一直在定期添加和减少功能,以更好地了解模型如何工作以及与它交互的最佳方式。有许多次要功能,但主要功能包括:

  • 修改生成图像的潜在向量,以便在图像之间进行插值,表达某些特征,并在质量和变化之间进行权衡(截断技巧)
  • 修改特征地图以改变图像中的特定位置:这可用于动画
  • 读取和处理特征地图,以自动检测有意义的特征
  • 通过创建批处理作业来自动化上述所有操作

和上一篇博客一样,我写这篇博客的目的是获得其他人对这个话题的看法,详细描述我在这个项目上的工作经历,并接受建设性的批评/纠正。本博客的教程格式旨在缓解该工具不发达的 UI,并使其有可能在不处理混乱的源代码的情况下使用。不幸的是,它仅适用于 Windows,但它已在免费的 Windows AWS 实例上进行了测试(Microsoft Windows Server 2019 Base,但图像生成会很慢)。

2.基础教程

在我们开始之前,有一个小提示:我在写这篇文章的时候修改了这个工具,所以一些截图与当前版本略有不同,但是一切都在大致相同的地方。

下载并打开上面链接的 zip 文件后,你会看到几个文件/文件夹:

我将在高级部分(3.3)更详细地解释其中的一些,但是此时唯一重要的文件是 GanStudio.exe。当您运行它时,单击免责声明的 ok(希望不要出现任何错误),您将看到如下内容:

由于 UI 的复杂性,在本教程中我第一次引用该工具的一部分时,我会有一个附近的截图,相关部分用红色标出。许多 UI 元素都有工具提示。

设置:

使用这个工具涉及到与 windows 资源管理器的交互,用“大”或“超大”图标查看生成的文件是最容易的。通过右键单击资源管理器窗口并选择“查看”来选择其中之一:

在许多情况下,按修改日期对图像进行排序也很有帮助,这也可以通过右键菜单实现:

生成新图像

要测试图像生成,请单击生成新图像(3)。这将产生一个新的潜在代码,并显示它的图像。注意生成第一幅图像通常比生成后续图像需要更长的时间。

该图像是随机创建的,但被插值以接近“平均”图像。这导致更高质量的图像,但减少了变化。如果你把质量滑块(1)放在上图的同一个地方,你的图像很可能是相似的:一个棕色头发,紫色和/或蓝色眼睛的女孩。

加载图像

为了使本教程中的图像与该工具将产生的图像保持一致,我提供了一个示例图像。点击“导入图像”(如上,2)。这将在“肖像”目录中创建一个打开文件对话框。导航至“肖像”上方的目录,并选择“教程文件”:

双击 sample_01.png 进行加载。您生成的所有图像都保存在“肖像”文件夹中,您可以使用这种方法再次加载它们。

GANs 通常不能加载任意图像,但是这个工具会将生成图像的潜在代码附加到它写入磁盘的每个 PNG 文件中。“导入图像”按钮读取写入您选择的图像的潜在代码。只要工具加载了生成图像的模型,它就能够重新创建图像。

修改属性

Hover over attribute label that have been cut off to see full name

要开始修改属性,请选择“Attributes_0”选项卡(如上)。属性包括头发/眼睛颜色、背景强度、配饰和嘴部状态(微笑/张开)。向右移动对应于属性的滑块将增加该属性对图像的影响,向左移动将减少所述影响。他们中的一些人比其他人工作得更好。选择位置后,按“更新此图像”(如上)。以下是一些例子:

Left to right/top to bottom: Positive open_mouth, positive skin_tone, negative background and negative black_hair, positive blonde_hair and negative smile

以这种方式修改属性的一个缺点是它们并不总是空间隔离的;修改只影响图像一部分的属性也会影响其他部分。如果我们想要创建动画,这尤其成问题。要查看实际问题,请执行以下步骤(以下截图供参考):

  1. 向下滚动到“张开嘴”滑块
  2. 把它移到右边
  3. 按“更新此图像”。嘴现在应该微微张开
  4. 选择批次- >属性- >光谱
  5. 选择“确定”以生成 5 幅图像,选择“否”以“滑过 0?”提示。

这将产生 5 个图像,其中“张嘴”属性从 0 移动到滑块上的选定位置:

将这些内容放入 gif 生成器会生成以下动画:

Frame order based on the first number in the filename: 0, 1, 2, 3, 4, 3, 2, 1

正如你所看到的,即使我们只选择了一个与嘴相关的属性,整个图像的特征都会改变。

修改具体位置

在这一节中,我们将只对嘴进行修改,而不改变其他特征。不幸的是,此时使用导入图像按钮导入的图像将不会反映这里所做的更改。

重复加载图像一节中的说明,回到基础图像(或重置属性滑块并更新)。我们使用“空间”选项卡(如下)来修改图像的孤立部分。

UI 很复杂,但是对于这一部分,我们将只使用几个部分。我们需要做的第一件事是指出我们想要改变图像的哪一部分:

  1. 选择“嘴巴张开”选项卡。
  2. 放开之前,单击、按住并拖动光标穿过嘴巴

这就在嘴的周围做了一个选择,并确保我们对图像的改变只会影响所选的区域。

Click on locations within these squares to create them on your image, or click and drag across this portion of the image

这将产生一个浅绿色的正方形,除非选择了“在可视化中用绿色替换蓝色”。我将在本教程中选择这个选项来提高可见度,并希望当我们开始处理表示负面影响的红框时,对色盲更加友好。

如果您错误地选择了一个位置,您可以在选择时按住“control”来删除方块:

Remove an undesired selection. Click and drag with ctrl held to remove multiple selections.

以下是您可以在图像上“绘制”的所有方式。其中一些现在还不需要,但以后会有用:

  1. 左键单击产生一个大小取决于所选分辨率的框(稍后将详细介绍)。该框表示在该位置的积极影响,根据您的设置,该框将为绿色或蓝色。
  2. 右键单击在该位置产生一个具有负面影响的红色框
  3. 按住 Ctrl 键并单击可擦除某个位置的方框
  4. 执行上述任一操作时,单击并拖动鼠标以绘制一个大矩形区域
  5. 如果未选中“无选择重叠”,您可以多次选择同一位置以增加选择的幅度(正或负)。这表现为更高的颜色强度和更厚的方框。

选择嘴部后,向右移动“嘴部张开”标签下方的滑块,直到左下方的数字大约为 100。此滑块是“要素地图乘数滑块”,当它向右(积极影响)或向左(消极影响)移动时,会对活动选项卡产生指数影响。将滑块左下方的数字设置为 100 左右,选择“更新此图像”:

这应该会产生以下图像:

正如标签的名字所暗示的,这开了口。让我们尝试用这种方法制作动画。selectBatch->Fmap->combinator IC(我会在高级教程中详述为什么这么叫):

为要生成的图像选择 5:

选择 0 作为起点。该批将由 5 个图像组成,滑块在起点和终点之间有规则的间距(0,20,40,80,100)。因为在此图像中嘴默认是闭合的,所以起点 0(无影响)表示闭合。

这将产生比属性方法具有更少空间纠缠的 5 个图像:

gif 生成器产生以下内容:

其他选项卡也可以使用相同的过程,并且可以组合不同的选项卡。如果你使用的是组合批处理生成器,你需要将除激活标签之外的所有标签的乘数条保持为零,以避免产生多个标签的组合。这可以通过在更改活动标签的乘数之前按下“全部设置为零”来完成:

这里列出了一些可能的变化。请注意,使用大乘数很可能会产生奇怪的伪像:

  1. 红色或蓝色的眼睛

起点和终点如下:

The dialog actually says Start Point, this is an old screenshot. The start point corresponds to the first image that gets generated in the batch, and the end point corresponds to the last.

生产:

2.脸红

设置:

If the screenshot and the tool disagree, believe the tool. This is an old screenshot (should say Start Point instead of End Point)

动画:

3.束发带

设置:

I actually had the variable for this prompt called ‘startValue’ originally, don’t know why I made the prompt say End Point. You may have guessed this is an old screenshot

动画:

4.头发

设置:

You’d think it would make sense to start at the low number and end at the high number, but actually this is an old screenshot and End Point should be Start Point. It will start at 100 and shift down to -257

动画:

These settings slightly influence the mouth because the effective receptive field of convolutions late in the network cover a lot of spatial locations in early layers.

5.ice_is_nice(???)

设置:

We’re selecting the entire image here. For scenarios like this, I’d advocate for the click and drag method over clicking 4096 times with extreme precision. Also: it should say Start Point instead of End Point

动画:

Example of a modification late in the network: details are influenced, but overall structure stays the same

其他可以尝试的东西:

  • 批量生成新图像,质量和属性栏位于不同位置:

  • 使用“设置为基础图像”(如下)使质量条在当前图像(而不是平均图像)和新图像之间插值。当与 Batch- > New latents (上图)结合使用时,这对于查找与当前图像略有不同的新图像非常有用。

  • 使用“切换上一张”在当前图像和上一张图像之间快速切换,以检查更改。

Focus on the red box, not the blue box around ‘Toggle Show Selection’ which I clicked earlier. At the moment toggle show selection doesn’t even work.

  • 使用 Misc- >在两幅图像之间插值生成两幅现有图像之间的图像光谱。

3.高级教程

本节假设您对卷积神经网络和 StyleGAN 有所了解。

3.1 寻找新功能

“空间”部分中的选项卡(嘴巴张开、发带等)对应于添加到特定图层的特定要素地图的值。尝试选择 mouth_open 选项卡。在选项卡上方的组合框中,它应该显示分辨率:16x16。StyleGAN 中的早期图层具有低分辨率的要素地图,而后期图层具有高分辨率的要素地图(分辨率通常会翻倍)。由于我们生成的图像是 256x256 像素,对应于 16x16 的层在网络中处于早期。要查看 mouth_open 选项卡修改了哪些特征映射,请在选中“过滤零点”的情况下按“查看所有 Fmap Mults ”,然后选择“特征映射输入”选项卡:

这意味着通过单击在图像中选择的空间位置会乘以-2,然后乘以要素地图乘数滑块,结果会添加到分辨率为 16x16 的图层上的要素地图 33 中。

一些选项卡会影响多个要素地图:

The feature maps influenced by the ‘hairband’ tab, viewed by clicking on ‘View All Fmap Mults’

我通过摆弄这个工具手动找到了这些乘数。我用了两种方法:

  1. 为了修改图像中的现有属性(例如,嘴),我通过修改不同的特征图并查看哪一个产生了期望的结果来使用试错法。
  2. 要添加一个属性(发带),我会查看当该属性存在时哪些特征地图是活动的。

在接下来的两节中,我将介绍这些方法的例子。

方法一:修改嘴

假设网络可以生成嘴巴张开和闭合的图像(这是欺骗鉴别者所必需的),并且每一层的特征图都是最终图像的表示,那么修改特征图可以用于张开或闭合嘴巴是有意义的。但是,不能保证修改单个要素地图会导致有意义的变化-我们可能需要修改许多要素地图的组合才能获得所需的结果。也就是说,单一要素地图更容易使用(至少在当前工具下),因此查看每个要素地图如何影响图像可以作为一个起点。

以下是我如何找到特征图 33 来张开/闭上嘴巴。首先,我用“添加标签”按钮添加了一个 16x16 的标签(如下)。我选择这个分辨率是因为它能产生合理的嘴巴大小的盒子。较小的分辨率将改变嘴以外的区域,而较大的分辨率通常导致比张开或闭合嘴更精细的变化(此时分辨率的选择是启发式的)。通过再次单击“查看所有 Fmap Mults ”,我们看到没有为新选项卡设置任何功能图。然后我将滑块移动到 190 左右,这也是一个基于过去模型经验的启发式决定。最后,和我们之前做的一样,我选择了包含嘴的两个盒子。

Adding a new tab, which initially does not influence any feature maps

然后,我选择批处理- > Fmap - >轴对齐,并选择 512 张图像进行生成。

这实际上会产生 1024 个图像,因为对于每个特征图,它会将乘数栏中指定的值(在本例中为 190)添加到图像中标记的空间位置(嘴)。批量生成会弹出一个窗口,显示已经生成的图像数量,并允许您中断该过程。点击“生成图像”旁边的计数器,打开它们被写入的目录:

The number prepended to the file names is the feature map that was modified

以‘33 _ n _ sample’(n 代表负)开头的样本明显有开口,而‘33 _ p _ sample’没有。这意味着当从嘴周围的特征图 33 中减去 190 时,嘴张开了。

我使用“设置 Fmap”框(如下)将特征映射 33 设置为-1。这使得向右移动滑块将打开嘴巴(这感觉比将特征地图 33 设置为 1 并使标签名为“mouth_close”)更直观,我使用“重命名标签”按钮将标签重命名为 mouth_open。重命名选项卡旁边的保存选项卡按钮可用于保存选项卡。

方法二:加一个发带

这种方法依赖于找到具有所需属性的现有图像。这需要一个图像库来处理,可以用 Batch- > New latents 生成。在这种情况下,我通常会将质量条移过中间一点,以确保有合理的变化量。

可能需要几百个样本才能得到几个带发带的样本。我在 tutorial_files 目录中添加了一个,我将在本教程中加载它(sample_02.png)。加载之前,创建一个 16x16 的选项卡,并确保“Fmaps To Get”设置为“All”或“Current Tab”(如下)。创建新图像时,这些选项从网络获取并存储额外的输出:当前选项卡或所有选项卡的特征映射。这可能会减慢速度,所以它不是默认选项(而且在撰写本文时,它有 0.5%的机会导致崩溃,与大批量相关)。

然后,执行以下操作:

  1. 选择发带周围的框
  2. 在“添加视图特征映射按钮”下,选择“按选择的相似性排序”
  3. 按“更新此图像”

这将向“功能图输出”选项卡添加一组按钮:

这些按钮对应于特征地图。它们按特征图的点积大小和图像上的选择(展平后)进行排序。这使得发带周围具有较大幅度的特征贴图会在按钮列表中较早显示。

这是第 310 张特征图的一个例子。蓝色对应正值,红色对应负值。某个位置的绝对值越大,在该位置绘制的方框就越厚、越饱和。

该特征图似乎在发带周围以及嘴周围具有大的正值。虽然它显然不仅仅用于发带,但我们可以尝试修改它,看看结果是什么。将该选项卡的特征映射 310 设置为 1,擦除发带周围的选择(ctrl+单击并拖动),并再次加载 sample_01.png。

尝试选择头发,将权重增加到 100 左右,并更新图像:

……没什么变化。然而,由于我们没有产生任何奇怪的人造物,将星等增加到 100 以上可能不会有什么坏处。

大约 600 年,我们得到了看起来像一个发带。我最初的假设是,我们需要使用大星等的一个原因是因为发带不常见。

对于包含在工具中的发带标签,我设置了几个其他的特征贴图,在示例图像中,这些贴图在发带周围是活跃的,设置为 3。将它们设置为大于 1 的数字有助于规范化选项卡的预期范围,因此将乘数设置为 100 左右应该可以表达所需的属性。

3.2 自动特征检测

我们修改属性的方法的一个问题是,它需要手动选择我们想要改变的方块。与在‘嘴部张开’方向上修改潜在向量相比,这无疑是不利的,因为在‘嘴部张开’方向上修改潜在向量不需要我们知道嘴部的位置(即使它也修改非嘴部特征)。这使得该方法无法很好地扩展;虽然比绘图容易,但每次修改仍然需要人工干预。然而,正如我们在上一节中看到的,一些特征地图与属性的位置相关联:例如,特征地图 310 可能被用于一般地检测发带。让我们看看能否找到一种方法,仅使用特征图的线性组合来检测图像中的嘴。

首先,重复用于激活发带周围的特征贴图的过程,只是这次选择嘴:

像以前一样,我们可以点击一个按钮来显示一个特征图:

但是,在查看和比较大量要素地图时,这种方法有点慢。相反,在“从输出添加”按钮下方的文本框中键入 20,然后按按钮。然后,按“查看多个 Fmaps”。

带有 20 个按钮的“从输出添加”将前 20 个按钮的特征地图添加到“fmap”文本框,“查看多个 fmap”并排显示它们。

对应于特征图 234、34、370 和 498 的前 4 个(以及其他几个)看起来都像是嘴巴检测器。然而,我们不知道他们是否会持续检测新图像的嘴部。为了测试这一点,我们可以生成几个新的图像,质量条位于中心右侧,以获得适当的方差。首先确保“记录要素地图”已选中。使用“重置历史记录”清除现有记录。此外,确保“Fmaps To Get”设置为“Current Tab”(该工具不会记录所有分辨率的历史记录,只会记录与当前选项卡相对应的分辨率)。然后,我们可以通过使用批- >新潜在客户生成许多新图像,该工具将记录它们的特征图。

在这种情况下,我将生成 10 个新的图像,这将是不同于你的任何一个。要查看所有图像的相同特征图,请在 Fmaps 框中输入特征图,然后选择“查看历史”。我将对 234、34 和 370 中的每一个都这样做。

234:

34:

370:

嘴的位置变化不大也无妨,但这些特征地图似乎确实能可靠地跟踪它。

相同的过程可以应用于其他层的其他属性。以下是一些例子:

眼睛:

脸颊:

背景:

在许多情况下,我通过组合多个特征地图来获得最一致的结果。为此,我让 python 脚本可以从工具中调用(这对未来的特性也很有用),因为我更愿意用 numpy 进行多维数据处理。该工具使用 PATH 环境变量来查找 pythonw.exe,因此需要在运行该工具之前进行设置。脚本功能是该工具的最新特性,甚至比其他功能开发得更少。这里有一个例子:

spatial_map.py 存储在“脚本”目录中,您需要安装其依赖项才能使用它。该工具将路径传递到写入“脚本要素地图”中指定的要素地图的目录。然后,它组合这些特征地图并输出结果,该结果由工具读取并用于在图像中进行选择。这里有一个例子,使用了我们之前发现的一些与嘴部位置相关的特征地图:

移动嘴部滑块到~100 并更新图像,像平常一样张开嘴。

这让我们可以自动创建具有特定属性的图像。

通过选择“生成时运行脚本”下的“运行并修改”,将 mouth_open 设置为 100 左右,并生成新的 latents,我们可以确保新图像有一个张开的嘴巴。通过将 mouth_open 设置为-100,并将该设置应用于包含张嘴图像的目录,我们可以生成同样的闭嘴图像。

将设置应用到目录可以通过杂项- >将当前滑块应用到目录并选择带有生成图像的目录来完成:

或者,这可以使用批处理- > Fmap- >新的潜在组合一次完成:

请注意,该选项将基于所有乘数为非零的选项卡进行组合修改。例如,如果“头发”选项卡有一个非零乘数,我们选择生成 3 个“头发”图像和 2 个“嘴巴张开”,它将创建每个图像的 6 个变体,具有以下属性:

  • 短发,闭着嘴
  • 短发,张着嘴
  • 中等长度的头发,闭着嘴
  • 中等长度的头发,嘴巴张开
  • 长头发,闭着嘴
  • 长发,张嘴

关于脚本还有几点:

  • 您可以在要素地图前添加一个乘数,以更改各种地图组合时的影响。

  • 用于检测面部特征的特征图的分辨率不需要与我们输入数据的分辨率相匹配。脚本应该根据需要调整大小:

  • 脚本还有其他潜在用途,例如记录要素地图的表示,以便在工具关闭后进行分析。

这涵盖了该工具的大部分功能。在下一节中,我将更详细地讨论这个架构。

3.3 工具详情

From TensorFlow python implementation to generating images with the tool

该工具有 4 个主要组件:

  1. TensorflowInterface.dll:使用 tensorflow C api 加载模型
  2. GanTools.dll:将 TensorflowInterface.dll 加载到 C#环境中
  3. GanStudio.exe:加载 GanTools.dll 以便与模型交互
  4. 数据文件:graph.pb(模型)和 data _[graph . Pb 的 MD5 中的文件,这些文件包含特定于模型的信息并被加载以帮助交互。

这些都可以在 zip 文件中看到:

图像被写入“肖像”目录,标记为收藏夹的图像被写入“收藏夹”目录,而“脚本”目录包含该工具可以加载的 python 脚本。其余的文件是工具的其他组件使用的库。

数据目录包含几个文件:

  • saved_fmaps 包含工具启动时加载的选项卡(嘴巴张开、发带、腮红等)数据。选项卡数据包括修改了哪些要素地图、脚本信息和乘数。
  • attributes.csv 包含“Attributes_0”选项卡用来以有意义的方式修改潜在向量的向量。
  • average_latent.csv 包含通过对映射网络生成的大约 10,000 个潜在值进行平均而生成的平均(中间)潜在值。质量/唯一性栏使用它来应用截断技巧。
  • latents.csv 包括所有生成图像的潜在值。在我开始将潜在值附加到图像之前,它更重要,但它仍然可以作为备份。

所有这些都是特定于模型的,这就是为什么我通过将 graph.pb 文件的散列附加到目录名来将目录绑定到模型的原因。

TensorflowInterface.dll 是加载 graph.pb 的组件,它使用tensorflow.dll与之交互。它通过导出 3 个主要函数来实现这一点:

这种交互的大部分是使用模型中张量的名称来完成的。虽然源代码是可用的,但我认为获得这些名称(以及更好地理解模型)的最好方法之一是通过像 netron 这样的工具。在下图中,netron 用于检查添加操作的输入,该操作合并了此工具所做的要素地图修改。

Operations to allow adding/subtracting values in feature maps (screenshot of Netron)

4.结论

结合本系列的前一篇博客,我已经写了一份相当全面的记录,记录了到目前为止我为这个项目所做的工作。这些博客没有详细介绍的两个例外是生成 512x256(高 x 宽)图像的能力和我用更多男性图像训练的模型。

本博客中使用的模型实际上可以产生 512x256 的图像,但是我在网络早期就切掉了底部:

Using netron to view graph.pb

这提高了图像创建速度,减小了 UI 的大小,但最重要的是,它保持了图像适合所有观众。

我最初认为有男性图像的模型更糟糕,因为图像的方差增加了,平均质量降低了,为了包含大量的男性图像,我必须降低“最喜欢的”阈值(见原始博客)。然而,当我更新我的 StyleGAN 重新实现的代码时,我注意到我在实现样式混合时引入了一个 bug ( 这里是修正)。该错误意味着用于从中间潜在到风格转换的权重在两个自适应实例规范化层之间共享。这降低了网络的容量,也可能是新模型比旧模型更差的原因。这是需要处理的最令人讨厌的错误类型之一:它不会阻止模型工作,但它会以一种直到模型完成训练才真正注意到的方式降低性能,并且性能的降低可能归因于其他因素。安德烈·卡帕西在这一系列推文中说得很好:

对于个人项目,包括这篇博客中讨论的工具,我更喜欢使用“快速修复”的方法(恶意软件分析让我几乎享受到了调试的乐趣)。然而,这对于实现深度学习模型不起作用,尽管我在使用 TensorFlow 时倾向于更慢地移动以避免这样的错误,但有时如果我在项目的不同部分花费了太多时间,它们仍然会出现。这是我正在积极尝试改进的地方,我发现一个有用的策略是在 TensorBoard 或 netron 中查看模型的图形,以获得不同的视角。

由于这个工具主要是基于查看和修改特征地图,我有兴趣使它适用于除了 GANs 之外的生成模型。如果可以将任意图像作为输入的模型可以像 StyleGAN 一样在其内部表示中演示相同类型的无监督面部特征检测,那将是一件好事。我还想将这种动画制作方法与视频到视频合成进行比较,并对使用生成模型制作动画的其他工作进行更多研究。

制作矩阵奇异值分解的动画

原文:https://towardsdatascience.com/animating-the-singular-value-decomposition-of-a-matrix-27f8ce1f7723?source=collection_archive---------20-----------------------

使用 Python 和 Autodesk Maya

Image by the author

奇异值分解(SVD)是许多应用中出现的一种计算,它将一个矩阵分解成 3 个矩阵的乘积。例如,它用于以下领域:

  • 在推荐系统中,如网飞。使用 SVD 构建推荐系统的介绍可以在下面找到:
    https://towards data science . com/beginners-guide-to-creating-an-SVD-recommender-system-1fd 7326 D1 F6
  • 在图像分析程序中使用主成分分析
    https://towardsdatascience . com/eigen faces-recovering-humans-from-ghosts-17606 c 328184
  • 以及文本的主题分析方法
    https://medium . com/nano nets/topic-modeling-with-LSA-psla-LDA-and-LDA 2 vec-555 ff 65 b 0b 05

在本文中,我将借助 3D 动画展示这种分解背后的几何解释,以鼓励直觉。

您可以在下面找到对 SVD 的很好的介绍:

[## 你不知道 SVD(奇异值分解)

真正理解 SVD——直观的核心思想

towardsdatascience.com](/svd-8c2f72e264f)

[## 奇异值分解教程:应用,例子,练习

奇异值分解方法的完整教程

blog.statsbot.co](https://blog.statsbot.co/singular-value-decomposition-tutorial-52c695315254)

所考虑的(数据)矩阵可以具有 n 行和 m 列的任何维度,并且矩阵中的条目可以代表图像的像素值、文本中的词频、用户对电影的评级或许多其他东西。

分解的三个矩阵有特殊的性质,与矩阵相关的线性变换有特殊的几何解释。我想用 3D 动画展示分解矩阵的几何解释。

为了便于说明,我使用 3x2 矩阵及其分解乘积作为例子,使数据可以用 3D 表示。小球体的栅格在动画中经受相应的线性变换。让我们看看结果:

Animation of the Singular Value Decompositions of some matrices

为了创建动画,我使用了 Autodesk Maya(https://www.autodesk.com/products/maya/overview)并在 Maya 中使用 Python 编写脚本。

让我们看看动画是如何录制的

我使用 Python 脚本在 Maya 中构建场景并制作对象动画。可以从 Maya 的脚本编辑器中运行脚本。

Maya script editor / Image by the author

在脚本开始时,导入所需的包。“Maya.cmds”用于在 Maya 中执行命令,“math”用于某些计算,“numpy”用于奇异值分解。创建了一个由 3 个平面构建的长方体,考虑球体在其上投射阴影。

我们设置光源并构建一个小球体网格来测试转换。

我们借助线性代数的“Numpy 包”(https://docs . scipy . org/doc/Numpy/reference/routines . Lina LG . html)定义我们想要分解、动画化和计算 SVD 的矩阵的变换矩阵。

我们需要一个函数来执行平面旋转。定义请看 https://en.wikipedia.org/wiki/Rotation_matrix 的。

以及一些用于计算 3D 旋转的旋转轴和旋转角度(欧拉角)的函数。关于定义和计算,请参见同一篇维基百科文章。

对于球体的中心,我们使用作为测试对象,我们通过取点积来计算矩阵变换后的新坐标。与矩阵 A 相乘得出的端点与按此顺序与 V、S 和 U 相乘得出的端点相同。

最后,我们构建球体动画的路径,首先在一个平面内旋转,然后用一个对角矩阵沿着轴拉伸坐标,最后执行 3D 旋转。

这个脚本用于记录不同矩阵等级的几个矩阵的动画。你可以在上面的视频中看到结果。

制作旅行推销员问题的动画

原文:https://towardsdatascience.com/animating-the-traveling-salesman-problem-56da20b95b2f?source=collection_archive---------21-----------------------

从制作模型动画中学到的经验

动画可以是一个强大的工具。用文字甚至图片来解释一个复杂的主题是一回事,但是动态的视觉效果有一种惊人的品质,可以将抽象的想法变得生动。这在诸如优化和机器学习等复杂的计算机科学领域尤其有用。

2018 年 10 月,我在 KotlinConf 做了一个关于优化和机器学习的演讲。在这几个例子中,有一个是旅行推销员问题(又名“TSP”)。这是一个如此有趣和迷人的问题,它经常作为优化和甚至机器学习算法的基准。然而,解释一些算法(如局部搜索和模拟退火)在没有视觉辅助的情况下不太直观。因此,我通过 TornadoFX 用 JavaFX 做了这个开源项目。

会议上和网上的许多人都对动画视觉效果感到惊讶,评论它看起来多么“集成”和流畅。事实是我一起破解了这个应用程序,JavaFX 在其中起了很大的作用。它替我处理了动画,所以我可以专注于算法本身。这就是我想在这篇文章中写的内容。

您可以在这里观看这个应用程序的视频演示(带有对 TSP 的详细解释)。我建议在继续阅读之前先看看这个。

这篇博文的重点将放在动画和它是如何实现的。要深入了解 TSP 以及如何解决它,请观看上面的视频。

该结构

为了建立这一点,让我们首先布局我们的视觉框架的结构。我将用 Kotlin 语言来表达这一点,并通过 TornadoFX 来利用 JavaFX。幸运的是,TornadoFX 没有隐藏或抑制 JavaFX 的任何功能,而是用富于表现力的 Kotlin DSL 来增强它。所以你可以用 Java,Kotlin,Scala,或者任何可以使用 JavaFX 的 JVM 语言来实现。

我在应用程序中要做的第一件事是声明一个Pane,并在其中放置一个带有简单欧洲地图图像的ImageView 。然后从我的领域模型中,我将导入我的City对象,并在相对于欧洲地图的 x 和 y 屏幕坐标上放置一个红色的Circle 。最后,我将从我的域中导入Edge对象,其中每个对象都绑定到一个City,并将每个对象绑定到一个Line。每个Edge 代表两个城市之间的一个连接,它以同一个城市为起点和终点进行初始化。因此,Line将通过停留在Circle内作为一个小点来初始化。Line也将绑定到其所属EdgestartXendXstartYendY属性。

pane {
    imageview(Image("europe.png")) {
        fitHeight = 1000.0
        fitWidth = 1000.0

        CitiesAndDistances.cities.forEach { city ->
            circle(city.x,city.y,10.0) {
                fill = Color.RED
            }
        }

        Model.edges.forEach { edge ->
            line {
                startXProperty().bind(edge.edgeStartX)
                startYProperty().bind(edge.edgeStartY)
                endXProperty().bind(edge.edgeEndX)
                endYProperty().bind(edge.edgeEndY)
                strokeWidth = 3.0
                stroke = Color.RED
            }
        }
    }
}

在这一点上,我应该有这样的渲染:

当我们制作动画时,我们将改变每个边的startXendXstartYendY属性。例如,当我们想要连接两个城市时,我可以更改endXendY属性,使这条线延伸到另一个城市的坐标。

策划动画

有了这个结构,接下来我确实需要考虑一些事情。我应该实时制作算法的动画,还是将动画排队并使其可播放?我是想把算法做的每一件事都做成动画,还是过滤掉噪音,只把关键事件做成动画?

乍一看,这些决定似乎不重要,我甚至告诉自己“为什么不把一切都做成动画呢?”。当然,这很快就适得其反了,因为动画已经降低了算法的速度……而且在算法中制作无效事件的动画只会增加噪音。这也使得动画变得异常冗长和乏味。

你会问,什么是非生产性事件?正如视频中所解释的,该算法通过进行数千次随机Edge 交换来工作。当互换没有改善解决方案时(或者在模拟退火方法中抛硬币失败了),我会取消互换,把所有东西都放回去。我了解到最好不要将这些事件动画化,因为大多数迭代都是失败的交换,并且最好将成功动画化来显示进展,而不是每个迭代都包括失败。

我最终做的另一个调整是首先运行算法,然后用然后用动画显示结果。这样做的好处是能够重放结果,而不必再次运行整个过程。我在 JavaFX 库中需要的关键实用程序是SequentialTransition,它允许我将动画排队并按顺序播放(而不是一次播放)。

然后我可以让我的算法给SequentialTransition 添加动画,当它完成后就可以播放了。我将每个算法(“贪婪”、“二次选择”、“模拟退火”等)存储为可枚举的,所以我给每个算法赋予了自己的SequentialTransition。我还创建了一些方便的扩展函数,这样我就可以使用+=操作符来添加动画。

enum class SearchStrategy {

    RANDOM {
        ... 
    },

    GREEDY {
        ... 
    },

    REMOVE_OVERLAPS {
        ... 
    },
    TWO_OPT {
        ... 
    },

    SIMULATED_ANNEALING {
        ... 
    }

    val animationQueue = SequentialTransition()

    abstract fun execute()
}

// extension functions for SequentialTransition
operator fun SequentialTransition.plusAssign(timeline: Timeline) {   
     children += timeline }fun SequentialTransition.clear() = children.clear()operator fun SequentialTransition.plusAssign(
    other:SequentialTransition) { 
        children.addAll(other) 
}

执行路径遍历

在领域模型方面,我有最初属于一个CityEdge项目。然而,startCityendCity可以变异,在每次变异时,Edge都有一个animateChange()函数返回一个延迟的Timeline来播放那个变化。

但这是我最后做的有趣的设计决定。我创建了edgeStartXedgeStartYedgeEndXedgeEndY,使其不与各自的startCityendCity同步。相反,它们纯粹用于动画执行。当我决定在startCityendCity中制作一个变化的动画时,我调用animateChange()来创建一个Timeline来制作坐标变化的动画。它将获取保存坐标值的每个 JavaFX 属性中的当前值,并通过在这段时间内逐渐增加/减少到指定值来制作动画(这是KeyFramespeed)。

注意,虽然这个Timeline不执行,但这取决于函数调用程序如何使用这个动画。

class Edge(city: City) {

    val startCityProperty = SimpleObjectProperty(city)
    var startCity by startCityProperty

    val endCityProperty = SimpleObjectProperty(city)
    var endCity by endCityProperty

    val distance get() = CitiesAndDistances.distances[CityPair(startCity.id, 
      endCity.id)]?:0.0

    // animated properties
    val edgeStartX = SimpleDoubleProperty(startCity.x)
    val edgeStartY = SimpleDoubleProperty(startCity.y)
    val edgeEndX = SimpleDoubleProperty(startCity.x)
    val edgeEndY = SimpleDoubleProperty(startCity.y)

    fun animateChange() = timeline(play = false) {
            keyframe(speed) {
                keyvalue(edgeStartX, startCity?.x ?: 0.0)
                keyvalue(edgeStartY, startCity?.y ?: 0.0)
                keyvalue(edgeEndX, endCity?.x ?: 0.0)
                keyvalue(edgeEndY, endCity?.y ?: 0.0)
                keyvalue(Model.distanceProperty, 
                     Model.totalDistance)
            }
        }
}

这个特殊的函数用于第一次将一个Edge扩展到另一个城市,这发生在GREEDYRANDOM算法中。将这些按顺序缝合在一起会产生一条光滑的路径,从而创建一个往返行程。下面是在RANDOM算法中如何利用animateChange()函数。请注意,当我遍历每个随机的City时,我是如何分别通过它们的startcityendCity连接每个连续的Edge对的。然后我调用animateChange()返回一个Timeline并添加到animationQueue中。

RANDOM {
    override fun execute() {
        animationQueue.clear()

        val capturedCities = mutableSetOf<Int>()

        val startingEdge = Model.edges.sample()
        var edge = startingEdge

        while(capturedCities.size < 
                CitiesAndDistances.cities.size) { capturedCities += edge.startCity.id

            val nextRandom = Model.edges.asSequence()
                    .filter { it.startCity.id !in capturedCities }
                    .sampleOrNull()?:startingEdge

            edge.endCity = nextRandom.startCity
            animationQueue += edge.animateChange()
            edge = nextRandom
        }

        Model.bestDistanceProperty.set(Model.totalDistance)
    }
}

当绿色 play 按钮被按下时,我的 UI 可以调用animationQueue.play()来执行更改。

执行交换

交换比制作路径遍历的动画要复杂一些。当TWO_OPTSIMULATED_ANNEALING算法选择随机边并试图以某种方式交换它们的城市(顶点)时,有时会失败,有时会成功。如果交换中断了旅程,则会发生故障,并且会调用reverse()函数。如果成功,可以调用一个animate()函数并返回一个等待排队或执行的Timeline

class TwoSwap(val city1: City,
          val city2: City,
          val edge1: Edge,
          val edge2: Edge
) {

fun execute() {
    edge1.let {      
          sequenceOf(it.startCityProperty,it.endCityProperty)      
    }.first { it.get() == city1 }
    .set(city2) edge2.let { 
       sequenceOf(it.startCityProperty,it.endCityProperty) 
    }.first { it.get() == city2 }
    .set(city1)
}fun reverse() {
    edge1.let { 
        sequenceOf(it.startCityProperty, it.endCityProperty) 
    }.first { it.get() == city2 }
    .set(city1)

    edge2.let {
        sequenceOf(it.startCityProperty,it.endCityProperty)     
    }.first { it.get() == city1 }
     .set(city2)}

fun animate() = timeline(play = false) {
        keyframe(speed) {
            sequenceOf(edge1,edge2).forEach {
                keyvalue(it.edgeStartX, it.startCity?.x ?: 0.0)
                keyvalue(it.edgeStartY, it.startCity?.y ?: 0.0)
                keyvalue(it.edgeEndX, it.endCity?.x ?: 0.0)
                keyvalue(it.edgeEndY, it.endCity?.y ?: 0.0)
            }
        }
        keyframe(1.millis) {
            sequenceOf(edge1,edge2).forEach {
                keyvalue(Model.distanceProperty, 
                   Model.totalDistance)
            }
        }
    }

}

fun attemptTwoSwap(otherEdge: Edge): TwoSwap? {

    val e1 = this
    val e2 = otherEdge

    val startCity1 = startCity
    val endCity1 = endCity
    val startCity2 = otherEdge.startCity
    val endCity2 = otherEdge.endCity

    return sequenceOf(
        TwoSwap(startCity1, startCity2, e1, e2),
        TwoSwap(endCity1, endCity2, e1, e2),

        TwoSwap(startCity1, endCity2, e1, e2),
        TwoSwap(endCity1, startCity2, e1, e2)

    ).filter {
        it.edge1.startCity !in it.edge2.let { 
           setOf(it.startCity, it.endCity) 
        } && it.edge1.endCity !in it.edge2.let {  
           setOf(it.startCity, it.endCity) 
       }
    }
    .firstOrNull { swap ->
        swap.execute()
        val result = Model.tourMaintained
        if (!result) {
        swap.reverse()
        }
        result
    }
}

这可用于TWO_OPTSIMULATED_ANNEALING算法。请注意,对于这两种算法,我首先清理animationQueue,执行RANDOM算法并获取其所有动画,并将它们添加到该算法的动画中。对于TWO_OPT,我尝试了 2000 次随机交换,并且只添加了增加旅程距离的动画。否则我调用reverse()并且不对交换进行动画处理(就好像它从未发生过一样)。

TWO_OPT {
    override fun execute() {
        animationQueue.clear()
        SearchStrategy.RANDOM.execute()
        animationQueue += SearchStrategy.RANDOM.animationQueue

        (1..2000).forEach { iteration ->
        Model.edges.sampleDistinct(2).toList()
                .let { it.first() to it.last() }
                .also { (e1,e2) ->

                    val oldDistance = Model.totalDistance
                    e1.attemptTwoSwap(e2)?.also {
                        when {
                            oldDistance <= Model.totalDistance -> 
                                it.reverse()
                            oldDistance > Model.totalDistance -> 
                                animationQueue += it.animate()
                        }
                    }
                }
        }
        Model.distanceProperty.set(Model.totalDistance)
        Model.bestDistanceProperty.set(Model.totalDistance)

        println("TWO-OPT BEST DISTANCE: ${Model.totalDistance}")

    }
}

一旦算法完成,就在期望的SearchStrategy可枚举上调用animationQueue.play()并观看焰火。

Matplotlib 动画

原文:https://towardsdatascience.com/animations-with-matplotlib-d96375c5442c?source=collection_archive---------0-----------------------

使用 matplotlib 库创建一些有趣的动画。

Rain Simulation with Matplotlib

动画是展示一种现象的有趣方式。我们人类总是被动画和互动的图表所吸引,而不是静态的图表。动画在描述时间序列数据时更有意义,如多年来的股票价格、过去十年的气候变化、季节性和趋势,因为我们可以看到特定参数如何随时间变化。

上图是对雨 的模拟,是用 Matplotlib 库实现的,该库被亲切地称为 python 可视化包的始祖。** Matplotlib 今天 Python 拥有大量强大的可视化工具,比如 Plotly、Bokeh、Altair 等等。这些库能够实现最先进的动画和交互性。尽管如此,这篇文章的目的是强调这个库的一个方面,这是没有探索太多,那就是动画**,我们将看看这样做的一些方法。****

概观

Matplotlib 是一个 Python 2D 绘图库,也是最流行的一个。大多数人从 Matplotlib 开始他们的数据可视化之旅。使用 matplotlib 可以很容易地生成曲线图、直方图、功率谱、条形图、误差图、散点图等。它还与 Pandas 和 Seaborn 等库无缝集成,以创建更复杂的可视化。

matplotlib 的一些好特性是:

  • 它的设计类似 MATLAB,因此两者之间的切换相当容易。
  • 包括许多渲染后端。
  • 它几乎可以复制任何情节(只需一点努力)。
  • 已经存在了十多年,因此,拥有庞大的用户群。

然而,也有一些领域 Matplotlib 并不突出,落后于其强大的对手。

  • Matplotlib 有一个命令式 API,通常过于冗长。
  • 有时不良的文体默认。
  • 对 web 和交互式图形的支持较差。
  • 对于大而复杂的数据,速度通常很慢。

作为复习,这里有一个 Matplotlib 备忘单,来自 Datacamp ,你可以通过它来复习你的基础知识。

动画片

Matplotlib 的animation基类处理动画部分。它提供了一个构建动画功能的框架。有两个主要接口可以实现这一点:

[FuncAnimation](https://matplotlib.org/api/_as_gen/matplotlib.animation.FuncAnimation.html#matplotlib.animation.FuncAnimation) 通过反复调用函数*func*制作动画。

[ArtistAnimation](https://matplotlib.org/api/_as_gen/matplotlib.animation.ArtistAnimation.html#matplotlib.animation.ArtistAnimation): 动画使用一组固定的Artist对象。

然而,在这两者中, FuncAnimation 是最方便使用的一个。你可以在文档中读到更多关于它们的内容,因为我们将只关注FuncAnimation工具。

要求

  • 应该安装包括numpymatplotlib的模块。
  • 要将动画保存为 mp4 或 gif,需要安装[ffmpeg](https://www.ffmpeg.org/)[imagemagick](https://sourceforge.net/projects/imagemagick/files/)

一旦准备好了,我们就可以开始制作 Jupyter 笔记本中的第一个基本动画了。这篇文章的代码可以从相关的 Github 库 中获得,或者你可以点击下面的图片在我的活页夹中查看。

基本动画:运动正弦波

让我们使用FuncAnimation创建一个正弦波在屏幕上移动的基本动画。动画的源代码取自 Matplotlib 动画教程。让我们首先看看输出,然后我们将分解代码,以了解在引擎盖下发生了什么。

  • 在第(7–9)行中,我们简单地创建了一个图形窗口,图形中只有一个轴。然后我们创建我们的空行对象,它实际上是动画中要修改的对象。稍后将使用数据填充线对象。
  • 在第(11–13)行,我们创建了init函数来制作动画。init 函数初始化数据并设置轴限值。
  • 在第(14–18)行中,我们最终定义了动画函数,该函数将帧数(I)作为参数,并创建一个正弦波(或任何其他动画),该正弦波根据 I 的值移动。该函数在此返回一个已修改的绘图对象元组,该元组告诉动画框架应该对绘图的哪些部分进行动画处理。
  • 在第 20 行中,我们创建了实际的动画对象。blit参数确保只重新绘制那些已经改变的图形。

这是在 Matplotlib 中创建动画背后的基本直觉。只要对代码稍加修改,就可以创建有趣的可视化效果。让我们来看看其中的一些

越来越大的线圈

类似地,在 GeeksforGeeks 也有一个很好的创建形状的例子。现在让我们在 matplotlib 的animation 类的帮助下,创建一个慢慢展开的动圈。代码与正弦波图非常相似,只是稍有调整。

实时更新图表

在绘制股票数据、传感器数据或任何其他与时间相关的数据等动态量时,实时更新图表非常方便。我们绘制了一个基础图,随着更多的数据输入系统,该图会自动更新。这个例子摘自send ex。一定要访问这个 youtube 频道,看一些很棒的教程。

让我们绘制一家假设公司一个月内的股价。

现在,打开终端并运行 python 文件。您将获得如下图所示的图表,该图表会自动更新如下:

这里的间隔是 1000 毫秒或 1 秒。

3D 绘图上的动画

创建 3D 图形是很常见的,但是如果我们可以将这些图形的视角制作成动画呢?这个想法是改变相机的视角,然后使用每一个结果图像来创建一个动画。在Python 图库有一个很好的部分专门讨论这个问题。

在笔记本所在的目录下创建一个名为 volcano 的文件夹。所有的图像都将存储在这个文件夹中,然后将在动画中使用。

这将在火山文件夹中创建多个 PNG 文件。现在,使用 ImageMagick 将它们转换成动画。打开“终端”并导航到 Volcano 文件夹,然后输入以下命令:

convert -delay 10 Volcano*.png animated_volcano.gif

使用赛璐珞模块的动画

赛璐珞是一个 Python 模块,简化了在 matplotlib 中创建动画的过程。这个库创建一个 matplotlib 图形,并从中创建一个Camera。然后,它重复使用图形,并在每一帧创建后,用相机拍摄快照。最后,用所有捕获的帧创建一个动画。

装置

pip install celluloid

这里有几个使用赛璐珞模块的例子。

最小的

支线剧情

传说

包裹

动画有助于突出视觉化的某些特征,否则用静态图表很难传达。话虽如此,记住不必要的和过度的观想有时会使事情复杂化也是很重要的。数据可视化中的每一个特性都应该被明智地使用,以产生最佳效果。

Anime2vec:一个序列推荐系统

原文:https://towardsdatascience.com/anime2vec-a-sequence-recommender-1e0a3e558c44?source=collection_archive---------28-----------------------

从 skipgram 模型中提取嵌入

Source: Exploiting Similarities among Languages for Machine Translation paper.

在这篇文章中,我将向你展示如何实现一个简单的 word2vec 或 Anything2vec 的变体,以便拥有一个基于项目的推荐系统。

让我们从我们的数据开始,为了创建一个推荐器,我们需要几个项目,一些用户和一个隐式或显式的反馈。在这里,我们有动漫,有用户,也有他们的评分。

我们将重新设计我们的数据,以便它可以被序列模型接收。为此,我们将创建一个数组列表来表示用户的观察列表。

print(data[:10])[array([39, 20,  2, 36, 13, 18, 73, 31, 78, 68, 80, 54, 62, 60, 64, 27, 52,
         3, 84, 29, 17, 35, 12, 63,  8], dtype=int64),
 array([73,  7, 51, 62, 33,  1, 35, 30, 10, 80,  2], dtype=int64),
 array([28,  2, 61, 15, 89, 14, 26,  7,  1, 32, 57,  6], dtype=int64),
 array([77, 88, 12,  8,  2, 14, 19, 10, 47,  6,  4], dtype=int64),
 array([24,  1,  8, 88, 14, 12,  2,  6, 47, 10], dtype=int64),
 array([54,  3, 33, 45, 35,  4, 19, 30,  6,  2, 10], dtype=int64),
 array([52, 84, 50,  3, 14, 27, 64, 69, 80, 32,  4], dtype=int64),
 array([25, 22,  1, 17, 46, 35, 80,  4, 47,  3, 26], dtype=int64),
 array([77, 52, 74, 45, 17, 19,  8,  2, 88, 67,  5,  9, 11,  6,  1,  4, 14,
        22, 47, 26, 29], dtype=int64),
 array([38, 36, 83, 85, 31, 42, 53, 58, 13, 23, 56, 65, 39, 72, 37, 74, 70,
        76,  7, 33, 66, 50, 54, 59, 64, 51, 49, 21,  5,  3, 45, 73, 24, 11,
        89, 84, 12, 48, 71,  9,  2,  1, 14, 19, 17, 80,  6,  4, 26],
       dtype=int64)]

然后我们将定义我们的 SkipGram 模型

直觉

给定一组顺序数据,SkipGram 模型将循环遍历序列的每个 ,并尝试使用上下文(固定窗口大小中当前项的每个邻居)来预测当前项。通过这个过程,我们将训练一个简单的神经网络,该网络有一个单独的隐藏层作为分类任务。输出是一个 softmax 层,它返回给定上下文的每个项目成为当前项目的概率分布。在训练过程中,每个权重都会更新,我们将提取隐藏层的权重,即 项向量 。在我们的例子中,简而言之,该算法将试图找到给定的上一部 k 和下一部 k 的理想动画。

然后我们将定义一个生成器函数来提供数据。

让我们实例化一些参数。

让我们训练我们的模型,提取一个形状的嵌入(len(unique_anime),200)。

最后,通过嵌入,我们可以提取一些项目-项目相似性。

Nearest to - Clannad:
	Angel Beats ,
	School Days,
	Suzumiya Haruhi no Shoushitsu,
	Suzumiya Haruhi no Yuuutsu 2009 ,
	Code Geass Hangyaku no Lelouch R2,

Nearest to - Mononoke Hime:
	Majo no Takkyuubin,
	Sen to Chihiro no Kamikakushi,
	Hotaru no Haka,
	Samurai Champloo,
	Howl no Ugoku Shiro,

Nearest to - Hajime no Ippo:
	Hajime no Ippo New Challenger,
	Great Teacher Onizuka,
	Monster,
	One Outs,
	Hunter x Hunter 2011 

为了获得一些见解,我们可以通过降维算法展示更多的嵌入,通过传递 2 个组件,我们可以在 2D 图中绘制部分相似性。

最后

在这篇文章中,我采用了一个基于动画的 skipgram 模型,这篇文章的结果仅来自于对一个样本的训练,并且是可完善的。代码可用[here](https://github.com/AlexWarembourg/Medium/blob/master/SkipGramModel.ipynb)。为了改进这个模型,我们可以用丰富的数据训练我们的模型,然后创建一个用户配置文件,以便将我们基于项目的系统转换为定制系统,我将在另一篇文章中重点讨论这一部分。

5 个简单步骤中的关联矩阵注释热图

原文:https://towardsdatascience.com/annotated-heatmaps-in-5-simple-steps-cc2a0660a27d?source=collection_archive---------6-----------------------

热图是数据的图形表示,其中数据值用颜色表示。也就是说,它使用颜色向读者传达一个价值。当您拥有大量数据时,这是一个很好的工具,可以帮助受众了解最重要的领域。

在本文中,我将指导您通过 5 个简单的步骤创建自己的带注释的关联矩阵热图。

  1. 输入数据
  2. 创建相关矩阵
  3. 设置遮罩以隐藏上面的三角形
  4. 在 Seaborn 创建热图
  5. 导出热图

您可以在我的 Jupyter 笔记本中找到这篇文章的代码,该笔记本位于这里。

1)导入数据

df = pd.read_csv(“Highway1.csv”, index_col = 0)

该高速公路事故数据集包含汽车事故率(以每百万英里事故数表示)以及几个设计变量。关于数据集的更多信息可以在这里找到。

2)创建相关矩阵

corr_matrix = df.corr()

我们用.corr创建相关矩阵。注意,htype 列没有出现在这个矩阵中,因为它不是数字。我们需要虚拟化 htype 来计算相关性。

df_dummy = pd.get_dummies(df.htype)
df = pd.concat([df, df_dummy], axis = 1)

此外,请注意,相关矩阵的上半部分三角形与下半部分三角形对称。因此,我们的热图不需要显示整个矩阵。我们将在下一步隐藏上面的三角形。

3)设置蒙版隐藏上面的三角形

mask = np.zeros_like(corr_matrix, dtype=np.bool)
mask[np.triu_indices_from(mask)]= True

我们来分解一下上面的代码。np.zeros_like()返回与给定数组具有相同形状和类型的零数组。通过传入相关矩阵,我们得到一个如下的零数组。

dtype=np.bool参数覆盖了数据类型,所以我们的数组是一个布尔数组。

np.triu_indices_from(mask)返回数组上部三角形的索引。

现在,我们将上面的三角形设置为真。

mask[np.triu_indices_from(mask)]= True

现在,我们有了一个可以用来生成热图的遮罩。

4)在 Seaborn 创建热图

f, ax = plt.subplots(figsize=(11, 15)) heatmap = sns.heatmap(corr_matrix, 
                      mask = mask,
                      square = True,
                      linewidths = .5,
                      cmap = ’coolwarm’,
                      cbar_kws = {'shrink': .4, 
                                ‘ticks’ : [-1, -.5, 0, 0.5, 1]},
                      vmin = -1, 
                      vmax = 1,
                      annot = True,
                      annot_kws = {“size”: 12})#add the column names as labels
ax.set_yticklabels(corr_matrix.columns, rotation = 0)
ax.set_xticklabels(corr_matrix.columns)sns.set_style({'xtick.bottom': True}, {'ytick.left': True})

为了创建我们的热图,我们传递步骤 3 中的关联矩阵和步骤 4 中创建的掩码,以及定制参数,使我们的热图看起来更好。如果您有兴趣了解每一行是做什么的,这里有参数的描述。

#Makes each cell square-shaped.
square = True,
#Set width of the lines that will divide each cell to .5
linewidths = .5,
#Map data values to the coolwarm color space
cmap = 'coolwarm',
#Shrink the legend size and label tick marks at [-1, -.5, 0, 0.5, 1]
cbar_kws = {'shrink': .4, ‘ticks’ : [-1, -.5, 0, 0.5, 1]},
#Set min value for color bar
vmin = -1, 
#Set max value for color bar
vmax = 1,
#Turn on annotations for the correlation values
annot = True,
#Set annotations to size 12
annot_kws = {“size”: 12})
#Add column names to the x labels 
ax.set_xticklabels(corr_matrix.columns)
#Add column names to the y labels and rotate text to 0 degrees
ax.set_yticklabels(corr_matrix.columns, rotation = 0)
#Show tickmarks on bottom and left of heatmap
sns.set_style({'xtick.bottom': True}, {'ytick.left': True})

5)导出热图

现在您已经有了热图,让我们将其导出。

heatmap.get_figure().savefig(‘heatmap.png’, bbox_inches=’tight’)

如果你发现你有一个非常大的热图不能正确导出,使用bbox_inches = ‘tight’来防止你的图像被切掉。

感谢阅读!请在下面的评论中分享你用数据制作的热图。

如何增强 Matplotlib 图

原文:https://towardsdatascience.com/annotating-bar-charts-and-other-matplolib-techniques-cecb54315015?source=collection_archive---------12-----------------------

Photo by Adeolu Eletu on Unsplash

眼睛是我们最重要的器官,因为我们通过视觉感知大约 80%的印象。毫不奇怪,可视化是我们收集和分析信息的最简单的方法。当谈到数据科学时,各种各样的图表帮助我们理解不同复杂性的问题。它们允许我们识别数据中的模式、关系和异常值。因此,无论我们想要分析什么数据,数据可视化都是至关重要的第一步。当使用 Python 时,M atplotlib 和相应的插件如 seaborn 是快速实现这一点的首选工具。

在本文中,我想向您展示一些技巧来增强和丰富您的 matplolib 数字。最重要的是,我为您提供了一种注释各种条形图的好方法。

感兴趣吗?所以让我们开始吧!

先决条件

按照这个例子,你需要 Python 3.7+和 M atplotlib 、 pandas 和 seaborn 。一如既往,我推荐使用poem来管理您的 Python 包和环境。你可以查看这篇文章了解如何设置它。作为一种快捷方式,我建议使用 pip 或 pipx 将其安装在您的机器上。

作为提醒,我们首先要从样本数据中创建条形图 图表而不需要进一步的样式化。本文的目标是增强和丰富这些图表。你可以在我的 GitHub 资源库 上找到所有的示例代码。

设置

首先,我们创建一个名为 nice-plots 的诗歌项目,在这里我们实现了示例并添加了必要的包

poetry new nice-plots
cd nice-plots
poetry add pandas matplotlib seaborn
touch nice_plots/bar_charts.py

现在我们有了一个独立的 Python 环境,安装了我们需要的所有东西。太好了,我们可以开始工作了!

数据

作为数据,我们使用著名的鸢尾花数据集。幸运的是,这是 seaborn 直接提供的。为了创建“有意义的”条形图,我首先使用 平均值 作为聚合函数,按照对数据集进行分组。根据这些数据,我创建了四个不同的条形图,分别是 垂直条形图水平条形图 两个版本的 正常-堆叠版本 。在代码中,这看起来像

***import** seaborn **as** sns
**import** os **from** dataclasses **import** dataclass
**import** pandas **as** pd
**import** matplotlib.pyplot as plt
**import** matplotlib
**from** typing **import** *sns.set()
**# BLOCK 1
# BLOCK 2
# BLOCK 4
# BLOCK 6**data = sns.load_dataset(**"iris"**).groupby(**'species'**).mean()
fig, axes = plt.subplots(2,2)
data.plot.bar(ax=axes[0][0]) 
data.plot.bar(stacked=True, ax=ax[0][1])
data.plot.barh(ax=axes[1][0])
data.plot.barh(stacked=True, ax=ax[1][1])
**# BLOCK 3
# BLOCK 5
# BLOCK 7**plt.show()*

我添加了注释 # BLOCK N ,其中我向前引用了下面的增强功能。我希望这不会太令人困惑。我还添加了稍后需要的所有导入。

由于您可能不会坐在电脑前,下面是最终的条形图

嗯,不太好,对吧?我想努力让它们变得更好是值得的。

提高

图形和字体大小

看这些图表时,第一件显而易见的事情是,与图中的其他部分相比,它们太小了。有几种方法可以改变这种情况。我更喜欢 从 pyplot 设置全局 rcParams。全局意味着它们适用于你创建的所有人物,而不仅仅是某个特定人物。要更改图形大小和某些字体大小,您只需

***# BLOCK 1
def** set_sizes(fig_size:*Tuple[int,int]*=(9, 6), *font_size:int*=10):
    plt.rcParams["figure.figsize"] = fig_size
    plt.rcParams["font.size"] = font_size
    plt.rcParams["xtick.labelsize"] = font_size
    plt.rcParams["ytick.labelsize"] = font_size
    plt.rcParams["axes.labelsize"] = font_size
    plt.rcParams["axes.titlesize"] = font_size
    plt.rcParams["legend.fontsize"] = font_sizeset_sizes((12,8), 10)*

运行这个会产生

这已经比以前好多了。但仍有改进的余地。

旋转刻度标签

垂直文本,就像水平条形图的 x 刻度标签,对我来说没有吸引力。除此之外,这种竖排文字还浪费了大量的图形空间。为了解决这个问题,Matplotlib 提供了一种简单的方法来通过

***# BLOCK 2**
**def** rotate_xticks(ax: matplotlib.axes, degrees : *float* = 45):
    ax.set_xticklabels(ax.get_xticklabels(), rotation=degrees)**# BLOCK 3**
rotate_xticks(ax=axes[0][0],0)
rotate_xticks(ax=axes[1][0],0)*

由于将 x 轴旋转 45 度是很常见的,所以我将其设为默认值。然而,在这个例子中,水平打印标签最有意义。可以通过将设置为 0 来实现。

我的机器上产生的输出看起来像

注释条形图

条形图非常适合快速直观地了解不同组之间的比较情况。然而,我们可能不仅对相对比较感兴趣,还想知道相应的绝对值。我们可以通过用各自的值注释每个条来实现这两个目标。

为此,我创建了一个类 AnnotateBars ,这个类允许您在堆叠和非堆叠版本中注释垂直和水平条形图

***# BLOCK 4
#Alias types to reduce typing, no pun intended** 
Patch = matplotlib.patches.Patch
PosVal = Tuple[float, Tuple[float, float]] 
Axis = *matplotlib.axes.Axes
PosValFunc = Callable[[Patch], PosVal]*@dataclass
**class** AnnotateBars:
    font_size: *int* = 10
    color: *str* = "black"n_dec: *int* = 2 **def** horizontal(**self**, ax: *Axis,* centered=False):
        **def** get_vals(p: Patch) -> PosVal:
            value = p.get_width()
            div = 2 **if** centered **else** 1
            pos = (
                p.get_x() + p.get_width() / div,
                p.get_y() + p.get_height() / 2,
            )
            **return** value, pos
        ha = "center" **if** centered **else**  "left"
        **self**._annotate(ax, get_vals, ha=ha, va="center") **def** vertical(**self**, ax: *Axis,* centered:*bool*=False):
        **def** get_vals(p: Patch) -> PosVal:
            value = p.get_height()
            div = 2 **if** centered **else** 1
            pos = (p.get_x() + p.get_width() / 2,
                   p.get_y() + p.get_height() / div
            )
            **return** value, pos
        va = "center" **if** centered **else** "bottom"
        self._annotate(ax, get_vals, ha="center", va=va) **def** _annotate(**self**, ax, func: *PosValFunc*, **kwargs):
        cfg = {"color": **self**.color, 
               "fontsize": **self**.font_size, **kwargs}
        **for** p **in** ax.patches:
            value, pos = func(p)
            ax.annotate(f"{value:.{**self**.n_dec}f}", pos, **cfg)*

Puh,代码很多但是不用担心,我指导你怎么用。

首先,您需要创建一个 AnnotateBars 的实例。您可以指定字体大小、文本颜色以及应该打印的小数位数。所有这些参数都有合理的默认值。

接下来,您需要调用垂直水平,这取决于您想要注释的条形图的类型。对于这些函数,您需要传递包含相应条形图的轴对象。此外,它们接受一个名为的附加参数,以为中心。这样,您就可以确定注释是打印在工具栏的中心还是顶部/右侧。当您使用堆积条形图时,这尤其有用。

说得够多了,让我们利用这个类,用不同的配置来注释我们的四个条形图

***# BLOCK 5**
AnnotateBars().vertical(axes[0][0])
AnnotateBars(color="blue").vertical(axes[1][0], True)
AnnotateBars().horizontal(axes[0][1])
AnnotateBars(font_size=8, n_dec=1).horizontal(axes[1][1], True)*

这是结果输出图表

现在我们更聪明了,不仅知道关系,还知道绝对值。厉害!

顺便提一下,当我们在堆积条形图中有非常小的条形时,叠加值就成了一个问题。你可以从堆叠的 Setosa 图表中看到这一点。在这种情况下,你必须选择是接受还是要求不同的东西。

保存绘图

最后,当你创作出令人自豪的精彩情节时,你可能想与你的同事分享。为此,您必须以 PNG 这样的格式存储您的绘图,以便于分发。尽管将数字转储到图像的语法相当简单,但我很容易忘记它。这就是我使用这个助手函数的原因

***# BLOCK 6
def** save_figure(fig : *matplotlib.figure.Figure*, path : *str*):
    folder = os.path.dirname(path)
    **if** folder:
        os.makedirs(folder, exist_ok=True)
    fig.savefig(path, bbox_inches="tight")*

你只需要把它的一个 图对象路径 传递到输出的图像文件中。如果您想要存储图像的文件夹不存在,该功能会自动为您创建一个。对我来说,这是非常方便的。让我们添加这最后一块代码,我们就完成了

***# BLOCK 7**
save_figure(fig, "./plots/medium/bar-charts.png")*

这就是我如何创造了你们之前看到的所有情节。我肯定是自己吃狗粮的:)!

包裹

在本文中,我向您展示了几个 Matplotlib 函数来增强您的绘图。最重要的是,我向您展示了一种注释各种条形图的好方法。

感谢您关注这篇文章。一如既往,如有任何问题、意见或建议,请随时联系我。密谋愉快!

命名实体识别中的标注者偏差和不完整标注(NER)

原文:https://towardsdatascience.com/annotator-bias-and-incomplete-annotations-for-named-entity-recognition-ner-84819af730?source=collection_archive---------32-----------------------

介绍 2019 年发表的两篇论文,涉及命名实体识别的不完全标注(NER)

Photo by Alvaro Reyes on Unsplash

我们知道深度学习(DL)的兴起离不开带注释的数据。换句话说,正是那些注释者让 DL 发展的如此之快。但他们也是人,他们有自己的注释习惯,也会犯错误。在本帖中,我将介绍一些有趣的论文。一篇论文是关于注释者的偏见,两篇论文是关于命名实体识别的不完整注释(NER)。

em NLP-2019/11-我们是对任务建模还是对注释器建模?自然语言理解数据集中标注者偏差的研究

这篇文章的出发点相当有趣。外包标注任务在业内很常见。我们可能关注注释的质量,但是很少关注注释者的偏见。注释者偏差意味着每个注释者都有自己标记数据的习惯,他们会给数据带来这样的偏差。本文表明注释者的偏见会影响模型的性能。如果在训练期间输入注释者标识符作为特征,模型将学习注释者的习惯并训练一个更健壮的模型。另一个有趣的发现是,模型不能很好地概括来自对训练集没有贡献的注释者的例子。具体来说,如果模型不能从训练集中学习注释者的习惯,它就不能很好地推广到测试集中。一个建议是,当我们注释数据集时,一个注释器应该同时注释训练集和测试集。

NAACL-2019/06-对命名实体识别的不完整注释进行更好的建模

注释者也是人,人也会犯错。注释数据不可能总是完美的。对于这种情况,我们必须找出如何更好地学习不完善的标注数据。这两篇论文是为 NER 任务学习这样的数据。

上图显示了不完整的注释示例。为了更好地对不完整标注建模,作者提出了一种新的损失函数。

为了对不完全标注建模,作者引入了一种新的概率分布 q 来表示所有可能的标注。

这个想法在上图的右下角。通过引入 q 分布,该模型可以考虑不完整标签的所有可能路径。

如何学习 q 分配?

作者提出了两种方法,硬方法和软方法。在硬方法中,所得的 q 分布是将概率 1 分配给单个完整标签序列的折叠分布,而在软方法中,每个可能的标签序列将得到某个概率分数。

EMNLP-2019/11-CrossWeigh:从不完善的注释中训练命名实体标记器

NER 存在两种标签错误:(1)测试集中的错误会干扰评估结果,甚至导致对模型性能的不准确评估;以及(2)训练集中的错误会损害 NER 模型训练。

来解决第一个问题。在本文中,他们纠正了测试集中的错误,以形成更清晰的基准,并开发了一个新颖的框架来处理训练集中的错误。他们纠正了 CoNLL03 NER 数据集的 5.38%标签错误测试句子。它表明,模型性能在更干净的测试数据集上有所提高。

为了解决第二个问题,他们提出了一个交叉权重框架来更好地处理标签错误。这个框架包含两个部分。

  • 错误估计:通过交叉检查过程识别训练数据
    中潜在的标签错误。
  • 错误重新加权:在最终 NER 模型的训练过程中,它降低了这些实例的权重。交叉校验过程受 k 重交叉验证的启发;不同的是,在每个文件夹的训练数据中,它会删除包含该文件夹中出现的任何实体的数据。

查看我的其他帖子 一分类查看
GitHub:
bramble Xu LinkedIn:徐亮 博客:bramble Xu

参考

  • https://arxiv.org/pdf/1908.07898.pdf
  • https://www.aclweb.org/anthology/N19-1079
  • https://arxiv.org/pdf/1909.01441.pdf

公告:TensorFlow 2.0 已经到来!

原文:https://towardsdatascience.com/announcement-tensorflow-2-0-has-arrived-ee59283fd83a?source=collection_archive---------14-----------------------

几个月前,我提到了 TensorFlow 2.0 中将包含的一些激动人心的新功能。

你猜怎么着?今天(撰写本文时)TensorFlow 2.0 Alpha 预览包正式发布,并在官网更新了文档!

我对此感到非常兴奋和激动,迫不及待地想和你们分享这个!!

要了解 TensorFlow 以前的一些用例以及 TensorFlow 2.0 中的一些变化,请查看下面的短视频:

What’s New in TensorFlow 2.0 by Paige Bailey (Developer Advocate)

TensorFlow 2.0 中的一些新功能

即使 Tensorflow 2.0 仍处于预览版,但我们可以开始尝试 TensorFlow 1.x 之后期待已久的一些最酷的功能。

相信我。学习和使用 TensorFlow 2.0 的易用性会让你大吃一惊,尤其是对于初学者。

TensorFlow 2.0 专注于简单易用,拥有急切执行、直观的高级 API 和在任何平台上灵活构建模型等更新。

TensorFlow 2.0 中有多个变化,使 TensorFlow 用户更有效率。在下一节中,我将简要概述使 TensorFlow 2.0 使用起来更加直观和高效的两个主要变化。

要了解 TensorFlow 2.0 中有哪些内容,可以查看 TensorFlow 团队发布的中型文章,或者 TensorFlow 官方网站上的摘要。

或者,你也可以观看由 aurélien géRon(aurélien géRon)创建的这个视频(附在下面),他是用 Scikit-Learn 和 TensorFlow 进行机器学习的作者。我最喜欢视频的一点是,他除了提到 TensorFlow 2.0 的一些重大变化外,还对比了 Pytorch 和 TensorFlow 2.0 的区别。

TensorFlow 2.0 Changes by Aurélien Géron

1.急切的执行

  • 默认情况下启用快速执行,TensorFlow 操作现在会立即被评估并返回它们的值,而不构建图形
  • 由于没有计算图形要构建并在随后的会话中运行,所以很容易使用 print()或调试器检查结果
  • 评估、打印和检查张量值不会中断计算梯度的流程
  • TensorFlow 2.0 急切地执行(就像 Python 通常做的那样),在 2.0 中,图形和会话应该感觉像实现细节。

2.函数,而不是会话

让我们面对现实吧。

在用我们的张量流图进行任何计算之前,我们需要调用会话,这一直是我们头疼的问题。

TensorFlow 2.0 就是为了解决这个问题而诞生的。

因为session.run()调用几乎类似于函数调用:您指定输入和要调用的函数,然后您得到一组输出。

在 TensorFlow 2.0 中,您可以使用一个名为tf.function()的装饰器,这样您就可以自动定义一个 TensorFlow 函数,以 TensorFlow 操作图的形式运行计算,带有命名参数和显式返回值。

换句话说,您可以使用自然的 Python 语法编写图形代码,同时能够以简洁的方式编写渴望风格的代码,并使用 tf.function 将其作为张量流图形运行。

最后的想法

Wonderful Google office tour in Singapore

感谢您的阅读。

这么多激动人心又人性化的功能,真的很期待 TensorFlow 2.0 的最终版本。

同时,如果您有兴趣了解 TensorFlow 2.0 的最新发展,您可以随时订阅邮件列表或在此加入社区!

一如既往,如果您有任何问题或意见,请随时在下面留下您的反馈,或者您可以随时通过 LinkedIn 联系我。在那之前,下一篇文章再见!😄

关于作者

Admond Lee 目前是东南亚排名第一的商业银行 API 平台Staq的联合创始人/首席技术官。

想要获得免费的每周数据科学和创业见解吗?

加入 Admond 的电子邮件简讯——Hustle Hub,每周他都会在那里分享可行的数据科学职业建议、错误&以及从创建他的初创公司 Staq 中学到的东西。

你可以在 LinkedIn 、 Medium 、 Twitter 、脸书上和他联系。

** [## 阿德蒙德·李

让每个人都能接触到数据科学。Admond 正在通过先进的社交分析和机器学习,利用可操作的见解帮助公司和数字营销机构实现营销投资回报。

www.admondlee.com](https://www.admondlee.com/)**

宣布现实项目

原文:https://towardsdatascience.com/announcing-the-reality-project-e16cc71abb64?source=collection_archive---------28-----------------------

Sunrise from the International Space Station (Source)

用数据减少对世界的误解

当你放下报纸,关掉电视,决定看看关于这个世界的实际统计数据,而不是依赖别人告诉你的,奇怪而美妙的事情就会发生。当你意识到新闻一直灌输给你的世界观——世界正在走下坡路——是基于几乎每一个事实衡量标准的,与现实完全相反时,你脚下的地面开始移动。一旦我们看了关于财富、健康、人权和环境保护等主题的数据,我们别无选择,只能得出这样的结论在有记录的历史的大部分时间里,世界一直处于上升轨道,我们生活在人类文明有史以来最好的时代,而且这种改善没有停止的迹象。

在过去的五年里,随着我慢慢戒掉令人衰弱的新闻瘾,我经历了只能被描述为我大脑中世界观生成软件的更新。通过数万页书、百万个数据点、无数图表,我对世界是黑暗危险之地、人性是邪恶力量的看法发生了逆转。根据这些数据,世界的故事发生了逆转:人类的历史不是衰落的历史,而是持续到今天的逐渐上升的历史

我一开始并没有打算成为一个乐观主义者,但长期积极的观点是基于事实审视世界的必然结论。

随着新的一年的开始,现在我已经吸收了足够多的独立数据来源可以确信 现实真的比我们想象的好 ,我开始了现实项目,这是一个数据驱动的努力,通过一系列的每周文章来呈现世界。声明的目标是通过数据减少对世界的误解,消除我们扭曲的世界观。如果在这个过程中,这些数据碰巧让你对人性有了更乐观的看法,那么就把它当作一个有益的副作用。

现实项目第一篇《消失的穷人》在这里。你可以在这里找到在现实项目中发表的所有文章。

现实项目基础

每周,我都会写一些关于我们世界不同方面的统计数据,这些数据是根据我最初最错误的观点挑选出来的。这些将涵盖从环境到民主到核武器的主题——如果人类参与其中并且有可靠的数据,它就属于这一范围,尽管重点通常是大局而不是日常细节。文章将会很短,内容丰富,每一条数据都必须经过独立消息来源的确认,才能成为现实项目。

首先,我想澄清的是,我并不声称自己垄断了真相。我知道数据会受到收集和报告数据的人的偏见的影响。然而,仅仅是我们可能被证明是错误的,并不是阻止我们努力获得真相的理由。科学,进而人类,通过收集数据、质疑理论和抛弃不再有数据支持的观点的过程而进步。我的信念从来不是一成不变的,当证据发生变化,或者当我发现数据与我现有的想法相矛盾时,它不会被压制而是被报告!

这个项目忠于一个想法:我们应该依靠证据——数据——而不是观点。现实项目与新闻的区别在于,当世界观与现实不符时,人们愿意推翻它们。

为什么这很重要

减少对世界的误解不仅仅是一个虚荣的项目。我以事实为基础的世界观已经让我的生活方式变得更好,我相信准确的世界观对社会至关重要。在这次世界观软件升级之前,我从来没有志愿或捐助过慈善事业,理由很简单:这个世界是一个可怕的地方,你必须自己照顾自己,总会有穷人/病人/受压迫者/饥饿者,所以试图改变是没有用的。

了解世界真实状况的一个最重要的影响是看到世界范围内的努力在减少贫困、扩大人权和根除疾病等领域取得了压倒性的成功。这些项目产生了影响,并证明人们一起行动可以在全球范围内减少有意识生命的痛苦。

事实表明,试图改善自己的邻里关系甚至整个世界 并非徒劳

这种认识触动了我的大脑:不花时间或金钱让世界变得更美好是不可原谅的。联合国、非营利组织,是的,甚至个人志愿者,都为人类的繁荣做出了贡献。你所做的每一点工作可能看起来无关紧要,但累积起来,直到我们生活在这样一个世界:自 1990 年以来,超过 10 亿人摆脱了极端贫困,接种疫苗的儿童人数超过 85%。

简而言之,正如发现大脑的可塑性让你意识到你可以更好地改变你的习惯(在人生的任何阶段),采取数据驱动的世界观意味着看到人类作为一个整体是有能力改善的。人们认为阅读新闻是公民的义务,但直到我开始阅读事实,我才开始以一种有意义的方式做出贡献。那些错误地认为世界正在变得更糟的人可能并不在那些真正让世界变得更好的人之列。

减少错误的资源

如果我们想采用基于事实的世界观,那么我们需要一些事实。幸运的是,对于那些希望减少对世界的误解的人来说,现在有比以往更多的数据资源(通常是免费的)。如果你想改变一个新闻习惯(证据表明我们并没有改掉坏习惯,而是用好习惯来代替它们)或者只是核实事实,那么就从这些开始:

  1. 我们的数据世界:可视化、原始数据、深度分析——你可以在这个综合资源中找到所有这些,它汇集了来自许多来源的数据。
  2. Gapminder . org:Gapminder 基金会是一个致力于通过帮助社会采用基于事实的世界观来改善世界的组织。至少,参加 Gapminder 测试来评估你的世界知识。
  3. 世界银行开放数据:如果你喜欢你的数据直接来源,这是获得它的地方。通过在线图表或下载数据来浏览数据。
  4. 汉斯·罗斯林著 《真实性:我们对世界误解的十个原因——以及为什么事情比你想象的好》 》(此处有很好的评论):一本通俗易懂的书,解释了我们为什么不了解这个世界,以及该如何应对。这是一种阅读的乐趣,也是一个基于事实的世界观的良好起点。
  5. 理性的乐观主义者:繁荣如何演变马特·里德利著:解释是什么推动了人类进步繁荣增加。
  6. 我们本性中更好的天使:为什么暴力减少了 史蒂芬·平克(好概述)和 现在的启蒙:理性、科学、人文主义和进步 史蒂芬·平克(精彩播客在此):这些都是宏伟的作品,将从根本上改变你对世界的看法。它们总共由 1000 多页经过严格研究的统计数据、图表和故事组成,不仅展示了为什么我们生活在人类历史上最和平的时代,也展示了为什么我们生活在人类文明最好的时代。

这些只是一小部分展示真实世界数据的网站和书籍。在项目过程中会提供额外的资源,我一直在寻找更多的建议。

结论

现实项目将是一周一次的系列文章,致力于呈现基于事实的世界图景,目的是用数据减少对世界的误解。每周我们将探索一个不同的主题,涵盖人类活动的整个范围。这个项目是从我的“启蒙”中产生的,当我开始把我的世界观建立在事实而不是通过新闻告诉我的基础上。虽然目的不是让你更乐观,但这可能是减少对世界的误解的不可避免的副作用。

有许多个人和机构在我的旅程中指导过我,并将在整个现实项目中与我们在一起。其中最突出的是令人难以置信的已故的汉斯·罗斯林,他把传播以数据为中心的世界观作为自己的目标,进而努力确保事情继续变得更好。他的工作由他的妻子和 Gapminder 基金会(T21)继续。我想给你们留下一段他的签名视频,这是我走出黑暗之路的许多灵感之一。

一如既往,我欢迎反馈,建设性的批评,并在整个现实项目中积极鼓励不同意见。我只要求反驳植根于数据。可以通过 Twitter @koehrsen_will 找到我。

宣布 tidyUSDA:一个用于处理 USDA 数据的 R 包

原文:https://towardsdatascience.com/announcing-tidyusda-an-r-package-for-working-with-usda-data-6066fa830f0a?source=collection_archive---------31-----------------------

我很自豪地宣布一个 R 包的发布,它治愈了我个人的一个痒处:提取并使用美国农业部的数据,特别是来自 NASS 的快速统计数据。tidyUSDA 是实现这一目的的最小软件包。以下是从包装上剪下来的小片段,可以在这里找到:【https://github.com/bradlindblad/tidyUSDA】

为什么是 tidyUSDA?

为什么我们还需要另一个“整洁”的包装?为什么我必须安装这么多地理空间依赖项?

合理的问题。如果你使用美国农业部的数据,你会知道当你需要时,有时很难找到你需要的东西。大量的数据(2017 年农业普查包括大约 640 万个信息点[1])应该归功于美国农业部,因为这是一项巨大的组织任务。

目前,从以前的农业普查和农业调查中提取数据的最佳方式是通过快速统计门户网站,它允许您在交互式 gui 中应用过滤器,然后下载 CSV 文件。这对于大多数应用程序来说非常有效,但是 R 程序员讨厌以非编程方式提取数据,这就是 tidyUSDA 的用武之地。

编程数据直接从 Quick Stats 中提取 在其核心,tidyUSDA 是一个用于 Quick Stats 数据的 API,允许您在 R 会话中将相同的数据提取到 dataframe 中。

地理空间功能 tidyUSDA 还为您提供了在县或国家级别自动向快速统计数据添加简单要素列的选项。这允许您快速可视化快速统计数据,以便快速迭代或生成报告。

快速启动

首先,按照自述文件部分中的说明安装 tidyUSDA。请注意,如果您使用的是旧版本,您可能需要升级您的 R 版本。

接下来,调用 tidyUSDA 来确保所有东西都正确安装了。

library(tidyUSDA)

美国农业部通过 API 密钥控制对他们数据的访问。您可以按照此链接中的简要说明快速获得免费的 API 密钥。

现在来拉一些数据。

# Use keyring to store your api key 
# key <- keyring::key_get("tidyusda")# Or hard code that thing 
key <- 'abc-123' 

在这一点上,最好使用实际的快速统计网站来挑选出你想要过滤的参数。通过这种方式,您可以确定数据将被返回。我希望看到使用 2017 年人口普查数据的州级运营计数细分。

在这一点上,它有助于了解哪些可能的值您可以输入到函数参数中。您可以使用内置数据集查看所有参数的这些可能输入。让我们来看看几个。

tidyUSDA::allCategory %>% head() 
#> statisticcat_desc1 statisticcat_desc2 
#> "ACCESSIBILITY" "ACCESSIBILITY, 5 YEAR AVG" 
#> statisticcat_desc3 statisticcat_desc4 
#> "ACCESSIBILITY, PREVIOUS YEAR" "ACTIVE GINS" 
#> statisticcat_desc5 statisticcat_desc6 
#> "ACTIVITY" "ACTIVITY, 5 YEAR AVG"

所以看起来对于类别字段只有六个可能的输入值。很高兴知道。

tidyUSDA::allGeogLevel %>% head() 
#> agg_level_desc1 agg_level_desc2 
#> "AGRICULTURAL DISTRICT" "AMERICAN INDIAN RESERVATION" 
#> agg_level_desc3 agg_level_desc4 
#> "COUNTY" "INTERNATIONAL" 
#> agg_level_desc5 agg_level_desc6 
#> "NATIONAL" "REGION : MULTI-STATE"

有许多不同的地理级别。目前只支持为值提供几何图形。

现在我们对可以输入的内容有了一点了解,让我们使用主函数进行数据提取。

# Get count of operations with sales in 2017 
ops.with.sales <- tidyUSDA::getQuickstat(sector=NULL, group=NULL, commodity=NULL, category=NULL, domain=NULL, county=NULL, key = key, program = 'CENSUS', data_item = 'CROP TOTALS - OPERATIONS WITH SALES', geographic_level = 'STATE', year = '2017', state = NULL, geometry = TRUE, lower48 = TRUE)

注意,我设置 geometry = TRUE 是为了包含我们绘图所需的几何特征,我设置 lower48 = TRUE 是为了排除夏威夷和阿拉斯加。

在这一点上,我有一个数据帧,其中包含相当多的数据字段。如果您设置 geometry = TRUE ,您将拥有更多列。快速统计的主要数据点将在“值”字段中。此时,您可以随意过滤数据框中您实际需要的字段。

现在让我们看看基本的 choropleth 图的数据是什么样的。

# Plot this data for each state 
tidyUSDA::plotUSDA(df = ops.with.sales)

好的,哇,看起来这个国家所有的农场都在加利福尼亚。但是等一下,就陆地面积而言,加州很大,农场的相对规模相对较小,所以也许我们应该换个角度来看这个问题。首先,让我们清理数据帧,以便更容易处理。

mydata <- ops.with.sales[,c("NAME", "Value", "ALAND")]

我们选择州名、来自快速统计查询的值(运营次数)和“ALAND”,即以平方米为单位的土地面积。让我们修改我们的数据框架来计算每平方米的操作数,这样状态的大小就不会影响我们想要得到的结果。

mydata$ALAND <- as.numeric(mydata$ALAND) 
mydata$modified_value <- mydata$Value / mydata$ALAND

这给了我们一堆没有意义的非常小的数字,但是对于我们的映射目的来说,它们就够了。

# tidyUSDA::plotUSDA(df = mydata, target_col = 'modified_value') tidyUSDA::plotUSDA(df = mydata, fill_by = 'modified_value')

啊,好多了。现在我们有了一个真实的曲线图,显示了每平方米的操作次数。看起来加州仍然是每块土地上拥有农场最多的州。

原载于 2019 年 9 月 29 日https://technistema.com

全球自杀数据的异常

原文:https://towardsdatascience.com/anomalies-in-global-suicide-data-6ce05ff178b3?source=collection_archive---------31-----------------------

Mental Health Search Interest on Google Trends

每个心理健康意识日(10 月 10 日),在谷歌趋势上对“心理健康”的搜索兴趣都会出现一个峰值。然而,在刚刚过去的 10 月,人们对搜索的兴趣达到了有史以来的最高水平。美国的精神健康正在成为全球话题的一部分——部分是因为它的去污名化,但主要是因为它与技术(最显著的是社交媒体)、国内恐怖主义和毒瘾的相关性。

虽然 kagglers 和非营利组织已经对这一主题进行了大量预先存在的分析,但我希望使用时间序列异常检测技术,从不同的角度研究自杀统计数据集。

世卫组织自杀统计数据

世界卫生组织收集了每个国家的自杀人数,并提供了年龄、年份、国家、世代和性别之间的细分。自杀的数量经常被低估,即使如此,也只占自杀企图的很小一部分。然而,令人印象深刻的是,世卫组织能够以相同的粒度收集 100 多个国家的信息。

Albania subset of WHO suicide data

他们的数据集按照国家、年份、性别和年龄按行进行格式化。当我们将表格转换为每个国家和年份的总量时,我们发现每个国家的报告中存在一些差距。使用 missingno 库,我们可以很容易地可视化任何数据集的无效性。在下图中,每一列都是一个国家,白色方块表示该年的空值。

Nullity of suicide data per country

对于零死亡率高(超过 50%的年份缺失)的国家,我们将其从分析中剔除:这包括波斯尼亚和黑塞哥维那、塞浦路斯、多米尼克、斐济、基里巴斯、澳门、马尔代夫、蒙古等等。对于其余部分,我们将使用均值插补简单地填充缺失的数据(用该国 1985 年至 2016 年的平均自杀率替换空值)。

IMHE,全球疾病负担数据集

健康指标和评估研究所(IMHE)也发布了另一个自杀数据集,用于我们的数据世界:自杀报告。它提供了时间段(1990 年至 2017 年)的自杀指标,每个被调查国家都没有遗漏条目。有了这些完整的数据,他们能够创建一个随时间变化的地图可视化:

异常检测

既然我们已经查看了数据,我们将使用聚类算法来确定哪个国家从 1985 年到 2016 年的自杀率与所有其他国家相比有偏差。为此,我们将每个时间序列(每年 1 个数据点,每个国家 32 个)转换为每个国家 32 长度的向量。由此,我们可以使用基于密度的聚类方法(DBSCAN)来识别异常的时间序列。

通过在 IMHE 数据集上运行同样的聚类,我们得到了相似的结果。在世卫组织数据集中,格陵兰岛与丹麦王国合并在一起,因此它在 IMHE 数据集中仅作为一个单独的国家出现。

我们从 DBSCAN 中确定的异常值似乎属于两种趋势:

#1:正在改善的高自杀率国家。

格陵兰岛因拥有世界上最高的自杀率而臭名昭著,尤其是在当地居民中。2016 年, NPR 甚至录制了一集播客来进一步了解这一现象并与研究人员交流。虽然有许多因素,但许多研究文章将这一现象归因于因纽特人和丹麦文化之间的冲突。最近,《卫报》的一篇文章将精神健康危机与气候变化及其对他们生活方式的影响联系起来。数据显示的自杀率下降可能表明政府的干预正在起作用,尽管这与来自维基百科的这篇文章相矛盾(基于与 Tina Evaldsen 的对话)。

东欧的(俄罗斯、立陶宛等。)高自杀率主要是由 20 世纪 80 年代后半期开始的苏联解体造成的。事实上,自苏联解体以来,约有 80 万俄罗斯人自杀。这一时期的特点是经济危机和国家动乱。幸运的是,随着东欧经济的改善,自杀率也有所下降。

第二:最近自杀率的急剧上升。

苏里南+圭亚那是南美洲的邻国,拥有大量的印度斯坦(东印度)人口。在圭亚那,印度教徒占人口的 40%,但却占了 2010 年至 2013 年间自杀事件的 80%。关键因素可能包括精神疾病在印度文化中的污名、未治疗的创伤或 PTSD。在农村社区,个人可能会被孤立,独自应对心理健康问题。今天,努力的方向是打破围绕精神健康和家庭暴力的沉默。

南韩,自杀是第四大死因。我最初认为自杀在年轻人中会很普遍,但数据显示它实际上主要影响老年人群。

根据 W ikipedia 的说法,这部分人口容易自杀,因为该国一半的老年人生活在贫困线以下。

再加上资金不足的老年人社会安全网,这可能会导致他们为了不成为家庭的经济负担而自杀,因为子女照顾父母的旧社会结构在 21 世纪已经基本消失了。

渗透率突破的异常检测和预测

原文:https://towardsdatascience.com/anomaly-detection-and-forecasting-of-permeate-breakthrough-e79a1cfaf0a9?source=collection_archive---------24-----------------------

在这项工作中,我们评估了各种方法,以预测何时有渗透突破的生化生产过程。自动编码器模型似乎很有前途,但应该与传统的统计过程控制指标相结合,以增加其鲁棒性。

同样,指数移动平均线(EMA)和长短期记忆(LSTM)提供了不同的结果。均线平滑时间序列数据,给出一段时间的趋势。这与 LSTM 相结合,使我们能够对未来的渗透值进行预测。

这个项目的完整代码可以在我的 github repo 中找到。

超滤过程

在食品和生化工业中,使用超滤(UF)是纯化目标产品的关键单元操作。进料进入 UF,根据膜的孔径,大于孔径的物质保留在浓缩液(产品)中,小于孔径的物质进入透过液(废物)

Image courtesy www.crs-reprocessing.com

取决于应用,超滤膜的孔径大约为 10-100 千道尔顿。正因为如此,才有可能分离蛋白质,并通过除去水和盐来增加浓缩物流中蛋白质的浓度,留下感兴趣的产物。

Image courtesy www.synderfiltration.com

然而,随着时间的推移,膜降解,蛋白质进入渗透。由于渗透物是一种废物流,我们实际上是在扔掉我们想要出售的产品!!!

问题陈述

在本项目中,通过分析历史渗透值,目的是检测渗透物突破(渗透物中产品含量高)并在应该更换超滤膜时向工程师提供反馈,从而使生产过程更加可靠并减少产品损失。

换句话说,我们希望开发一种稳健的方法来预测何时出现渗透突破,并预测未来的价值。

方法学

比例渗透数据由位于卡伦堡德纳姆克的诺维信生产工厂提供。

然而,历史突破的时间记录是不一致的。因此,突破的特征将被创造。这四个特征是:

  • mean_value_scaled :从 0-1 缩放的原始渗透值。
  • ema_avg: 均线的平均值 _ 缩放值。
  • 标准:平均值的标准偏差 _ 缩放
  • 目标:1.5σ以上的数值,分为正常(0)和突破(1)

为了检测渗透数据中的异常值(渗透突破),我们评估了:

  • 主成分分析
  • 一个自动编码器型号

为了预测未来渗透值,我们评估了:

  • EMA 的使用
  • 更加精密的T5【LSTM】型号

以下指标用于确定模型的表现如何:

  • 对于异常/异常值检测,我们将使用准确度和 F 值。
  • 对于预测,我们将使用测试集的均方误差(MSE)。

结果

异常值检测

PCA 分析显示正常渗透值(蓝色)和异常值(红色)之间存在差异。

可以看出,97.5 %的方差可以由前两个主成分(PC)来解释。此外,上面的双图显示了前两个主成分的负荷和得分。对于第一台 PC,所有的特性都是正面的。这是合理的,因为如果 mean_value_scaled 增加,则 std 也会随着 ema_avg 增加(过程中有更多变化)。当包含两个 PC 时, ema_avgstd 的相关性更强,但与 mean_value_scaled 的相关性较弱。

每个主成分是一个指向最高方差方向的单位向量(在考虑了早期主成分捕获的方差之后)。权重离零越远,主分量在相应特征的方向上就越多。如果两个特征具有相同符号的较大权重(都是正的或都是负的),那么一个特征的增加会与另一个特征的增加相关联。相比之下,具有不同符号的特征可能会表现出负相关性:一个变量的增加会导致另一个变量的减少。

同样,更先进的自动编码器型号能够在测试集上以 0.9715 的准确度分数、0.8438 的精确度分数和 0.7714 的 F 分数捕获何时出现突破。

黑线是我们认为有突破的目标和标志。蓝色和绿色的线是训练和测试数据集残差。阈值是自动内折器模型识别为异常值的值,在大多数情况下,该值与目标值一致。

以下是自动编码器模型的指标。当您处理一个类不平衡的数据集时,仅准确性并不能说明全部情况,就像这个数据集一样,其中正标签和负标签的数量存在显著差异。因此,我们也将使用 f1 分数,它是精度和召回的平衡。

上面的 autoencoder 给出了比朴素情况好得多的性能(朴素预测器:[准确度分数:0.0543,F 分数:0.0669])。详见我的代号。

预测渗透值

简单的 EMA 在跟踪趋势方面做得很好,但是通常滞后于新数据的移动,如下所示。这一具体分析表明,在使用 EMA 的一个主峰之后,大约需要一年时间才会出现另一个主峰(假设在导致渗透值降低的主峰之后更换膜)。
这实际上比制造商所说的更短,应该接近 2 年。这可能意味着我们需要评估膜的操作和清洁条件,看看这对膜的寿命是否有影响。

LSTM在预测实际渗透值方面表现不佳,但在预测 EMA(如下所示)和标准偏差方面表现出色。与仅使用 EMA 模型相比,这可以用于实现更长期的预测。

未来工作

在这一分析的基础上,还可以做更多的事情。我想到的几个例子是:

  • 不更换膜的机会成本分析。
  • LSTM 在预测未来值的均值和标准差方面做得很好。评估我们是否能重建未来价值的概率可能会很有趣。
  • 应调查梯度的使用或数值之间的%变化。虽然移动平均是一个成功的特征,但考虑到渗透物样品不是以规则的间隔采集的,梯度可以提供更多有用的信息。
  • 评估不同的模型参数:
    —损失函数和优化器
    —激活函数:relu

感谢您的阅读,希望这能激发您对该领域的兴趣。欢迎建设性的反馈,如果您发现代码有问题,您可以在 Github repo 中提出问题。

具有 Reserved.ai 的每日账单的异常检测

原文:https://towardsdatascience.com/anomaly-detection-for-daily-bills-with-reserved-ai-547401218de2?source=collection_archive---------26-----------------------

该项目

这是我和 Reserved.ai 合作的一个项目,用于异常检测。广义地说,异常检测是检测意外或异常数据的任何过程。在这种特殊情况下,Reserved.ai 帮助客户在 AWS 信用上获得更好的交易,因此可以访问他们的日常账单。在一个案例中,有人注意到账单金额突然增加,并提醒了客户。原来,他们的一名工程师部署了一项改变,无意中大幅增加了他们的日常账单。该项目的想法是自动化监控每日账单的过程,目的是提醒客户意外的费用。

数据

数据由各种客户的每日账单组成,如上所述。此外,成本可以按服务、地区或客户进行细分。首要任务是找出一种方法来自动检测整个账单的异常情况。

我注意到的第一件事是,对于许多客户来说,每个月的第一天都会有一个可预测的高峰。虽然这将被许多异常检测算法标记出来,但它并不是我们真正要寻找的那种异常。首先,这是可以预测的;第二,客户可以在每个月的第一天查看他们的账单(其他日子的账单只在内部跟踪),所以他们在第一天就已经知道账单了。目的是提醒他们注意他们不知道的指控。为了解决这个问题,我简单地从数据集中删除了每个月的第一天。这是剔除了每月第一天的相同数据。

我们可以看到,这消除了许多尖峰,但一些仍然存在。这样一来,是时候尝试一些异常检测算法了。

模型

异常检测有许多算法。我从最简单的开始:为基本的统计测量应用阈值。我的方法是基于一个叫做 SundaySky 的开源成本异常检测器。它查看过去 14 天的账单数据,并计算平均值和标准差。然后,它检查是否满足三个阈值:相对阈值,检查它是否至少是前几天平均成本的 1.25 倍;标准差阈值,寻找比平均值高至少 3.5 倍的标准差;和一个绝对阈值,寻找高于 10 美元的成本。

正如文档所解释的:

我们发现,同时使用所有 3 个阈值可以获得最佳结果,每个阈值都有自己的原因:

相对阈值过滤掉无关紧要的异常。

标准差阈值过滤掉具有正常不同日使用量(高日/低日)的服务常规使用量。

绝对阈值阻止我们得到关于廉价异常的通知,这将导致无行动。

SundaySky repo 中的大部分代码处理从数据库中存储和检索数据。算法的核心实际上非常简单,所以我发现自己写出来是最简单的。

当我用建议的缺省值测试它时,发现要求增加至少 3.5 个标准差太多了:它没有标出一个点。然而,完全取消标准偏差要求导致它标记了太多的点。1.5 标准差的要求被证明是一个很好的中间立场,通过了突出客户可能关注的点的眼球测试。下图中,检测到的异常点以红色突出显示。

我本来打算在转向更高级的模型之前使用这个简单的方法作为基线,但是结果证明它表现得足够好,以至于 CEO 决定按原样将其投入生产。有时候简单是最好的!

履行

唯一的另一个调整是添加一些代码,从服务、地区和帐户方面找出增长的主要原因。准备就绪后,我们将系统投入生产。当算法检测到一个异常点时,它会向 Reserved.ai 的客户服务代表发送一个松弛警报。然后,那个人会查看成本历史和主要原因,并决定是否将其传递给客户。到目前为止,这已经导致几个客户被警告他们的日常账单会有意想不到的增加。

感谢 Aran Khanna 和 Reserved.ai 对这个项目的帮助。

该项目的代码可在这里获得。

虚拟异常检测

原文:https://towardsdatascience.com/anomaly-detection-for-dummies-15f148e559c1?source=collection_archive---------0-----------------------

Photo credit: Unsplash

单变量和多变量数据的无监督异常检测。

异常检测 是识别数据集中与常态不同的意外项目或事件的过程。异常检测通常应用于未标记的数据,称为无监督异常检测。异常检测有两个基本假设:

  • 数据中很少出现异常。
  • 他们的特征明显不同于正常情况。

单变量异常检测

在我们开始多元异常检测之前,我认为有必要先看一个简单的单变量异常检测方法的例子,在这个例子中,我们从单个特征空间中的值分布中检测异常值。

我们正在使用超级商店销售数据集,可以从这里下载,我们将分别找出与预期行为不符的销售和利润模式。也就是说,一次发现一个变量的异常值。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib
from sklearn.ensemble import IsolationForest

销售的分布

df = pd.read_excel("Superstore.xls")
df['Sales'].describe()

Figure 1

plt.scatter(range(df.shape[0]), np.sort(df['Sales'].values))
plt.xlabel('index')
plt.ylabel('Sales')
plt.title("Sales distribution")
sns.despine()

Figure 2

sns.distplot(df['Sales'])
plt.title("Distribution of Sales")
sns.despine()

Figure 3

print("Skewness: %f" % df['Sales'].skew())
print("Kurtosis: %f" % df['Sales'].kurt())

超市的销售分布远不是正态分布,它有一个正的细长尾巴,分布的质量集中在图的左边。并且尾部销售分布远远超过正态分布的尾部。

在分布的右侧有一个数据出现概率低的区域。

利润分配

df['Profit'].describe()

Figure 4

plt.scatter(range(df.shape[0]), np.sort(df['Profit'].values))
plt.xlabel('index')
plt.ylabel('Profit')
plt.title("Profit distribution")
sns.despine()

Figure 5

sns.distplot(df['Profit'])
plt.title("Distribution of Profit")
sns.despine()

Figure 6

print("Skewness: %f" % df['Profit'].skew())
print("Kurtosis: %f" % df['Profit'].kurt())

超市的利润分布既有正尾也有负尾。但是,正尾比负尾长。所以分布是正偏态的,数据是重尾的或者大量的异常值。

有两个区域数据出现的概率很低:一个在分布的右侧,另一个在左侧。

销售单变量异常检测

Isolation Forest 是一种检测异常值的算法,它使用 Isolation Forest 算法返回每个样本的异常值,该算法基于异常值是少量且不同的数据点这一事实。隔离林是基于树的模型。在这些树中,通过首先随机选择一个特征,然后在所选特征的最小值和最大值之间选择一个随机分割值来创建分区。

以下过程显示了 IsolationForest 在 Susperstore 销售案例中的表现,该算法是在 Sklearn 中实现的,代码主要是从本教程中借用的

  • 使用销售数据训练 IsolationForest。
  • 将销售额存储在 N umPy 数组中,以便稍后在我们的模型中使用。
  • 计算每个观察的异常分数。输入样本的异常得分计算为森林中树木的平均异常得分。
  • 将每个观察值分类为异常值或非异常值。
  • 可视化突出显示了异常值所在的区域。

sales_IsolationForest.py

Figure 7

根据上述结果和可视化,似乎超过 1000 的销售额肯定会被视为异常值。

目测调查一个异常情况

df.iloc[10]

Figure 8

这一购买对我来说似乎很正常,只是与数据中的其他订单相比,它的销售额更大。

利润的单变量异常检测

  • 使用利润变量训练 IsolationForest。
  • 将利润存储在 N umPy 数组中,以便稍后在我们的模型中使用。
  • 计算每个观察的异常分数。输入样本的异常得分计算为森林中树木的平均异常得分。
  • 将每个观察值分类为异常值或非异常值。
  • 可视化突出显示了异常值所在的区域。

profit_IsolationForest.py

Figure 9

目测调查一些异常情况

根据上述结果和可视化,低于-100 或超过 100 的利润似乎会被视为异常值,让我们直观地检查由我们的模型确定的每个示例,看看它们是否有意义。

df.iloc[3]

Figure 10

不言而喻,任何负利润都是异常现象,应该进一步调查

df.iloc[1]

Figure 11

我们的模型确定这个利润很高的订单是异常的。但是,当我们调查这个订单时,它可能只是一个利润相对较高的产品。

以上两个可视化显示了异常分数,并突出显示了异常值所在的区域。正如预期的那样,异常分数反映了基础分布的形状,异常值区域对应于低概率区域。

然而,单变量分析只能让我们到此为止。我们可能会意识到,由我们的模型确定的这些异常中的一些并不是我们预期的异常。当我们的数据是多维的,而不是单变量的时,检测异常的方法变得更加计算密集和数学复杂。

多元异常检测

由于我们生活的世界的复杂性,我们最终做的大多数分析都是多变量的。在多变量异常检测中,异常值是至少两个变量的组合异常值。

因此,使用销售和利润变量,我们将基于几个模型构建一个无监督的多元异常检测方法。

我们使用的是 PyOD ,这是一个 Python 库,用于检测多元数据中的异常。这个库是由赵月开发的。

销售和利润

当我们做生意时,我们期望销售额和利润是正相关的。如果一些销售数据点和利润数据点不是正相关的,它们将被认为是异常值,需要进一步调查。

**sns.regplot(x="Sales", y="Profit", data=df)
sns.despine();**

Figure 12

从上面的相关图中,我们可以看到部分数据点是极低值、极高值等明显的异常值。

基于聚类的局部异常因子

CBLOF 根据基于聚类的本地异常值因子计算异常值分数。异常分数是通过每个实例到其聚类中心的距离乘以属于其聚类的实例来计算的。 PyOD 库包含CBL of 实现。

以下代码均借用自 PyOD 教程结合本文。

  • 将销售额和利润缩小到零和一之间。
  • 根据试验和最佳猜测,将异常值部分任意设置为 1%。
  • 将数据拟合到 CBLOF 模型并预测结果。
  • 使用阈值来考虑数据点是在内还是在外。
  • 使用决策函数计算每个点的异常分数。

CBLOF.py

Figure 13

基于直方图的异常检测(HBOS)

HBOS 假设特征独立,并通过构建直方图来计算异常程度。在多变量异常检测中,可以计算每个单一特征的直方图,单独评分,最后合并。使用 PyOD 库时,代码与 CBLOF 非常相似。

HBOS.py

Figure 14

隔离森林

隔离林在原理上类似于随机林,建立在决策树的基础上。隔离林通过随机选择一个要素,然后随机选择所选要素的最大值和最小值之间的分割值来隔离观察值。

PyOD 隔离林模块是具有更多功能的 Scikit-learn 隔离林的包装器。

IsolationForest.Py

Figure 15

K -最近邻(KNN)

KNN 是异常检测中最简单的方法之一。对于一个数据点,其到第 k 个最近邻的距离可以被视为异常值分数。

KNN.py

Figure 16

上述四种算法预测的异常情况差别不大。

目测调查一些异常情况

我们可能希望调查由我们的模型确定的每个异常值,例如,让我们详细查看由 KNN 确定的两个异常值,并尝试理解是什么使它们异常。

**df.iloc[1995]**

Figure 17

对于这个特殊的订单,客户购买了 5 件产品,总价为 294.62 英镑,利润低于-766 英镑,折扣为 80%。看起来像是通关。我们应该意识到我们销售的每件产品的损失。

**df.iloc[9649]**

Figure 18

对于这次购买,在我看来,4.7%左右的利润太小,模型确定该订单是异常的。

**df.iloc[9270]**

Figure 19

对于上面的订单,一个客户购买了总价为 4305 的 6 件产品,在打了 20%的折扣后,我们仍然获得了超过 33%的利润。我们希望有更多这样的异常现象。

Jupyter 笔记本以上分析可以在 Github 上找到。享受这周剩下的时光。

图像中的异常检测

原文:https://towardsdatascience.com/anomaly-detection-in-images-777534980aeb?source=collection_archive---------7-----------------------

用卷积神经网络对异常进行分类和个性化

Photo by mahdis mousavi on Unsplash

在机器学习中处理异常检测任务是正常的。数据科学家经常会遇到一些问题,他们必须显示、解释和预测异常。

我还发表了一篇关于时间序列的异常检测的帖子,其中我研究了内部系统行为,并提供了未来的异常预测。

在这篇文章中,我试图解决一个不同的挑战。我改变感兴趣的领域:从时间序列转换到图像。给定一幅图像,我们想要达到双重目的:预测异常的存在并对其进行个性化,给出结果的彩色表示。

数据集

我从网上得到的数据:裂缝数据集包含墙壁裂缝的图像。一半的图像显示了新的和未被破坏的墙体;其余部分显示了不同尺寸和类型的裂缝。

正如你从下面的样本中看到的,我们的数据显示了不同类型的墙体裂缝,其中一些对我来说也不容易识别。

Examples of Crack and No Crack

模型

我们希望建立一个机器学习模型,它能够对墙壁图像进行分类,同时检测出异常所在的位置。为了达到这个双重目的,最有效的方法是建立一个强分类器。它将能够读取我们的输入图像,并将其分类为“受损”或“未受损”。在最后一步,我们将利用我们的分类器学习的知识来提取有用的信息,这将有助于我们检测哪里有异常。

但是让我们按顺序进行,开始组装我们的神经网络…

对于这种任务,我选择了计算机视觉的银弹,忠诚 VGG16。我们装载并改造了 VGG16 列车。这在 Keras 中很容易做到,只需要几行代码。

vgg_conv = vgg16.VGG16(weights='imagenet', include_top=False, input_shape = (224, 224, 3))for layer in vgg_conv.layers[:-8]:
    layer.trainable = False

具体来说,我们引入了 VGG 架构,允许训练最后两个卷积块。这将允许我们的模型专门处理我们的分类任务。为此,我们还排除了原始模型的顶层,用另一个结构替换它们。

x = vgg_conv.output
x = GlobalAveragePooling2D()(x)
x = Dense(2, activation="softmax")(x)
model = Model(vgg_conv.input, x)model.compile(loss = "categorical_crossentropy", optimizer = optimizers.SGD(lr=0.0001, momentum=0.9), metrics=["accuracy"])

在分类阶段,GlobalAveragePooling 图层通过取每个要素地图的平均值来减小前一图层的大小。这种选择,加上中间致密层的省略使用,允许避免过度拟合。

如果你有一个图形处理器,训练是简单和容易的。COLAB 或 Kaggle 给了我们加速这一进程所需的武器。我们还使用了一个由 Keras 提供的简单的数据生成器来增强图像。

最终我们能够做到 0.90 的整体准确率,还不错!

From sklearn documentation

定位异常

现在,随着我们的模型被训练,我们使用来提取所有有用的信息,这些信息允许我们在墙壁图像中显示裂缝。我们试图用热图表示法让这个过程变得简单易懂。

我们需要的有用信息位于顶部。特别是,我们可以访问:

  • 卷积层:我们在 VGG 结构中走得更高,网络创造了更重要的特征。我们已经选择了最后一个卷积层(block 5 _ con v3’),并在这里剪切我们的分类模型。我们重新创建了一个中间模型,给定原始图像作为输入,输出相关的激活图。考虑到维度,我们的中间模型增加了通道(新特征)并减少了初始图像的维度(高度和宽度)。
  • 最终密集层:对于每个感兴趣的类,我们需要这些权重,它们负责提供分类的最终结果。

有了这些压缩物体在手,我们就有了定位裂缝的所有知识。我们希望将它们“画”在原始图像上,以使结果易于理解和观看。在 python 中,“解压缩”这些信息很容易:我们只需进行双线性上采样来调整每个激活图的大小,并计算点积。

这种魔力可以通过执行一个简单的函数来实现:

def plot_activation(img): pred = model.predict(img[np.newaxis,:,:,:])
    pred_class = np.argmax(pred) weights = model.layers[-1].get_weights()[0]
    class_weights = weights[:, pred_class] intermediate = Model(model.input,
                         model.get_layer("block5_conv3").output)
    conv_output = intermediate.predict(img[np.newaxis,:,:,:])
    conv_output = np.squeeze(conv_output) h = int(img.shape[0]/conv_output.shape[0])
    w = int(img.shape[1]/conv_output.shape[1]) act_maps = sp.ndimage.zoom(conv_output, (h, w, 1), order=1)
    out = np.dot(act_maps.reshape((img.shape[0]*img.shape[1],512)), 
                 class_weights).reshape(img.shape[0],img.shape[1]) plt.imshow(img.astype('float32').reshape(img.shape[0],
               img.shape[1],3))
    plt.imshow(out, cmap='jet', alpha=0.35)
    plt.title('Crack' if pred_class == 1 else 'No Crack')

我在下图中显示了结果,我在分类为裂纹的测试图像上绘制了裂纹热图。我们可以看到,热图能够很好地概括和指出含有裂缝的墙体。

Show anomalies in Crack images

摘要

在这篇文章中,我们提出了一个用于异常识别和定位的机器学习解决方案。所有这些功能都可以通过实现单个分类模型来实现。在训练过程中,我们的神经网络获取所有相关信息,使其能够进行分类操作。在这一阶段之后,我们已经组装了最终的碎片,这些碎片告诉我们图像中的裂缝在哪里,不需要额外的工作!

查看我的 GITHUB 回购

保持联系: Linkedin

火星表面异常探测

原文:https://towardsdatascience.com/anomaly-detection-in-martian-surface-66dc9953a546?source=collection_archive---------21-----------------------

The University of Arizona — Views of MSL Hardware 12 Days after Landing — Image Source

大海捞针!

我得到了这个极好的机会,通过奥姆德纳社区参与“火星表面异常探测”项目。这个项目的目标是探测火星表面由非地球人造物品引起的异常现象,如火星着陆器、火星车等的碎片。

最近,寻找所谓的“技术签名”——提供过去或现在外星技术的科学证据的可测量的属性或效果——获得了新的兴趣。美国宇航局于 2018 年 9 月在德克萨斯州休斯顿的月球和行星研究所举办了一场“技术签名”研讨会,以了解更多关于“技术签名”搜索的当前领域和现状,以及美国宇航局未来可能在这些搜索中发挥的作用。这个研究领域中的一个领域是寻找太阳系中的非地球人造物品。这个人工智能挑战赛旨在为行星科学家开发“人工智能工具箱”,以帮助识别非地球文物。

这个人工智能挑战有多个挑战,从数据集开始。

数据集面临的挑战

探测火星表面的异常没有什么独特的挑战。除了数据收集和没有预定义数据集的挑战,最初的挑战是火星表面本身非常多样化。火星表面的不同部分看起来与其他部分完全不同。同一个表面在不同的季节看起来差别很大。不同火星表面的少量样本:

NASA — Jamming with the ‘Spiders’ from Mars — Image Source, Sciencealert — Gorgeous New Photos of Mars — Image Source, Sinc — Fotografían las capas del Polo Norte marciano — Image Source

NASA — Squiggles in Hellas Planitia — Image Source, NASA — Radial Channels Carved by Dry Ice — Image Source

因此,该算法应该足够通用,能够检测所有这些不同表面中的异常。第二个挑战是关于数据不平衡,火星表面大约有 1.45 亿平方公里,在这个表面上,我们有几个 100 个不超过几十英尺的异常。人们可以考虑使用数据扩充来克服不平衡,但不同地形中产生的异常仍然会有所不同,我们没有跨不同地形的标记数据。

下一个挑战是数据总量已经被异常污染。通常的异常检测算法通过在正常/通常人群样本上训练 AI 模型来工作,并且该模型用于预测目标数据偏离正常/通常人群样本多少。这里不能应用这种方法。

创建数据集

我在这次演习中使用的数据集是 https://www.uahirise.org/ESP_028401_1755登陆后 12 天的 MSL 硬件图像。在这幅图像中,来自“亚利桑那大学”的人们对硬件在火星表面制造异常的表面图像进行了注释。这似乎是一个用于初步评估的完美数据集。

The University of Arizona — Views of MSL Hardware 12 Days after Landing — Image Source

The University of Arizona — Views of MSL Hardware 12 Days after Landing — Image Source

完整的 HiRISE 图像大小约为 550MB,分辨率为 25516x45788 像素。左边是完整 HiRISE 图像的压缩浏览图像。这种异常在这幅图像中几乎看不到。即使在全分辨率图像中,也很难发现异常,除非人们确切地知道在哪里看。

为了从这个图像中创建一个数据集,我将这个 25516x45788 像素的图像分割成 256x256 像素的小图像块,跨度为 256 像素。正如你所看到的,这张图片周围有黑边,黑边对人工智能模型来说并不好。为了减少预处理这张图片的工作量,我去除了图片边缘的图片块,使用了图片中心的图片块。这产生了一个大约有 10K 图像的数据集。在这些 10K 图像中,有 6 个异常分布在 50 幅图像中。

以下是数据集中出现的 6 个异常的样本图像:

The University of Arizona — JP2 Black and White — [Image Source](http://Black and white)

算法背后的直觉

主要动机是利用数据集中的挑战,并应用出版物https://arxiv.org/abs/1811.06861中提到的“使用基于深度学习的图像完成的异常检测”方法

该想法是使用深度卷积神经网络来逐块完成表面图像,目的是检测表面上的异常。本文中使用的方法是专门在正常数据上训练模型,屏蔽/切除中心 32×32 像素,并且训练模型以重建屏蔽区域。为了检测异常,查询图像的中心 32×32 像素被屏蔽,并且该模型用于重建被屏蔽区域的无故障克隆。通过用生成的区域减去相应的查询区域,获得逐像素的异常分数,然后使用该分数来检测异常。

betergevondenworden.nl — Image Source

在我们的数据集中,由于与正常图像相比,异常预计非常少,因此我们将使用整个数据集来训练模型。然后,使用经过训练的模型来计算同一数据集的异常分数。由于该模型将在正常图像上进行推广,因此预计它将给出异常的高异常分数。

让我们看看这种方法能否在 10K 图像的大海里找到这 6 根针。

前馈生成 DCNN

图像完成任务通常旨在以最自然的方式完成图像的缺失区域。除了语义上有意义之外,修复还必须看起来尽可能真实。出于这个原因,前馈修复 DCNNs 通常与对抗网络联合训练。敌对网络的目标是区分真假图像。相反,生成模型必须通过生成逼真的图像来增加敌对网络的错误率。虽然这种额外的不利损失确实使修补看起来更真实,但它对像素匹配图像的丢失部分没有积极的影响。用联合损失函数进行训练甚至会增加像素重建误差,这对于异常检测来说是不希望的行为。为此,本文采用仅用重构损失训练的前馈生成型 DCNN。

模型定义

arxiv.org — Image Source

如上图所示,DCNN 网络由 17 层组成。在第三层之后,特征图的分辨率通过步进卷积减半。为了增加输出神经元的感受野,使用了一系列扩张的回旋(第 7-10 层)。在第 13 层,通过双线性重定标以及随后的卷积来执行放大回到输入大小。镜像填充用于所有卷积层。此外,使用指数线性单位(ELU)激活函数。

损失函数

用 L1 重构损失训练网络。由二进制掩码 M 定义的 32×32 的中心区域与剩余区域的权重不同。X 是要检查的图像块,用下面的损失函数训练网络:

arxiv.org — Image Source

培养

256×256 的图像块尺寸被调整为 128×128,并且图像完成网络被馈送以 128×128 尺寸的图像补片。由于遮蔽了大小为 32×32 的中心区域,补丁被破坏。已知和未知图像内容之间的这种大比例为网络提供了更多的语义信息来完成中心区域。在通过网络重建受损图像之后,通过上述损失函数计算重建图像和查询图像之间的逐像素绝对差作为损失值。该模型被训练了 200 个历元。

异常分数

对于异常检测,仅使用该绝对差图像的 24×24 中心区域。其中缺陷出现在靠近切出的 32×32 中心区域的边界的图像补片,神经网络似乎生成边界缺陷的局部延续。通过仅考虑 24x24 中心区域,这些不想要的延续大部分被排除。

初步结果

在对模型进行 200 个时期的训练之后,该模式再次用于预测同一数据集的异常分数。由此产生的异常分数分布如下所示:

列出与样本平均值相差 3 个标准偏差的图像,可以得到 99 个图像文件。99 出 10K 的图像还不错。通过将这些文件名与 99 幅图像中的异常图像块进行交叉引用,该模型仅检测到两种异常类别:“降落伞”和“下降阶段-坠毁地点”。它漏掉了“隔热屏”,“2-新点-点 1”,“2-新点-点 2”,“好奇号-漫游者”。在 99 个图像中,只有 7 个图像是异常的。虽然不是一个好结果!

即兴创作

在仔细分析没有检测到的异常图像时,发现遗漏的异常图像在图像的侧面具有异常,即不在图像的 32×32 中心。由于 DCNN 模型被训练来重建中心 32×32 像素,以 16 的步幅分割图像块将确保异常将占据一些图像块的中心 32×32 部分。

因此,用步长 16 切割的图像块重新创建了初始数据集。不是在这个新数据集上再次重新训练模型,而是使用先前训练的模型来预测这个步幅 16 数据集上的异常分数。由此产生的异常分数分布如下所示:

我们可以清楚地看到在分布图的最右边有一个图像数量的峰值。列出与样本平均值相差 3 个标准偏差的图像,得到 705 个图像文件。通过将这些文件名与异常图像块进行交叉引用,发现所有 705 个文件都属于四种异常类型“隔热层”、“降落伞”、“下降阶段-坠毁地点”、“好奇号-漫游车”。零误报。瞧,六根针中有四根找到了!

这种方法仍然遗漏了“2-新点-点 2”、“2-新点-点 1”异常。如果我们观察这些异常,这些异常非常小,并且随着图像从 256x256 重新缩放到 128x128,这些图像产生的异常分数将会更小。

结论

“使用基于深度学习的图像完成进行异常检测”的方法似乎是检测火星表面技术特征的可行选择。可以通过以下方式进一步增强模型性能:

  • 为更多时代而训练
  • 升级模型配置
  • 对 HiRISE 图像进行聚类,并在一组相似的图像上进行训练,以使模型能够更好地概括,并更果断地检测异常。

基于 Prophet 库的时间序列异常检测

原文:https://towardsdatascience.com/anomaly-detection-time-series-4c661f6f165f?source=collection_archive---------4-----------------------

首先,我们来定义一下什么是时间序列中的异常。时间序列的异常检测问题可以表述为寻找相对于一些标准或通常信号的异常数据点。虽然有许多异常类型,但从业务角度来看,我们将只关注最重要的类型,如意外的峰值、下降、趋势变化和水平变化。你可以用两种方式解决这个问题:有人监督和无人监督。虽然第一种方法需要一些标记数据,但第二种方法不需要,您只需要原始数据。在那篇文章中,我们将关注第二种方法。

看看我的机器和深度学习博客https://diyago.github.io/

一般来说,无监督异常检测方法是这样工作的:你建立你的数据的一些通用简化版本——在这个模型的阈值之外的任何东西都被称为异常值或异常值。因此,首先我们需要将我们的数据放入某个模型中,希望这个模型能够很好地描述我们的数据。先知图书馆来了。当然,你可以尝试或多或少强大/复杂的模型,如 arima、回归树、rnn/lstm 甚至移动平均线等,但几乎所有这些模型都需要调整,不太可能开箱即用。先知不是那样的,它像自动 arima,但好得多。开始使用专注于预测时间序列的库真的很强大也很容易。它是由脸书的核心数据科学团队开发的。你可以在这里阅读更多关于 T2 图书馆的信息。

要安装 Prophet 库可以通过 pypi 安装:

pip install fbprophet

我们将使用一些样本数据,其中有一些有趣的异常值。你在这里下载数据,看起来是这样的:

Some random time-series

为了训练模型,我们将定义一些基本超参数 interval_widthchangepoint_range 。它们可用于调整边界的宽度:

Fitting prophet model

然后,我们将高于顶部的所有内容设置为异常值,并降低模型边界的底部。此外,将离群值的重要性设置为基于点离边界有多远:

然后你就准备好获取剧情了。推荐试试牛郎星库,只需设置添加就能轻松获得一个互动剧情。与您的代码交互

最后,我们得到了结果。他们似乎很有道理:

  • Github 储存库包含代码和数据
  • Kaggle 代码与数据由 Vinay Jaju

Python 异常检测手册— (12)自动编码器

原文:https://towardsdatascience.com/anomaly-detection-with-autoencoder-b4cdce4866a6?source=collection_archive---------0-----------------------

(新修订日期:2022 年 12 月 5 日)

自动编码器模型是神经网络或深度学习的重要应用。它们被广泛应用于降维、图像压缩、图像去噪和特征提取。它们也被应用于异常检测,并取得了良好的效果。

深度学习是机器学习的整个课题。我知道不是所有的读者都熟悉深度学习,所以我在这一章中花了更多的章节来描述深度学习的具体细节。因为许多读者熟悉回归,所以我将从回归的角度介绍深度学习,并使用逻辑回归来解释神经网络图。这种回归友好的方法可以帮助读者理解神经网络建模。

至此,我解释了自动编码器的结构,并向您展示了如何构建异常值。我将深入研究自动编码器所基于的深度学习模型的组件。这些组件包括批量大小的概念、L1 和 L2 正则化、纪元、深度学习模型中的优化器等等。完成本章后,读者将对通用深度学习框架充满信心,可以对超参数进行微调。

(一)理解深度学习

往往深度学习或者神经网络是用他们的行话来呈现的。学习者以类似大脑的解剖学为导向来“想象”它在大脑中是如何运作的。学习者会看到神经元、互联性和复杂的神经网络系统。在我的讲座从回归到深度学习的过渡中,我不知何故感到有一瞬间的沉默——就像跳过一个深深的缺口。术语的差异也造成了知识差距。为了用回归友好的方法呈现深度学习,让我首先解释神经元、激活函数、层、优化器等等。然后,我将向您展示如何在深度学习框架中建立逻辑回归。

(A.1)数据在深度学习中被称为“张量”

在 y = XB + e 回归公式中,y 是一维向量,X 是 2D 矩阵。在 EXCEL 电子表格中,因变量 y 是一列,协变量 X 是多列。在深度学习术语中,一列称为张量。1D 矢量是张量,2D 矩阵是 2D 张量。流行的机器学习平台 tensor flow(tensorflow.org)也以此命名,并为神经网络建模而建。一旦你知道“张量”除了一维向量什么都不是,你可能会感到宽慰。为什么他们不直接叫它“向量”?这个术语来自哪里?它来自拉丁语张量,意思是“伸展的东西”。数学家沃耳德玛·福格特(1898 年)利用数学中的这一概念将矢量称为张量。

Figure (A.1): Tensor/Vector (Image by author)

(A.2)输入层中的神经元是输入变量

神经网络中的术语神经元对于回归学习者来说是陌生的。你大概见过类似图(A.2)的神经网络图。图为一款型号。模型是描述 X 和 y 之间关系的算法。例如,回归或决策树是模拟 X 和 y 之间关系的框架。

Figure (A.2): A Neural Network (Image by author)

神经网络模型有一个输入层、隐藏层和一个输出层。神经网络是一种监督学习模型。为了训练模型,X 矩阵被馈送到输入层,而目标 y 被馈送到输出层。图中的节点被称为神经元。神经元是一个矢量或张量。任何两个神经元之间的连接代表参数。隐藏层中的每个神经元都是前一层神经元的加权和。可以有很多隐藏层。

(A.3)使用神经网络构建逻辑回归

如果没有隐藏层,神经网络实际上会崩溃为逻辑回归。在图(A.3)中,有四个变量 x1 — x4 和一个输出变量 y 。表示逻辑回归 Y=f(a) 其中 a = w1x1 + w2x2 + w3x3 + w4x4w1 — w4 是需要优化的参数。

Figure (A.3): A logistic Regression in Deep Learning

(A.4)激活功能

在深度学习中,还有一个组件叫做激活函数。它的工作方式类似于逻辑回归中的 logit 函数。在逻辑回归中,logit 函数将原始预测转换为介于 0 和 1 之间的概率。在深度学习中,激活函数将原始值映射到非零值。因为一个神经元中的值是前一层神经元的线性组合,所以这些值可能会变得非常小,并最终在多层计算后消失。在这种情况下,神经网络无法继续。这就是消失梯度问题,说的是基于梯度的学习方法中权重会消失。因此,激活函数将权重映射到一系列值,如 0 和 1,以防止它们消失。

激活功能可以应用于一些或所有隐藏层。对于激活函数来说,任何能够将原始值单调映射到新值的非线性函数都是不错的选择。常见的函数有 Sigmoid、ReLu 和 Tanh 函数。这里我只介绍前两个。

一个 sigmoid 函数是一个 logit 函数。因为输出值的范围可以扩大到正无穷大或负无穷大,所以神经网络应用 sigmoid 函数将输出转换为 0 到 1 之间的值。

一个 ReLU 功能(整流线性单元)是另一个流行的激活功能。它将任何负值都限制在零。

(A.4)不同数据类型的不同深度学习算法

提及三大数据类别是有帮助的。它们是(1)多元数据,(2)串行数据(包括时间序列、文本和语音流),以及(3)图像数据。发明了许多不同类型的神经网络框架来处理每种类型的数据。标准的前馈神经网络通常用于多元数据。递归神经网络(RNN)和长短期记忆网络(LSTM)是系列数据的例子。和卷积神经网络(CNN)是图像数据的例子。在这一章中,我们主要关注多元数据。对序列数据感兴趣的读者,推荐查阅《现代时间序列异常检测》或《RNN/LSTM/GRU 股价预测技术指南》这本书。对图像数据和神经网络应用感兴趣的读者,推荐查看“用于图像分类的迁移学习”。

(A.5)神经网络的有用链接

如果你想了解更多关于人工神经网络(ANN)的知识,下面的视频剪辑给出了一个非常直观的观点:

这个视频描述了什么是反向传播:

(A.6)图像分类中的深度学习

显然,仅仅用深度学习来做逻辑回归是矫枉过正的。深度学习可以做很多复杂结构的图像识别。因为使用图像应用程序学习自动编码器会容易得多,所以在这里我将描述图像分类是如何工作的。

新生婴儿不知道狗的图像,但是他/她将学会记住关于狗的一些特殊“特征”,然后识别该图像。如果我们想要一种算法像我们人类一样识别图像,该算法必须经历相同的学习过程。我们要用成千上万张标签为“狗”的图像,和成千上万张标签为“猫”的图像来“训练”模型。该模型将学习狗或猫的特征。该模型将能够识别未知图像中的任何特殊特征,以辨别它是狗还是猫的图像。我个人认为图像识别模型无法取代上帝创造的人脑中错综复杂的网络。但是它们被聪明地发明来帮助人类重复任务。

Figure (A.5): Artificial Neural Network (Image by author)

(B)了解自动编码器

自动编码器是一种特殊类型的神经网络,它将输入值复制到输出值。因为它不像标准神经网络模型那样需要目标变量,所以它被归类为无监督学习。

在图(B)中,目标值(蒙娜丽莎图像)与输入值相同。它在蒙娜丽莎上模仿蒙娜丽莎。你可能会问,如果输出值设置为等于输入值,我们为什么要训练模型。事实上,我们对输出层不太感兴趣。我们对隐藏的核心层感兴趣。当隐层神经元的数量少于输入层时,隐层将提取输入值的本质信息。这种情况迫使隐藏层学习数据的大多数模式并忽略“噪声”。在自动编码器模型中,隐藏层的维数必须少于输入层或输出层的维数。如果隐藏层中的神经元数量多于输入层中的神经元数量,神经网络将被赋予过多的能力来学习数据。在极端情况下,它可能只是简单地将输入复制到输出值,包括噪声,而没有提取任何必要的信息。

Figure (B): Autoencoders

图(B)也显示了编码和解码过程。编码过程压缩输入值以到达核心层。它看起来像一个左宽右窄的漏斗。解码过程重构信息以产生结果。解码过程看起来与编码漏斗相反。它左边窄,右边宽。按照惯例,我们建立模型,使得解码过程反映编码过程。解码漏斗的神经元数量和隐藏层数量反映了编码漏斗的神经元数量和隐藏层数量。大多数从业者只是采用这种对称。我们将在后面的章节中学习如何建立模型。

(C)自动编码器有哪些应用?

自动编码器的早期应用是降维。Hinton 和 Salakhutdinov (2006)的一篇里程碑论文显示,与 PCA 的前 30 个主分量相比,经过训练的自动编码器产生更小的误差,并且更好地分离聚类。自动编码器在计算机视觉和图像编辑中也有广泛的应用。在图像着色中,自动编码器用于将黑白图像转换成彩色图像。图(C.1)显示了用于图像着色的自动编码器模型。输入图像是黑白图像,对应的目标图像是彩色图像。该模型在许多对黑白和彩色图像上被训练。该模型能够将任何黑白图像转换成彩色图像。

Figure (C.1): An autoencoder model for image coloring (Image by author)

类似地,自动编码器可以用于降噪。图(C.2)显示了一个自动编码器,输入图像是一个模糊的图像,而目标是一个清晰的图像。该模型将在多对模糊和清晰的图像上进行训练。然后,该模型将能够把任何模糊的图像转换成彩色图像。参见我的帖子“用于图像降噪的卷积自动编码器”。

Figure (C.2): An autoencoder model for noise reduction (Image by author)

(D)为什么要使用自动编码器进行降维?

已经有许多有用的工具,如主成分分析(PCA)来检测异常值,为什么我们需要自动编码器?回想一下 PCA 使用线性代数来转换。相反,自动编码器技术可以利用其非线性激活函数和多层来执行非线性变换。用自动编码器训练几个层比用 PCA 训练一个巨大的变换更有效。因此,当数据问题是复杂的和非线性的时,自动编码器技术显示了它们的优点。在“使用 Python 的降维技术”中,我描述了内核 PCA 更加灵活,因为它可以对数据中的非线性分布进行建模。事实上,更强大的自动编码器可以模拟比内核 PCA 更复杂的数据分布。

[## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士

阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…

dataman-ai.medium.com](https://dataman-ai.medium.com/membership)

(E)建模程序

我将以下建模过程应用于模型开发、评估和结果解释。

  1. 模型开发
  2. 阈值确定
  3. 正常组和异常组的描述性统计

使用异常值分数,您将选择一个阈值来区分异常值分数高的异常观察值和正常观察值。如果任何先验知识表明异常的百分比应该不超过 1%,那么您可以选择一个导致大约 1%异常的阈值。

两组之间特征的描述性统计(如平均值和标准偏差)对于传达模型的可靠性非常重要。如果期望异常组中某个特征的均值高于正常组,如果结果相反,那就反直觉了。在这种情况下,您应该调查、修改或删除该特征,然后重新建模。

(E.1)第一步——建立模型

让我使用 PyOD 的效用函数generate_data()来生成 500 个观察值和 5%的异常值。与其他章节不同,我将生成多达 25 个变量。这 25 个变量将馈入输入层的 25 个神经元。回想一下,在自动编码器中,隐藏层中的神经元数量应该少于输入层中的神经元数量。更多的变量可以让我们为自动编码器试验不同的层和神经元设置。

聚集在一起的紫色点是“正常”观察值,黄色点是异常值。

这里我指定了一个非常简单的自动编码器,它有两个隐藏层,每个隐藏层有两个神经元,即 hidden_neurons = [2,2]。

Figure (E.1): The structure of the Autoencoder (Image by author)

图(E.1)打印出了自动编码器模型的结构。第一列是层的名称,第二列是层的形状,第三列是参数的数量。术语“顺序”表示这是一个简单的神经网络模型。术语“密集”意味着神经网络是规则的密集连接的神经网络层。我们的模型有输入层、两个隐藏层和输出层。所以“密集 _1 +漏失 _1”、“密集 _2 +漏失 _2”、“密集 _3 +漏失 _3”、“密集 _4 +漏失 _4”这样的重复结构代表了四个层次。输入层的形状是 25,因为模型自动检测到有 25 个输入变量。在这个模型中,有 1433 个参数需要训练。我将在(G)节解释“辍学”的含义。

您的屏幕将显示“纪元 1/100”、“纪元 2/100”,依此类推,直到达到“纪元 100/100”。这就是模特培训。先完成模型训练吧。我将在后面解释时代的概念。

(E.2)步骤 2——确定一个合理的阈值

PyOD 有一个内置函数threshold_,在给定污染率的情况下计算训练数据的阈值。如果我们不指定污染率,默认为 10%。因为我们在模型中将其指定为 5%,所以阈值是 5%处的值。下面的代码显示了 5%污染率的阈值是 4.1226。

正如我们在其他章节中提到的,通常我们不知道异常值的百分比。我们可以使用异常值分数的直方图来选择合理的阈值。图(E.2)中异常值分数的直方图建议阈值为 4.0,因为直方图中存在自然切割。

Figure (E.2): The histogram of Autoencoder outlier score

(E.3)第 3 步——分析正常和异常组

描述正常组和异常组是证明模型可靠性的关键步骤。正常组和异常组的特征统计应该与任何领域知识一致。如果异常组中某个特征的平均值应该很高,但结果却相反,建议您检查、修改或丢弃该特征。您应该迭代建模过程,直到所有的特性都与先前的知识一致。另一方面,也建议你验证数据提供的新见解的先验知识。

Table (E.3)

上表显示了正常组和异常组的特征。它显示了正常组和异常组的计数和计数百分比。提醒您使用功能名称来标记功能,以便有效地进行演示。该表告诉我们几个重要的结果:

  • 离群组的大小:一旦确定了阈值,就确定了大小。如果阈值来源于图(E.2)并且没有先验知识,那么大小统计就成为一个很好的参考。
  • 各组中的特征统计:所有的手段必须与领域知识一致。在我们的例子中,异常值组的平均值小于正常组的平均值。
  • 异常平均分:异常值组的平均分应该高于正常组。你不需要对分数解读太多。

因为我们有了基本事实,我们可以产生一个混淆矩阵来理解模型性能。下面的混淆矩阵证明了该模型做了一个体面的工作,并确定了所有 25 个异常值。

(F)骨料达到模型稳定性

正如 Aggarwal [1]所指出的,使用神经网络有两个问题。第一个问题是神经网络训练缓慢,第二个问题是它们对噪声和过拟合敏感。为了缓解过度拟合和模型预测不稳定的问题,我们可以训练多个模型,然后汇总分数。在聚合过程中,您仍将像以前一样遵循步骤 2 和 3。

有四种方法可以汇总结果:

  • 平均:所有检测器的平均分数。
  • 最大值的最大值
  • 最大值的平均值(AOM)
  • 平均值的最大值

您只需要一种聚合方法。在本文中,我将只演示平均方法。

首先,让我们指定三种不同的模型。模型“atcdr1”有 2 个隐层,每个隐层有 2 个神经元。模型“atcdr2”有三个隐藏层。三个隐层的神经元数目分别为 10、2 和 10。模型“atcdr3”有 5 个隐含层,分别有 15、10、2、10、15 个神经元。

我们已经提到了在编码和解码过程中应用对称性的惯例。模型“atcdr3”中的对称模式很明显。它的第一个隐层和最后一个隐层有 15 个神经元。它的第二隐层和最后一个第二隐层有 10 个神经元。

为了安全起见,让我们在训练前将数据标准化:

让我们准备三列的空数据框来存储三个模型的预测。

然后我们将训练这三个模型。

对于训练和测试数据,三个模型的预测将存储在列 0、1 和 2 中:

最后,让我们将三个模型的预测标准化,以便稍后我们可以对预测进行平均。

让我们绘制预测平均值的直方图。

Figure (F): The Histogram of the Average Prediction of the Training Data

图(F)中的直方图建议阈值为 0.0。我们可以利用表(F)中的汇总得分得出描述性统计数据。它将 25 个数据点识别为异常值。读者应对表(E.3)进行类似的解释。

Table (E.3)

(G)超参数调谐

在第(E.1)节中,我们用所有默认的超参数建立了一个简单的自动编码器模型。现在是学习更多超参数的时候了。所有这些超参数都是神经网络框架中的螺母和螺栓。对它们的良好理解将推进你对神经网络的了解。由于篇幅限制,我只能对每个超参数进行简要描述。强烈推荐感兴趣的读者阅读《图像分类的迁移学习》一书,该书提供了深入而又平易近人的描述。

让我们打印出“atcdr”型号的规格。我将根据这个列表来解释组件。

(G.1)批量大小—“32”

在模型训练期间,神经网络将数据样本分成“批”。模型使用梯度下降来搜索最佳参数值。将数据分成批次可以减少计算负担。假设有 100,000 个数据样本。梯度下降中的计算一次合计所有 100,000 个样本的梯度,以更新参数值。一次性对 100,000 个样本的梯度求和是一个非常耗时的过程,并且需要大量内存。如果将 100,000 个样本分成每批 32 个,则每次计算只需对 32 个样本的梯度求和。这大大减少了计算量。有 100,000 / 32 = 3,125 个批次,因此梯度下降将被评估 3,125 次。简而言之,批量是每次梯度更新的样本数。默认的批量大小batch_size是 32。因为样本大小可能不总是批量大小 32 的倍数,所以最后一组样本可能少于 32 个样本。

(G.2)辍学率正规化——0.2

如前所述,神经网络中的复杂结构可能会过度拟合训练数据,但对新数据的预测却很差。神经网络模型使用两种技术来减轻过拟合:辍学率和 L1/L2 正则化。

丢弃技术在每次迭代期间随机丢弃或停用一层的一些神经元。这就像一些权重被设置为零。默认比率为 20%,这意味着在每次迭代的模型训练期间,隐藏层中 20%的神经元将被关闭。因为模型看的是稍微不同的结构本身来优化模型,可以防止某些神经元和权重记忆噪音。

(g . 3)L2 L1 正规化—“0.2”

正则化将惩罚项添加到损失函数中,以惩罚大量的权重(参数)或大量的权重。深度学习提供了拉索(L1)和里奇(L2):

默认正则化是λ值为 0.2 的 L2。

(G.4)纪元—“100”

纪元技术在神经网络中是独一无二的。一个历元正好迭代所有数据一次。模型参数在每个时期更新,直到它们达到最佳值。默认值为 100。这意味着该模型将遍历所有数据 100 次,以优化其参数。当您训练自动编码器时,您会看到“纪元 1”、“纪元 2”…,出现在您的屏幕上。

(G.5)隐藏激活—“ReLu”

在第(A.4)节中,我们已经解释了激活功能。PyOD 中的自动编码器将 ReLu 设置为默认激活功能。

(G.6)损失—“平均平方误差”

损失函数是判断模型性能的评价指标。PyOD 的自动编码器中的默认损失函数是均方误差。

如果您想知道为您的模型选择合适的评估指标是什么,让我提供一些信息。评估度量属于三个类别:(a)回归相关度量,(b)概率度量,以及(c)准确性度量。与回归相关的指标包括均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)、平均绝对百分比误差(MAPE)等等。当您的目标变量是连续的,并且您希望以百分比误差或绝对误差的形式追求最小偏差时,您应该考虑与回归相关的指标。

当您的预测是一个概率时,将考虑概率指标。它们包括二元交叉熵和分类交叉熵。如果你的目标是二进制,你可以使用二进制交叉熵。如果你的目标是多类分类交叉熵。

准确性度量计算预测等于标注的频率。常用的度量是精度类、二进制精度类和分类精度类。顾名思义,二进制精度类计算预测匹配二进制标签的频率,而分类精度类计算预测匹配多个标签的频率。

(G.7)优化器—“亚当”

优化器是一种优化模型的功能。优化器使用上述损失函数来计算模型的损失,然后尝试最小化损失。没有优化器,机器学习模型什么也做不了。

流行的优化器包括随机梯度下降(SGD)、弹性反向传播(RProp)、自适应矩(Adam)和 Ada 系列。SGD 可能是使用最广泛的优化器。我已经在附录中包含了一个温和的描述。RProp 广泛用于多层前馈网络。当处理大量数据和参数时,Adam 被认为效率更高,需要的内存更少。它需要更少的内存并且是高效的。

(G.8)验证尺寸—“0.1”

模型将保留最后 10%的样本用于验证目的。相同的验证数据应该用于所有时期。该模型不应该在每个时期中绘制新的验证数据。这组固定的随机样本将确保使用相同的验证数据来比较各时期的模型性能。

(G.9)预处理—“真”

输入数据将被标准化用于模型训练。

(一)提醒—张量流的安装

自动编码器是基于神经网络的算法,需要张量流。为防止意外后果,PyOD 不会自动安装 TensorFlow。PyOD 的安装页面[8]对此进行了解释。在撰写本书时,tensorflow 还没有 Python 3.9 的稳定版本。我为 Python 3.7 创建了一个虚拟环境。然后用“康达安装 tenshoflow”在我的虚拟环境上安装 tensorflow。然后 pip 安装 pyod。

(J)摘要

  • 自动编码器广泛应用于降维、图像压缩、图像去噪和特征提取。
  • 在自动编码器中,隐层神经元的数量应该少于输入层神经元的数量。这使得隐藏核心层能够提取输入值的基本信息。

(K) Python 笔记本:可以通过这个 Github 链接下载 Python 笔记本。

参考文献

  • Hinton,G. E .和 Salakhutdinov,R. R. (2006 年)。用神经网络降低数据的维数。科学,313,504–507。
  • Aggarwal,C. C. (2016 年)。异常值分析。斯普林格。国际标准书号:978–3319475776

为了便于导航到章节,我在最后列出了章节。

  • 第 1 章—简介
  • 第 2 章—基于直方图的异常值得分(HBOS)
  • 第 3 章——经验累积异常值检测(ECOD)
  • 第 4 章——隔离林(IForest)
  • 第 5 章——主成分分析
  • 第六章——单类支持向量机
  • 第七章——高斯混合模型(GMM)
  • 第八章——K 近邻(KNN)
  • 第 9 章—局部异常因素(LOF)
  • 第十章——基于聚类的局部异常因子(CBLOF)
  • 第 11 章——基于极端增强的异常检测(XGBOD)
  • 第 12 章——自动编码器
  • 第 13 章——极度不平衡数据的欠采样
  • 第 14 章—极度不平衡数据的过采样

[## 通过我的推荐链接加入 Medium-Chris Kuo/data man 博士

阅读 Chris Kuo/data man 博士的每一个故事。你的会员费直接支持郭怡广/戴塔曼博士和其他…

dataman-ai.medium.com](https://dataman-ai.medium.com/membership)

建议读者购买郭怡广的书籍:

  • 可解释的人工智能:https://a.co/d/cNL8Hu4
  • 图像分类的迁移学习:https://a.co/d/hLdCkMH
  • 现代时间序列异常检测:https://a.co/d/ieIbAxM
  • 异常检测手册:https://a.co/d/5sKS8bI

使用隔离林和可视化进行异常检测

原文:https://towardsdatascience.com/anomaly-detection-with-isolation-forest-visualization-23cd75c281e2?source=collection_archive---------1-----------------------

指标的突然上升或下降是一种异常行为,这两种情况都需要注意。如果我们在建模之前有关于异常行为的信息,异常的检测可以通过监督学习算法来解决,但是最初没有反馈,很难识别这些点。因此,我们使用像隔离森林、一类 SVM 和 LSTM 这样的算法,将这建模为一个无监督问题。在这里,我们使用隔离林来识别异常。

这里的数据是一个用例(如收入、流量等)的一天水平,有 12 个指标。我们必须首先识别用例级别是否有异常。然后为了更好的可操作性,我们深入到单个指标并识别其中的异常。

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)warnings.filterwarnings('ignore')
import os
print(os.listdir("../input"))df=pd.read_csv("../input/metric_data.csv")
df.head()

现在在数据帧上做一个透视来创建一个数据帧,其中所有指标都在日期级别。拉平多索引透视数据框架,并用 0 处理 na。

metrics_df=pd.pivot_table(df,values='actuals',index='load_date',columns='metric_name')
metrics_df.reset_index(inplace=True)
metrics_df.fillna(0,inplace=True)
metrics_df

隔离林试图分离数据中的每个点。在 2D 的情况下,它随机创建一条线,并试图挑出一个点。此处,异常点可以分几步分离,而较近的正常点可能需要更多的步骤才能分离。

我不会深入每个参数。污染在这里是一个重要的参数,我是在用 2D 图中的异常值验证其结果的反复试验的基础上得出它的值的。它代表数据中异常点的百分比

我在这里使用 sklearn 的隔离森林,因为它是一个只有几个月数据的小数据集,而最近 h2o 的隔离森林也可用,它在大容量数据集上更具可扩展性,值得探索。

更多算法细节可以在这里找到:https://cs . nju . edu . cn/zhouzh/zhouzh . files/publication/ICD m08 b . pdf

关于 H2O 隔离森林的更多详情:https://github . com/h2oai/H2O-tutorials/tree/master/tutorials/Isolation-forest

metrics_df.columns
#specify the 12 metrics column names to be modelled
to_model_columns=metrics_df.columns[1:13]
from sklearn.ensemble import IsolationForest
clf=IsolationForest(n_estimators=100, max_samples='auto', contamination=float(.12), \
                        max_features=1.0, bootstrap=False, n_jobs=-1, random_state=42, verbose=0)
clf.fit(metrics_df[to_model_columns])pred = clf.predict(metrics_df[to_model_columns])
metrics_df['anomaly']=pred
outliers=metrics_df.loc[metrics_df['anomaly']==-1]
outlier_index=list(outliers.index)
#print(outlier_index)
#Find the number of anomalies and normal points here points classified -1 are anomalous
print(metrics_df['anomaly'].value_counts())

Number of outliers are 15 indicated by -1

现在,我们有 12 个指标,根据这些指标,我们根据隔离林对异常进行了分类。我们将尝试可视化结果,并检查分类是否有意义。

将指标标准化并拟合到 PCA 中,以减少维度数量,然后在 3D 中绘制它们,突出异常。

import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from mpl_toolkits.mplot3d import Axes3D
pca = PCA(n_components=3)  # Reduce to k=3 dimensions
scaler = StandardScaler()
#normalize the metrics
X = scaler.fit_transform(metrics_df[to_model_columns])
X_reduce = pca.fit_transform(X)fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.set_zlabel("x_composite_3")# Plot the compressed data points
ax.scatter(X_reduce[:, 0], X_reduce[:, 1], zs=X_reduce[:, 2], s=4, lw=1, label="inliers",c="green")# Plot x's for the ground truth outliers
ax.scatter(X_reduce[outlier_index,0],X_reduce[outlier_index,1], X_reduce[outlier_index,2],
           lw=2, s=60, marker="x", c="red", label="outliers")
ax.legend()
plt.show()

3D plot of outliers highlighted

现在,当我们看到 3D 点时,异常点大多远离正常点群,但是 2D 点将帮助我们更好地判断。让我们试着将相同的 fed 绘制成缩减到二维的 PCA。

from sklearn.decomposition import PCA
pca = PCA(2)
pca.fit(metrics_df[to_model_columns])res=pd.DataFrame(pca.transform(metrics_df[to_model_columns]))Z = np.array(res)plt.title("IsolationForest")
plt.contourf( Z, cmap=plt.cm.Blues_r)b1 = plt.scatter(res[0], res[1], c='green',
                 s=20,label="normal points")b1 =plt.scatter(res.iloc[outlier_index,0],res.iloc[outlier_index,1], c='green',s=20,  edgecolor="red",label="predicted outliers")
plt.legend(loc="upper right")
plt.show()

因此,2D 图给了我们一个清晰的图像,该算法正确地对用例中的异常点进行了分类。

异常以红边突出显示,正常点以绿点表示。

这里的污染参数起了很大的作用。
我们这里的想法是捕捉系统中所有的异常点。
因此最好将少数可能正常的点识别为异常点(假阳性),但不要错过捕捉异常点(真阴性)。(因此,我指定 12%为污染,因使用情形而异)

现在,我们已经在用例层面上理解了异常行为。但是,要对异常采取行动,单独识别并提供关于it 中哪些指标异常的信息非常重要。

当业务用户直观地观察(突然的下降/峰值)并采取行动时,算法识别的异常应该是有意义的。因此,在这个过程中,创建一个良好的可视化同样重要。

此函数在时间序列上创建实际值图,并在其上突出显示异常点。也是一个提供实际数据、变化和基于异常的条件格式的表格。

from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import plotly.plotly as py
import matplotlib.pyplot as plt
from matplotlib import pyplot
import plotly.graph_objs as go
init_notebook_mode(connected=True)
def plot_anomaly(df,metric_name):
    df.load_date = pd.to_datetime(df['load_date'].astype(str), format="%Y%m%d")
    dates = df.load_date
    #identify the anomaly points and create a array of its values for plot
    bool_array = (abs(df['anomaly']) > 0)
    actuals = df["actuals"][-len(bool_array):]
    anomaly_points = bool_array * actuals
    anomaly_points[anomaly_points == 0] = np.nan
    #A dictionary for conditional format table based on anomaly
    color_map = {0: "'rgba(228, 222, 249, 0.65)'", 1: "yellow", 2: "red"}

    #Table which includes Date,Actuals,Change occured from previous point
    table = go.Table(
        domain=dict(x=[0, 1],
                    y=[0, 0.3]),
        columnwidth=[1, 2],
        # columnorder=[0, 1, 2,],
        header=dict(height=20,
                    values=[['<b>Date</b>'], ['<b>Actual Values </b>'], ['<b>% Change </b>'],
                            ],
                    font=dict(color=['rgb(45, 45, 45)'] * 5, size=14),
                    fill=dict(color='#d562be')),
        cells=dict(values=[df.round(3)[k].tolist() for k in ['load_date', 'actuals', 'percentage_change']],
                   line=dict(color='#506784'),
                   align=['center'] * 5,
                   font=dict(color=['rgb(40, 40, 40)'] * 5, size=12),
                   # format = [None] + [",.4f"] + [',.4f'],
                   # suffix=[None] * 4,
                   suffix=[None] + [''] + [''] + ['%'] + [''],
                   height=27,
                   fill=dict(color=[test_df['anomaly_class'].map(color_map)],#map based on anomaly level from dictionary
                   )
                   ))
    #Plot the actuals points
    Actuals = go.Scatter(name='Actuals',
                         x=dates,
                         y=df['actuals'],
                         xaxis='x1', yaxis='y1',
                         mode='line',
                         marker=dict(size=12,
                                     line=dict(width=1),
                                     color="blue"))#Highlight the anomaly points
    anomalies_map = go.Scatter(name="Anomaly",
                               showlegend=True,
                               x=dates,
                               y=anomaly_points,
                               mode='markers',
                               xaxis='x1',
                               yaxis='y1',
                               marker=dict(color="red",
                                           size=11,
                                           line=dict(
                                               color="red",
                                               width=2)))axis = dict(
        showline=True,
        zeroline=False,
        showgrid=True,
        mirror=True,
        ticklen=4,
        gridcolor='#ffffff',
        tickfont=dict(size=10))layout = dict(
        width=1000,
        height=865,
        autosize=False,
        title=metric_name,
        margin=dict(t=75),
        showlegend=True,
        xaxis1=dict(axis, **dict(domain=[0, 1], anchor='y1', showticklabels=True)),
        yaxis1=dict(axis, **dict(domain=[2 * 0.21 + 0.20, 1], anchor='x1', hoverformat='.2f')))fig = go.Figure(data=[table, anomalies_map, Actuals], layout=layout)iplot(fig)
pyplot.show()

查找百分比变化的辅助功能,根据严重性对异常进行分类。

预测功能基于来自决策功能的结果将数据分类为异常。
比方说,如果企业需要发现可能会产生影响的下一级异常情况,这可以用来识别这些点。

前 12 个分位数被识别为异常(高严重性),根据决策函数,我们在这里识别 12–24 个分位数点,并将其分类为低严重性异常。

def classify_anomalies(df,metric_name):
    df['metric_name']=metric_name
    df = df.sort_values(by='load_date', ascending=False)
    #Shift actuals by one timestamp to find the percentage chage between current and previous data point
    df['shift'] = df['actuals'].shift(-1)
    df['percentage_change'] = ((df['actuals'] - df['shift']) / df['actuals']) * 100
    #Categorise anomalies as 0-no anomaly, 1- low anomaly , 2 - high anomaly
    df['anomaly'].loc[df['anomaly'] == 1] = 0
    df['anomaly'].loc[df['anomaly'] == -1] = 2
    df['anomaly_class'] = df['anomaly']
    max_anomaly_score = df['score'].loc[df['anomaly_class'] == 2].max()
    medium_percentile = df['score'].quantile(0.24)
    df['anomaly_class'].loc[(df['score'] > max_anomaly_score) & (df['score'] <= medium_percentile)] = 1
    return df

识别单个指标的异常,并绘制结果图。

X 轴—日期
Y 轴—实际值和异常点。

指标的实际值显示在蓝线中,异常点突出显示为红点

在表中,背景红色表示高异常,黄色表示低异常。

import warnings  
warnings.filterwarnings('ignore')
for i in range(1,len(metrics_df.columns)-1):
    clf.fit(metrics_df.iloc[:,i:i+1])
    pred = clf.predict(metrics_df.iloc[:,i:i+1])
    test_df=pd.DataFrame()
    test_df['load_date']=metrics_df['load_date']
    #Find decision function to find the score and classify anomalies
    test_df['score']=clf.decision_function(metrics_df.iloc[:,i:i+1])
    test_df['actuals']=metrics_df.iloc[:,i:i+1]
    test_df['anomaly']=pred
    #Get the indexes of outliers in order to compare the metrics     with use case anomalies if required
    outliers=test_df.loc[test_df['anomaly']==-1]
    outlier_index=list(outliers.index)
    test_df=classify_anomalies(test_df,metrics_df.columns[i])
    plot_anomaly(test_df,metrics_df.columns[i])

是的,从这些图中,我们能够捕捉到指标中的突如其来的峰值、下降并投射出来。

此外,条件格式表为我们提供了对数据等情况的洞察,不存在(值为零)的数据被捕获为高异常,这可能是数据处理中管道破裂的潜在结果,需要修复并突出显示高和低级别异常。

这个怎么用?

如果当前时间戳异常对于一个用例向下钻到指标,找出时间戳中异常高的指标集,对其执行 RCA。

此外,来自业务用户的反馈可以在数据中更新,这将有助于将此转化为监督/半监督学习问题,并比较它们的结果。

这里的增强将是组合连续发生的异常行为。例如,会导致几天指标峰值的大销售日可以显示为单个行为。

喀拉斯 LSTM 异常探测

原文:https://towardsdatascience.com/anomaly-detection-with-lstm-in-keras-8d8d7e50ab1b?source=collection_archive---------2-----------------------

使用置信区间预测异常

Photo by Scott Umstattd on Unsplash

我在任何地方的各种竞赛中都读到过“异常”的定义。在这个混沌中,唯一的真理就是这个定义的可变性,即异常解释完全与兴趣域相关。

对这种行为的检测在每个行业中都是有用的,检测这些观察的难度取决于应用领域。如果您正在处理一个涉及人类活动的异常检测问题(如销售或需求预测),您可以利用人类行为的基本假设,规划一个更有效的解决方案。

这正是我们在这篇文章中所做的。我们试图预测纽约市在一个关键时期的出租车需求。我们制定了关于人类行为的简单而重要的假设,这将允许我们发现预测异常的简单解决方案。所有的脏活都是由喀拉斯开发的忠诚 LSTM 完成的,它可以同时预测和检测异常情况!

数据集

我从 Numenta 社区获取了用于我们分析的数据集。特别是,我选择了纽约出租车数据集。该数据集显示了纽约市从 2014 年 7 月 1 日到 2015 年 1 月 31 日的出租车需求,每半小时观察一次。

Example of Weekly NORMAL observations

在此期间,就偏离正常行为而言,存在 5 种异常。它们分别发生在纽约马拉松、感恩节、圣诞节、新年和暴风雪期间。

Example of Weekly ABNORMAL observations: NYC marathon — Christmas

我们的目的是提前探测到这些异常的观测结果!

从数据来看,我们注意到的第一个考虑因素是存在一个明显的每日模式(白天的需求高于夜间)。出租车需求似乎也受到每周趋势的驱动:在一周中的某些日子,出租车需求高于其他日子。我们简单地证明这个计算自相关。

timeLags = np.arange(1,10*48*7)
autoCorr = [df.value.autocorr(lag=dt) for dt in timeLags]plt.figure(figsize=(19,8))
plt.plot(1.0/(48*7)*timeLags, autoCorr)
plt.xlabel('time lag [weeks]')
plt.ylabel('correlation coeff', fontsize=12)

AutoCorrelation 10 weeks depth

我们现在能做的是记下这些重要的行为,以便我们进一步分析。我每小时计算并存储一周中每一天的平均值。当我们将数据标准化以构建我们的模型时,这将是有用的,以便减少各种时间依赖性(我计算将成为我们未来训练集的前 5000 个观察值的平均值)。

模型

我们需要一种策略来提前检测异常值。为此,我们决定关注出租车需求预测。我们希望开发一种模型,能够在考虑不确定性的情况下预测需求。一种方法是发展分位数回归。我们关注极值的预测:下限(第 10 个分位数),上限(第 90 个分位数)和经典的第 50 个分位数。计算第 90 个和第 10 个分位数,我们涵盖了现实中最有可能出现的值。这个范围的宽度可以很深;我们知道,当我们的模型对未来有把握时,它是小的,当我们的模型不能看到感兴趣领域的重要变化时,它可能是大的。我们利用了这种行为,并让我们的模型说明了出租车需求预测领域中的异常值检测。当我们的模型对未来有把握时,我们期望得到一个很小的区间(90-10 分位数范围),因为一切都在控制之中;另一方面,当间隔变大时,我们期望得到一个异常。这是可能的,因为我们的模型没有被训练来处理这种可能导致异常的场景。

我们在 Keras 建立了一个简单的 LSTM 神经网络,让这一切成为现实。我们的模型将接收过去的观察结果作为输入。我们用每日窗口大小(48 次观察:每半小时一次观察)来调整数据大小,以便为 LSTM 提供数据。当我们生成数据时,正如我上面提到的,我们操作对数转换和标准化减去平均每日小时值,以便将观察值视为其每日平均小时值的对数变化。我们以同样的方式构建目标变量,每半小时转换一次(我们希望预测接下来三十分钟的需求值)。

inputs = Input(shape=(X_train.shape[1], X_train.shape[2]))
lstm = Bidirectional(LSTM(64, return_sequences=True, dropout=0.5))(inputs, training = True)
lstm = Bidirectional(LSTM(16, return_sequences=False, dropout=0.5))(lstm, training = True)
dense = Dense(50)(lstm)
out10 = Dense(1)(dense)
out50 = Dense(1)(dense)
out90 = Dense(1)(dense)model = Model(inputs, [out10,out50,out90])

在 Keras 中操作分位数回归非常简单(我从这篇文章中获得了灵感)。我们很容易定义自定义分位数损失函数,该函数基于分位数以及误差是正的(实际>预测的)还是负的(实际<预测的)来惩罚误差。我们的网络有 3 个输出和 3 个损失,分别对应于我们试图预测的每个分位数。

def q_loss(q,y,f):
    e = (y-f)
    return K.mean(K.maximum(q*e, (q-1)*e), axis=-1)losses = [lambda y,f: q_loss(0.1,y,f), lambda y,f: q_loss(0.5,y,f), lambda y,f: q_loss(0.9,y,f)]model.compile(loss=losses, optimizer='adam', loss_weights = [0.3,0.3,0.3])

交叉问题

在处理 Keras 中的神经网络时,一个繁琐的问题是由于内部权值初始化导致的结果的不确定性。用它的提法,我们的问题似乎特别遭受这种问题;即计算分位数预测我们不能允许分位数重叠,这没有意义!为了避免这个陷阱,我在预测阶段使用自举:我重新激活我的网络的丢失(模型中的trainible:true),迭代预测 100 次,存储它们并最终计算期望的分位数(我在这篇文章中也使用了这个聪明的技术)。

pred_10, pred_50, pred_90 = [], [], []
NN = K.function([model.layers[0].input, K.learning_phase()], 
                [model.layers[-3].output,
                 model.layers[-2].output,
                 model.layers[-1].output])for i in tqdm.tqdm(range(0,100)):
    predd = NN([X_test, 0.5])
    pred_10.append(predd[0])
    pred_50.append(predd[1])
    pred_90.append(predd[2])

这个过程在下面用图表解释,重点放在预测的子集上。给定分位数引导,我们计算它们的汇总测量(红线),避免交叉。

q90 prediction bootstraps (cyan); q50 prediction bootstraps (blue); q10 prediction bootstraps (green)

结果

正如我前面提到的,我使用前 5000 个观察值进行训练,剩下的(大约 5000 个)用于测试。

我们的模型用第 50 个分位数达到了很好的预测出租车需求的性能。大约 0.055 的均方对数误差是一个辉煌的结果!这意味着 LSTM 网络能够理解驱动出租车需求的潜在规则。因此,我们的异常检测方法听起来很棒…我们计算了第 90 个分位数预测和第 10 个分位数预测之间的差异,看看发生了什么。

Real (red line); Quantile interval length (blue dots)

分位数区间范围(蓝点)在不确定时期较高。在其他情况下,正如我们所预期的那样,该模型往往能够很好地概括。更深入地说,我们开始调查这些高度不确定的时期。我们注意到这些与我们最初的假设相吻合。下面标绘的橙色圆圈分别是:纽约马拉松、感恩节、圣诞节、元旦和暴风雪。

Anomaly Detection

我们可以得出结论,我们达到了我们最初的目标:实现了强大的预测能力,并利用我们的模型的优势来识别不确定性。我们还利用这一点来说一些关于异常检测。

摘要

在这篇文章中,我复制了一个异常检测和预测的好方法。我们利用 LSTM 网络来了解纽约市的出租车需求行为。我们利用学到的知识进行预测,同时估计不确定性。我们隐含地将异常定义为不可预测的观察结果——即具有很大的不确定性。这个简单的假设允许我们的 LSTM 为我们做所有的工作。

查看我的 GITHUB 回购

保持联系: Linkedin

置换欠采样和时间相关的异常检测

原文:https://towardsdatascience.com/anomaly-detection-with-permutation-undersampling-and-time-dependency-5919e7c695d0?source=collection_archive---------31-----------------------

预测失衡情况下的政策转变

Photo by Francisco Ghisletti on Unsplash

在异常检测中,最乏味的问题之一是处理不平衡。我们作为数据科学家的角色是,在第一阶段,检测导致异常行为的模式。第二,开发特别的 ML 模型,该模型覆盖类不平衡并试图返回最佳结果。

我们在这篇文章中所做的就是利用不平衡。通过构建一个聪明的管道和一些技巧,我们将能够提高我们的 ML 模型的性能。

详细地说,我们分析了一个转换率预测的问题,但我们的方法并不只是专门针对这项任务。不平衡分类的类似问题可以是欺诈检测、流失预测、剩余寿命估计、毒性检测等等。

数据集

我为我们对 Kaggle 的分析找到了一个很好的基准,直接来自过去的比赛( Homesite 报价转换),目的是让一切变得更加真实和有趣。

该数据集代表了对购买保单感兴趣的大量客户的活动。每个条目对应于一个潜在客户,QuoteConversion_Flag 指示该客户是否购买了保单。

所提供的特征(总共 296 个)是匿名的,并且提供了潜在客户和保单的丰富表示。它们包括特定的覆盖范围信息、销售信息、个人信息、财产信息和地理信息。我们的任务是预测 QuoteConversion_Flag。

我们必须管理 211,859 次未转化中的 48,894 次成功转化(占总数的 23.07%)。如你所见,这是一个巨大的不平衡问题!

Label distribution on full dataset

验证策略

在我看来,当我们面临像这样的分类问题时,我们必须做的第一件事是对时间依赖的存在进行推理。这里,时间模式的存在由“原始报价日期”列给出。记住时间特征是重要的,以便开发一个健壮的验证方案,它以最好的方式反映现实;也就是说,我们希望开发一个能够预测未来可能转换的模型。因此,开发强大而稳定的解决方案的最佳方式是根据“报价日期”在培训/测试中分割我们的数据。鉴于此,我将原始数据按时间排序,并将前 70%(从 2013 年 1 月 1 日到 2014 年 8 月 25 日)作为训练,将后 10%(从 2015 年 3 月 9 日到 2015 年 5 月 18 日)作为测试。我没有故意使用 20%的数据(从 2014 年 8 月 25 日到 2015 年 3 月 9 日),因为我想制造一个漏洞,我很好奇我们的模型对未来的预测有多好。

凭借强大的验证渠道,我们已经处于有利位置。我们现在要做的是比较两种不同的架构。一个是经典的,由一个简单的交叉验证的逻辑回归组成,另一个是更复杂的,由多个交叉验证的逻辑回归组成,其中我们操作负下采样。我们简单地从多数类中随机抽取一部分条目,以使其等于少数类(转换)。

模型

现在我们已经介绍了所有我们需要的,让我们使它工作。我不太关注特征工程和模型选择;我更喜欢说明一个在各个方面都可以定制的通用方法。

首先,我实现了基线模型的结构。它由一个交叉验证模式组成,在每一个折叠中,我用主成分分析将原始特征的维度减少到前 50 个组件,并拟合一个逻辑回归。我尝试了 StratifiedCrossValidation 标准,以了解它处理不平衡的能力以及对我们的数据进行良好概括的可能性。使用 5 个折叠进行训练时,我在折叠外拆分中获得了 0.837 的平均 AUC,在测试中获得了 0.773 的最终 AUC,这导致训练数据明显过度拟合!

同样的,少数类的召回值极低,不能令人满意。

我们的第二个架构也是基于交叉验证模式,其中我像降维前一样操作,并拟合逻辑回归。与前一种情况不同,它在以下方面有所不同:

  • 我选择一个简单的 Kfold 交叉验证过程,没有洗牌;
  • 在交叉验证循环之前,我减少了对少数类采样不足的初始训练数据集(所选条目的选择是随机的);
  • 当整个交叉验证过程结束时,我存储结果并全部重复……我没有发疯,我全部重复(给定次数),改变构成欠采样类样本的条目,即,我改变采样的种子;
  • 最后,我平均所有的结果,获得置换种子,并计算性能(也堆叠西装)。
for s, seed in enumerate(seeds):

    train_pos = X_train.loc[y_train == 1, features].copy()
    train_pos['QuoteConversion_Flag'] = [1]*neg_istances
    train_pos['Quote_Date'] = Time_train[y_train == 1]
    train_neg = X_train.loc[y_train == 0, features].copy()
    train_neg['QuoteConversion_Flag'] = [0]*pos_istances
    train_neg['Quote_Date'] = Time_train[y_train == 0]
    train_neg = train_neg.sample(neg_istances, random_state=seed)

    train = pd.concat([train_pos, 
                       train_neg]).sort_values('Quote_Date')
    y = train.QuoteConversion_Flag.values
    train = train.drop(['Quote_Date',
                        'QuoteConversion_Flag'], 
                       axis=1).reset_index(drop=True)

    for fold,(in_index,oof_index) in enumerate(skf.split(train, y)):

        print(fold+1, 'FOLD --- SEED', seed)

        scaler = StandardScaler()
        pca = PCA(n_components=50, random_state=seed)

        y_in, y_oof = y[in_index], y[oof_index]
        X_in = train.iloc[in_index, :]
        X_in = scaler.fit_transform(X_in)
        X_in = pca.fit_transform(X_in)
        X_oof = train.iloc[oof_index, :]
        X_oof = scaler.transform(X_oof)
        X_oof = pca.transform(X_oof)

        model = LogisticRegression(C=0.1, solver="lbfgs", 
                                   max_iter=1000)
        model.fit(X_in, y_in)

        yoof[oof_index,s] = model.predict_proba(X_oof)[:,1]
        pred[:,s] += model.predict_proba(
                        pca.transform(
                            scaler.transform(X_test[features])
                        ))[:,1]

        print('AUC', roc_auc_score(y_oof, yoof[oof_index,s]))
        AUC[s] += roc_auc_score(y_oof, yoof[oof_index,s])  

        del model; del pca; del scaler

pred = pred/n_splits
AUC = AUC/n_splits

非折叠分割的 AUC 为 0.852(高于之前),但测试的相对 AUC 为 0.818。此外,混淆矩阵也有所改善。

这意味着我们能够在提高性能的同时减少过度拟合。这些结果之所以可能,有两个主要原因:

  • 我们利用了置换缩减采样,因为每次我改变种子时,我们都会在数据中引入一点多样性;
  • 我们选择了更现实的交叉验证模式,因为我们的数据遵循一种时间模式,使得现在(训练)不同于未来(测试)。没有洗牌的 K-fold 能够在训练中重现这种依赖性,降低过度拟合。

摘要

在这篇文章中,我创建了一个有效的管道来处理训练和测试之间的数据不平衡和差异的情况。正如你所看到的,这是现实生活中的一个常见场景,但也经常在许多 Kaggle 比赛中出现。我们可以做的第一件事是定义一个好的验证模式,并尝试从采样技术中提取价值。这将允许我们获得更好的性能并减少计算时间。

查看我的 GITHUB 回购

保持联系: Linkedin

使用 SQL 进行异常检测

原文:https://towardsdatascience.com/anomaly-detection-with-sql-7700c7516d1d?source=collection_archive---------6-----------------------

有很多方法可以检测数据中的异常,就像生活中的大多数事情一样,没有一个明确的“正确的方法”来做到这一点。您采用的方法将由您的数据决定,但也取决于项目的要求。

这是否需要像信用欺诈检测一样尽可能准确,您是否只需要监控一些潜在问题的指标,这是否需要快速启动并运行,或者您是否有 6 个月的时间将其投入生产,您有什么样的可用资源等。

Anomalies Detected!!

异常检测有两种基本方法。你可以走基于规则的路线,也可以走机器学习的路线。机器学习模型,如隔离森林、局部离群因子、自动编码器等。都可以用来成功检测异常。如果你走这条路,你应该看看 sklearn 的包以及《 手无监督学习 这本书,它们都是很好的起点。

然而,基于规则的方法工作得很好,更容易实现,更容易投入生产,启动和运行更快。根据您的需求,它们可能是最佳解决方案。

听着我明白了,每个人都想立即去机器/深度学习解决问题,因为让我们面对它,它很有趣,也很有挑战性。然而,走机器学习路线并不总是最好的选择,尤其是在商业环境中。

一种基于规则的方法效果很好并且易于在 SQL 中实现,那就是使用四分位数范围。IQR 被定义为数据集的 75%和 25%之间的差值。

如果一个数据点高于第 75 百分位 1.5 倍 IQR 或更多,或者低于第 25 百分位 1.5 倍 IQR 或更少,它们可以被认为是异常值。

  • *正异常值=第 75 百分位+ 1.5 (第 75 百分位-第 25 百分位)
  • *负异常值=第 25 百分位- 1.5 (第 75 百分位-第 25 百分位)

为什么是 1.5 倍而不是 2 倍或 3 倍?1.5x 相当于平均值以上的 3 个标准差(见下图)。你当然可以把它改成 1.75 倍或者 2.25 倍等等。这取决于您希望异常值检测有多“敏感”,这是使用 IQR 的另一个优点。

由于 IQR 使用中值而不是平均值,因此它被视为尺度的稳健度量,与使用平均值的度量(如标准差)相比,受少数异常值影响的可能性更小。这将更容易识别实际的异常值。

如果你曾经看过箱线图,那就是 IQR 离群点检测方法的可视化。“盒子”是 IQR,“胡须”位于第 25 和第 75 百分位,任何高于这些值的数据点(称为“飞行者”)都是异常值,如下图所示:

Source: Wikipedia

在我们开始这个例子之前,还有一些关于异常检测的注意事项。异常检测可以是单变量或多变量的。单变量更简单,更容易解释,因为您可以很容易地知道哪个指标触发了异常。如果您有多个指标,那么您可以设置单独的查询来检测每个指标的异常,这使得最终产品更容易理解。如果你走多元路线,机器学习可能更适合。异常检测也可以是有监督的或无监督的,但大多数时候是无监督的,就像我们在这里做的一样。

例子

我将使用 BigQuery 中的一个公共数据集,因此您可以自己重新创建它。“爱荷华州酒类销售”数据集(big query-public-data . Iowa _ liquid _ Sales . Sales)包含了爱荷华州自 2012 年以来的每日酒类销售情况。

酒类销售有很多不同的方式,包括城市、县、经纬度、类别、售出的瓶数、售出的数量等。在本例中,我将只查看一天的总销售额,但是您可以在表中的任何分项中发现异常。

带评论的完整问题可以在我的 GitHub 页面上找到,这里是一个要点。让我们来分解一下这个查询是做什么的。

我做的第一件事是创建一个 CTE(通用表表达式),用第 25 个百分位数、第 75 个百分位数和 IQR 制作一个表,用于查询的主要部分。

为了得到四分位数,我使用 BigQuery 的近似分位数函数。我们说我们需要 4 个分位数来创建一个数组,所以我们只需要用 offset 函数从数组中选择我们想要的分位数。

返回的数组如下所示[最小值,25,50,75,最大值]。如您所见,它还返回最小值和最大值。索引从零开始,所以应该是[0,1,2,3,4]。因此,对于第 25 个百分位数,我们使用偏移函数选择位置 1 的元素,依此类推。

接下来,我们进入查询的主要部分:

从内部查询开始,我们将再次获取每天的总酒类销售额,然后与我们在上面创建的 IQR CTE 进行交叉连接(不过要注意大型数据集上的交叉连接)。然后,我们将创建一个 case 语句,说明当天的酒类销售额是正/负异常值还是非异常值(内标)。为了便于显示,我们还获取了当天的总销售额和日期,并按日总销售额降序排列。这给了我们:

我们现在有一个名为“type”的列,它将告诉我们当天的酒类销售额是内值、正值异常值还是负值异常值。

让我们看看数据的分布情况,以确认查询是否有效。这是一个柱状图,左边显示的是几乎没有销售的日子,右边显示的是销售非常高的日子。这两个问题都应该进一步调查。

这是一个显示异常值的箱线图。您可以看到,箱线图反映了查询,正异常值被确定为大约 2.1MM,就像我们在上面的输出中看到的那样。

现在,您可以安排这个查询每天运行(或者根据需要频繁运行)并输出到一个表中。然后你有一个表,自动更新,识别离群值,你可以连接到你的可视化工具的选择。

您还可以更进一步,在云函数/lambda 中运行它,并在检测到异常时通过 api 自动发送松弛警报/电子邮件,并提供一些关于异常的基本信息。我用这种方法自动对工作中的异常情况发出松弛警报,效果非常好。以后我会写一篇关于这个的帖子。

任何会使用 SQL 的人(分析师、数据科学家、工程师等)都很容易在短时间内建立并运行这样的东西。)而且也很有效。现在你可以回到你的机器/深度学习😃

基于时间序列预测的异常检测

原文:https://towardsdatascience.com/anomaly-detection-with-time-series-forecasting-c34c6d04b24a?source=collection_archive---------0-----------------------

嗨,这是一篇关于异常检测的后续文章(链接到上一篇文章:https://medium . com/my ntra-engineering/anomaly-detection-with-isolation-forest-visualization-23 CD 75 c 281 e 2其中我们使用无监督学习进行了异常检测)。

这里我们将看到用时间序列预测检测异常。时间序列是与时间相关的任何数据(每天、每小时、每月等)。例如:商店每天的收入是一个天级别的时间序列数据。许多用例,如需求估计、销售预测是一个典型的时间序列预测问题,可以通过像萨里玛、LSTM、霍尔特温特斯等算法来解决。时间序列预测通过用当前数据估计未来需求,帮助我们为未来需求做准备。一旦我们有了预测,我们就可以使用这些数据,通过与实际数据进行比较来发现异常情况。我们来实现一下,看看它的利弊。

安装和导入可视化库

#Installing specific version of plotly to avoid Invalid property for color error in recent version which needs change in layout
!pip install plotly==2.7.0
import pandas as pd
import numpy as np
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import plotly.plotly as py
import matplotlib.pyplot as plt
from matplotlib import pyplot
import plotly.graph_objs as go
init_notebook_mode(connected=True)
time_series_df=pd.read_csv('../input/time-series-data/time_series_data.csv')
time_series_df.head()

这里的数据顺序很重要,应该是**按时间顺序* *因为我们要预测下一个点。

将 load_date 列转换为 datetime 格式,并根据日期对数据进行排序。

time_series_df.load_date = pd.to_datetime(time_series_df.load_date, format='%Y%m%d')
time_series_df = time_series_df.sort_values(by="load_date")
time_series_df = time_series_df.reset_index(drop=True)
time_series_df.head()

提取数值并应用对数变换以稳定数据中的方差或在将数据输入模型之前使其稳定

actual_vals = time_series_df.actuals.values
actual_log = np.log10(actual_vals)

用测试数据中的 70 分来划分数据进行训练和测试。

首先让我们尝试应用 SARIMA 算法进行预测。SARIMA 代表季节性自回归综合移动平均线。它有一个季节性参数,由于我们销售数据的每周季节性,我们将其初始化为 7。其他参数是 p、d、q,它们是基于 ACF 和 PACF 图确定的,或者理想情况下,我们应该使用预测误差最小的参数。

更多细节可以在这里找到:https://people.duke.edu/~rnau/arimrule.htm

我不会在这里讨论获得正确参数集的问题,我们稍后将使用 Auto Arima 来解决这个问题,它允许我们在误差最小的范围内获得最佳参数集。

这里我指定差分因子(d)为 1。它帮助我们去除数据中的趋势和周期。

import math
import statsmodels.api as sm
import statsmodels.tsa.api as smt
from sklearn.metrics import mean_squared_error
from matplotlib import pyplot
import matplotlib.pyplot as plt
import plotly.plotly as py
import plotly.tools as tlstrain, test = actual_vals[0:-70], actual_vals[-70:]train_log, test_log = np.log10(train), np.log10(test)my_order = (1, 1, 1)
my_seasonal_order = (0, 1, 1, 7)

每次我们预测下一个数据点的,我们循环遍历训练数据以预测下一个数据,并在预测后添加下一个数据点用于进一步预测。

这就像一个移动窗口日水平数据(例如:前 90 点用于预测任何给定时间的下一点)。

通过的 10 次方变换将预测数据转换回比例,并绘制结果。

history = [x for x in train_log]
predictions = list()
predict_log=list()
for t in range(len(test_log)):
    model = sm.tsa.SARIMAX(history, order=my_order, seasonal_order=my_seasonal_order,enforce_stationarity=False,enforce_invertibility=False)
    model_fit = model.fit(disp=0)
    output = model_fit.forecast()
    predict_log.append(output[0])
    yhat = 10**output[0]
    predictions.append(yhat)
    obs = test_log[t]
    history.append(obs)
   # print('predicted=%f, expected=%f' % (output[0], obs))
#error = math.sqrt(mean_squared_error(test_log, predict_log))
#print('Test rmse: %.3f' % error)
# plot
figsize=(12, 7)
plt.figure(figsize=figsize)
pyplot.plot(test,label='Actuals')
pyplot.plot(predictions, color='red',label='Predicted')
pyplot.legend(loc='upper right')
pyplot.show()

Actuals vs Predict forecast plot

这是一个很好的时间序列预测。趋势、季节性是时间序列数据中的两个重要因素,如果您的算法能够捕捉到您数据的趋势(上升/下降),并且如果您的数据是季节性的(每周、每天、每年的模式),那么您的算法就适合您的情况。

在这里,我们可以观察到,我们的 SARIMA 算法从峰值中捕捉到了趋势(不是通过复制它,而是通过捕捉峰值),并在正常情况下很好地预测了实际值。

我们在这里指定的参数似乎很适合这个指标,但是要进行绘图、验证和调整参数将是一项非常艰巨的任务。一个解决方案是 Auto Arima ,它在我们指定的范围内返回算法的最佳参数集。

为 auto arima 安装金字塔-arima。

!pip install pyramid-arima
from pyramid.arima import auto_arima
stepwise_model = auto_arima(train_log, start_p=1, start_q=1,
                           max_p=3, max_q=3, m=7,
                           start_P=0, seasonal=True,
                           d=1, D=1, trace=True,
                           error_action='ignore',  
                           suppress_warnings=True, 
                           stepwise=True)

让我们使用 auto_arima 查找 p 和 q 参数,并将 d 指定为 1 表示一阶差分,将季节性指定为 7 表示每周季节性。

现在,auto arima 模型可以通过我们在上面执行的相同过程用于逐步预测:

import math
import statsmodels.api as sm
import statsmodels.tsa.api as smt
from sklearn.metrics import mean_squared_error
train, test = actual_vals[0:-70], actual_vals[-70:]train_log, test_log = np.log10(train), np.log10(test)# split data into train and test-setshistory = [x for x in train_log]
predictions = list()
predict_log=list()
for t in range(len(test_log)):
    #model = sm.tsa.SARIMAX(history, order=my_order, seasonal_order=my_seasonal_order,enforce_stationarity=False,enforce_invertibility=False)
    stepwise_model.fit(history)
    output = stepwise_model.predict(n_periods=1)
    predict_log.append(output[0])
    yhat = 10**output[0]
    predictions.append(yhat)
    obs = test_log[t]
    history.append(obs)
    #print('predicted=%f, expected=%f' % (output[0], obs))
#error = math.sqrt(mean_squared_error(test_log, predict_log))
#print('Test rmse: %.3f' % error)
# plot
figsize=(12, 7)
plt.figure(figsize=figsize)
pyplot.plot(test,label='Actuals')
pyplot.plot(predictions, color='red',label='Predicted')
pyplot.legend(loc='upper right')
pyplot.show()

在这种情况下,auto arima 和我们的初始 SARIMA 在预测方面做得很好,也没有过多地追逐实际值。

接下来,让我们用可用的实际数据和预测结果创建一个数据框架

predicted_df=pd.DataFrame()
predicted_df['load_date']=time_series_df['load_date'][-70:]
predicted_df['actuals']=test
predicted_df['predicted']=predictions
predicted_df.reset_index(inplace=True)
del predicted_df['index']
predicted_df.head()

我们有预测和实际的结果,使用这些信息来检测异常,我使用了数据分布的属性。请注意,这仅在数据分布为正态/高斯时才有效。

我检测异常的步骤:
1。计算误差项(实际-预测)。
2。计算滚动平均值和滚动标准差(窗口为一周)。
3。将误差为 1.5、1.75 和 2 个标准偏差的数据分类为低、中、高异常。(基于此属性,5%的数据点将被识别为异常)

我使用 lambda 函数对基于误差和标准偏差的异常进行分类,而不是使用单独的循环和函数。

import numpy as np
def detect_classify_anomalies(df,window):
    df.replace([np.inf, -np.inf], np.NaN, inplace=True)
    df.fillna(0,inplace=True)
    df['error']=df['actuals']-df['predicted']
    df['percentage_change'] = ((df['actuals'] - df['predicted']) / df['actuals']) * 100
    df['meanval'] = df['error'].rolling(window=window).mean()
    df['deviation'] = df['error'].rolling(window=window).std()
    df['-3s'] = df['meanval'] - (2 * df['deviation'])
    df['3s'] = df['meanval'] + (2 * df['deviation'])
    df['-2s'] = df['meanval'] - (1.75 * df['deviation'])
    df['2s'] = df['meanval'] + (1.75 * df['deviation'])
    df['-1s'] = df['meanval'] - (1.5 * df['deviation'])
    df['1s'] = df['meanval'] + (1.5 * df['deviation'])
    cut_list = df[['error', '-3s', '-2s', '-1s', 'meanval', '1s', '2s', '3s']]
    cut_values = cut_list.values
    cut_sort = np.sort(cut_values)
    df['impact'] = [(lambda x: np.where(cut_sort == df['error'][x])[1][0])(x) for x in
                               range(len(df['error']))]
    severity = {0: 3, 1: 2, 2: 1, 3: 0, 4: 0, 5: 1, 6: 2, 7: 3}
    region = {0: "NEGATIVE", 1: "NEGATIVE", 2: "NEGATIVE", 3: "NEGATIVE", 4: "POSITIVE", 5: "POSITIVE", 6: "POSITIVE",
              7: "POSITIVE"}
    df['color'] =  df['impact'].map(severity)
    df['region'] = df['impact'].map(region)
    df['anomaly_points'] = np.where(df['color'] == 3, df['error'], np.nan)
    df = df.sort_values(by='load_date', ascending=False)
    df.load_date = pd.to_datetime(df['load_date'].astype(str), format="%Y-%m-%d")return df

下面是一个可视化结果的函数。清晰全面的可视化同样重要,有助于业务用户对异常情况提供反馈,并使结果具有可操作性。

第一个图中的误差项指定了上限和下限。

突出显示异常的实际值图将易于用户解释/验证。因此,第二个图突出显示了实际值和预测值以及异常情况。

蓝线-实际值

橙色线条-预测的

红色-错误

绿色——移动平均线

虚线——正常行为的上限和下限

def plot_anomaly(df,metric_name):
    #error = pd.DataFrame(Order_results.error.values)
    #df = df.sort_values(by='load_date', ascending=False)
    #df.load_date = pd.to_datetime(df['load_date'].astype(str), format="%Y%m%d")
    dates = df.load_date
    #meanval = error.rolling(window=window).mean()
    #deviation = error.rolling(window=window).std()
    #res = error#upper_bond=meanval + (2 * deviation)
    #lower_bond=meanval - (2 * deviation)#anomalies = pd.DataFrame(index=res.index, columns=res.columns)
    #anomalies[res < lower_bond] = res[res < lower_bond]
    #anomalies[res > upper_bond] = res[res > upper_bond]
    bool_array = (abs(df['anomaly_points']) > 0)#And a subplot of the Actual Values.
    actuals = df["actuals"][-len(bool_array):]
    anomaly_points = bool_array * actuals
    anomaly_points[anomaly_points == 0] = np.nan#Order_results['meanval']=meanval
    #Order_results['deviation']=deviationcolor_map= {0: "'rgba(228, 222, 249, 0.65)'", 1: "yellow", 2: "orange", 3: "red"}
    table = go.Table(
    domain=dict(x=[0, 1],
                y=[0, 0.3]),
    columnwidth=[1, 2 ],
    #columnorder=[0, 1, 2,],
    header = dict(height = 20,
                  values = [['<b>Date</b>'],['<b>Actual Values </b>'],
                            ['<b>Predicted</b>'], ['<b>% Difference</b>'],['<b>Severity (0-3)</b>']],
                 font = dict(color=['rgb(45, 45, 45)'] * 5, size=14),
                  fill = dict(color='#d562be')),
    cells = dict(values = [df.round(3)[k].tolist() for k in ['load_date', 'actuals', 'predicted',
                                                               'percentage_change','color']],
                 line = dict(color='#506784'),
                 align = ['center'] * 5,
                 font = dict(color=['rgb(40, 40, 40)'] * 5, size=12),
                 #format = [None] + [",.4f"] + [',.4f'],#suffix=[None] * 4,
                 suffix=[None] + [''] + [''] + ['%'] + [''],
                 height = 27,
                 #fill = dict(color=['rgb(235, 193, 238)', 'rgba(228, 222, 249, 0.65)']))
                 fill=dict(color=  # ['rgb(245,245,245)',#unique color for the first column
                      [df['color'].map(color_map)],
                      )
    ))#df['ano'] = np.where(df['color']==3, df['error'], np.nan)anomalies = go.Scatter(name="Anomaly",
                       x=dates,
                       xaxis='x1',
                       yaxis='y1',
                       y=df['anomaly_points'],
                       mode='markers',
                       marker = dict(color ='red',
                      size = 11,line = dict(
                                         color = "red",
                                         width = 2)))upper_bound = go.Scatter(hoverinfo="skip",
                         x=dates,
                         showlegend =False,
                         xaxis='x1',
                         yaxis='y1',
                         y=df['3s'],
                         marker=dict(color="#444"),
                         line=dict(
                             color=('rgb(23, 96, 167)'),
                             width=2,
                             dash='dash'),
                         fillcolor='rgba(68, 68, 68, 0.3)',
                         fill='tonexty')lower_bound = go.Scatter(name='Confidence Interval',
                          x=dates,
                         xaxis='x1',
                         yaxis='y1',
                          y=df['-3s'],
                          marker=dict(color="#444"),
                          line=dict(
                              color=('rgb(23, 96, 167)'),
                              width=2,
                              dash='dash'),
                          fillcolor='rgba(68, 68, 68, 0.3)',
                          fill='tonexty')Actuals = go.Scatter(name= 'Actuals',
                     x= dates,
                     y= df['actuals'],
                    xaxis='x2', yaxis='y2',
                     mode='line',
                     marker=dict(size=12,
                                 line=dict(width=1),
                                 color="blue"))Predicted = go.Scatter(name= 'Predicted',
                     x= dates,
                     y= df['predicted'],
                    xaxis='x2', yaxis='y2',
                     mode='line',
                     marker=dict(size=12,
                                 line=dict(width=1),
                                 color="orange"))# create plot for error...
    Error = go.Scatter(name="Error",
                   x=dates, y=df['error'],
                   xaxis='x1',
                   yaxis='y1',
                   mode='line',
                   marker=dict(size=12,
                               line=dict(width=1),
                               color="red"),
                   text="Error")anomalies_map = go.Scatter(name = "anomaly actual",
                                   showlegend=False,
                                   x=dates,
                                   y=anomaly_points,
                                   mode='markers',
                                   xaxis='x2',
                                   yaxis='y2',
                                    marker = dict(color ="red",
                                  size = 11,
                                 line = dict(
                                     color = "red",
                                     width = 2)))Mvingavrg = go.Scatter(name="Moving Average",
                           x=dates,
                           y=df['meanval'],
                           mode='line',
                           xaxis='x1',
                           yaxis='y1',
                           marker=dict(size=12,
                                       line=dict(width=1),
                                       color="green"),
                           text="Moving average")axis=dict(
    showline=True,
    zeroline=False,
    showgrid=True,
    mirror=True,
    ticklen=4,
    gridcolor='#ffffff',
    tickfont=dict(size=10))layout = dict(
    width=1000,
    height=865,
    autosize=False,
    title= metric_name,
    margin = dict(t=75),
    showlegend=True,
    xaxis1=dict(axis, **dict(domain=[0, 1], anchor='y1', showticklabels=True)),
    xaxis2=dict(axis, **dict(domain=[0, 1], anchor='y2', showticklabels=True)),
    yaxis1=dict(axis, **dict(domain=[2 * 0.21 + 0.20 + 0.09, 1], anchor='x1', hoverformat='.2f')),
    yaxis2=dict(axis, **dict(domain=[0.21 + 0.12, 2 * 0.31 + 0.02], anchor='x2', hoverformat='.2f')))fig = go.Figure(data = [table,anomalies,anomalies_map,
                        upper_bound,lower_bound,Actuals,Predicted,
                        Mvingavrg,Error], layout = layout)iplot(fig)
pyplot.show()classify_df=detect_classify_anomalies(predicted_df,7)
classify_df.reset_index(inplace=True)
del classify_df['index']
plot_anomaly(classify_df,"metric_name")

通过使用滚动平均值和标准偏差,我们能够避免在大减价日这样的场景中出现连续的错误异常。

突出显示第一个峰值或谷值,之后调整阈值。

此外,提供实际数据的表格根据异常水平预测了变化和条件格式。

接下来,我们还尝试使用 LSTM 预测,这是一个递归神经网络。

https://machine learning mastery . com/time-series-prediction-lstm-recurrent-neural-networks-python-keras/是一个非常好的使用 lstm 进行时间序列预测的教程,我们将在这里使用部分代码作为我们的用例。

以下是用于差分、与它们的倒数一起缩放以及训练和预测LSTM的辅助函数。

from pandas import DataFrame
from pandas import Series
from pandas import concat
from pandas import read_csv
from pandas import datetime
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from math import sqrt

# frame a sequence as a supervised learning problem
def timeseries_to_supervised(data, lag=1):
    df = DataFrame(data)
    columns = [df.shift(i) for i in range(1, lag+1)]
    columns.append(df)
    df = concat(columns, axis=1)
    df.fillna(0, inplace=True)
    return df# create a differenced series
def difference(dataset, interval=1):
    diff = list()
    for i in range(interval, len(dataset)):
        value = dataset[i] - dataset[i - interval]
        diff.append(value)
    return Series(diff)# invert differenced value
def inverse_difference(history, yhat, interval=1):
    return yhat + history[-interval]# scale train and test data to [-1, 1]
def scale(train, test):
    # fit scaler
    scaler = MinMaxScaler(feature_range=(-1, 1))
    scaler = scaler.fit(train)
    # transform train
    train = train.reshape(train.shape[0], train.shape[1])
    train_scaled = scaler.transform(train)
    # transform test
    test = test.reshape(test.shape[0], test.shape[1])
    test_scaled = scaler.transform(test)
    return scaler, train_scaled, test_scaled# inverse scaling for a forecasted value
def invert_scale(scaler, X, value):
    new_row = [x for x in X] + [value]
    array = np.array(new_row)
    array = array.reshape(1, len(array))
    inverted = scaler.inverse_transform(array)
    return inverted[0, -1]# fit an LSTM network to training data
def fit_lstm(train, batch_size, nb_epoch, neurons):
    X, y = train[:, 0:-1], train[:, -1]
    X = X.reshape(X.shape[0], 1, X.shape[1])
    model = Sequential()
    model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True))
    model.add(Dense(1))
    model.compile(loss='mean_squared_error', optimizer='adam')
    for i in range(nb_epoch):
        model.fit(X, y, epochs=1, batch_size=batch_size, verbose=0, shuffle=False)
        model.reset_states()
    return model# make a one-step forecast
def forecast_lstm(model, batch_size, X):
    X = X.reshape(1, 1, len(X))
    yhat = model.predict(X, batch_size=batch_size)
    return yhat[0,0]#### LSTM
supervised = timeseries_to_supervised(actual_log, 1)
supervised_values = supervised.values# split data into train and test-sets
train_lstm, test_lstm = supervised_values[0:-70], supervised_values[-70:]# transform the scale of the data
scaler, train_scaled_lstm, test_scaled_lstm = scale(train_lstm, test_lstm)# fit the model                 batch,Epoch,Neurons
lstm_model = fit_lstm(train_scaled_lstm, 1, 850 , 3)
# forecast the entire training dataset to build up state for forecasting
train_reshaped = train_scaled_lstm[:, 0].reshape(len(train_scaled_lstm), 1, 1)
#lstm_model.predict(train_reshaped, batch_size=1)

使用 LSTM 预测数据并绘制结果

from matplotlib import pyplot
import matplotlib.pyplot as plt
import plotly.plotly as py
import plotly.tools as tls# walk-forward validation on the test data
predictions = list()
for i in range(len(test_scaled_lstm)):
#make one-step forecast
    X, y = test_scaled_lstm[i, 0:-1], test_scaled_lstm[i, -1]
    yhat = forecast_lstm(lstm_model, 1, X)
    # invert scaling
    yhat = invert_scale(scaler, X, yhat)
    # invert differencing
    #yhat = inverse_difference(raw_values, yhat, len(test_scaled)+1-i)
    # store forecast
    predictions.append(10**yhat)
    expected = actual_log[len(train_lstm) + i ]
# line plot of observed vs predicted
figsize=(12, 7)
plt.figure(figsize=figsize)
pyplot.plot(actual_vals[-70:],label='Actuals')
pyplot.plot(predictions, color = "red",label='Predicted')
pyplot.legend(loc='upper right')
pyplot.show()

LSTM 也很适合这个指标。LSTM 神经网络的重要参数是激活函数、神经元数量、批量大小和时期,需要对其进行调整以获得更好的结果。

现在,让我们在不同的指标数据中尝试一下。数据是同一时期的。

tf_df=pd.read_csv('../input/forecast-metric2/time_series_metric2.csv')
tf_df.head()

按照与上述相同的步骤,我们使用 auto arima 获得最佳参数并逐步预测。

绘制实际结果和预测结果。

actual_vals = tf_df.actuals.values
train, test = actual_vals[0:-70], actual_vals[-70:]
train_log, test_log = np.log10(train), np.log10(test)
from pyramid.arima import auto_arima
stepwise_model = auto_arima(train_log, start_p=1, start_q=1,
                           max_p=3, max_q=3, m=7,
                           start_P=0, seasonal=True,
                           d=1, D=1, trace=True,
                           error_action='ignore',  
                           suppress_warnings=True, 
                           stepwise=True)
history = [x for x in train_log]
predictions = list()
predict_log=list()
for t in range(len(test_log)):
    #model = sm.tsa.SARIMAX(history, order=my_order, seasonal_order=my_seasonal_order,enforce_stationarity=False,enforce_invertibility=False)
    stepwise_model.fit(history,enforce_stationarity=False,enforce_invertibility=False)
    output = stepwise_model.predict(n_periods=1)
    predict_log.append(output[0])
    yhat = 10**output[0]
    predictions.append(yhat)
    obs = test_log[t]
    history.append(obs)
    #print('predicted=%f, expected=%f' % (output[0], obs))
#error = math.sqrt(mean_squared_error(test_log, predict_log))
#print('Test rmse: %.3f' % error)
# plot
figsize=(12, 7)
plt.figure(figsize=figsize)
pyplot.plot(test,label='Actuals')
pyplot.plot(predictions, color='red',label='Predicted')
pyplot.legend(loc='upper right')
pyplot.show()

这里,算法试图追踪实际值。虽然这可能是一个误差较低的好预测,但是实际中的异常行为不能用这个来识别。

这是一个使用预测技术进行异常检测的问题。我们试图捕捉数据中的趋势/季节性,同时不对误差进行过多优化,以获得实际值的精确副本(这使得我们难以发现异常)。

每个指标都需要用微调的参数进行验证,以便在使用预测来检测异常时检测到异常。此外,对于具有不同数据分布的指标,需要遵循不同的方法来识别异常。

另一个缺点是,隔离林我们检测到一个用例的异常,该用例一次包含多个指标,我们向下钻取其中单个指标的异常。而使用预测机制,我们需要一个单独的关联逻辑,因为预测是针对指标的

而像隔离森林这样的算法从数据中分离出异常行为,这些异常行为可用于归纳多个指标。

又一起自动驾驶车祸,又一堂人工智能开发课

原文:https://towardsdatascience.com/another-self-driving-car-accident-another-ai-development-lesson-b2ce3dbb4444?source=collection_archive---------13-----------------------

作为一名数据科学家,优步能从自动驾驶汽车事故中学到什么

Photo from https://blogs.nvidia.com

他的事故实际上发生在大约一年半前,发生在一辆优步的自动驾驶汽车上,并夺走了一名女性的生命。这对 AI 社区是一个严重的提醒,正在做的工作承载着很多重量,有时是其他人的生命。

对所发生事情的回顾

T 他的可怕事故发生在 2018 年 3 月 19 日深夜。一辆优步自动驾驶汽车在自动模式下行驶,方向盘后面有一名安全驾驶员,在亚利桑那州坦佩撞死了一名女子。详细的调查结果可以在这里找到。从仪表板摄像头和内部驾驶座摄像头的录像来看,事故发生在一条光线不足的道路上,限速 40 英里/小时。在汽车撞上这名女子之前,这名安全司机正在看她的手机(可能在看 Hulu)。根据优步在撞车后获得的遥测数据,算法将这些女性分类为'未知物体,然后是'车辆,然后是'自行车',在此过程中,优柔寡断导致了非常晚的行动(在撞车前 1.3 秒命令汽车停下),最终导致了悲剧的发生。激光雷达或雷达传感器都没有触发,也没有付费的安全司机看到行人。以上任何一种方法,如果有效,都有可能挽救这位妇女的生命。这起事故已经过去了一段时间,优步已经恢复在道路上测试他们的自动驾驶汽车。然而,从数据科学的角度多思考一些问题可能是有价值的,这些问题是什么,优步的自动驾驶系统中有哪些缺陷导致了这场悲剧。

自动驾驶系统可能存在的缺陷

在深入探讨自动驾驶系统的潜在缺陷之前,值得注意的是,自动驾驶汽车实际上是人工智能的最先进应用,最接近于 AGI(人工智能)。首先,驾驶是一项非常复杂且潜在相当危险的行为。自动驾驶汽车必须应对的环境可能非常复杂,需要各种情况意识:其他汽车、行人、自行车、交通信号、标志、天气、路况等。诚然,这些年人工智能已经取得了很大的进步,但对于这项任务来说,它足够好吗?不管答案是什么,所有可能的问题都应该彻底解决和测试,不遗余力。这导致了该系统的第一个也是最重要的方面,即开发自动驾驶汽车的团队。

应用人工智能开发团队有时工程师人手不足

Photo from https://365datascience.com

做数据科学工作不一定需要硕士或者博士,但是统计数据显示行业内的数据科学家绝大多数至少有硕士学历。他们中的很大一部分人甚至拥有博士学位。这是非常合理的,因为人工智能和数据科学不是微不足道的领域。它需要多年的数学、计算机科学和各种技术的训练。这已经是业界的共识。这种共识如此强烈,有时人们会忘记其他同样重要的角色,以使自动驾驶汽车等现实生活中的人工智能项目取得成功。最重要的是,工程。如果需要证明某个算法对于某个单一目的任务的性能(比如放射学图像识别),你不需要太多的工程能力。一个可靠的数据科学家可能会做得足够好。如果在 web 上开发和部署一个机器学习应用程序来分析评论情绪是一项任务,那么你可能需要雇用更多可靠的开发人员和 DevOps 工程师来确保该应用程序结构良好、精心编码并且易于维护。那么,如果你想建立一个自动驾驶汽车系统,需要在现实世界中维持许多小时而不发生任何事故,那该怎么办呢?你可能想雇佣汽车设计师、监管专家、汽车安全专家、物理学家和一些顶尖的数据科学家来创建一个多元化的团队,以便正确处理这项任务。对于这起优步自动驾驶汽车事件,自动驾驶汽车未能迅速做出反应的一个原因是,激光雷达和雷达系统都没有捕捉到过马路的女子。优步从使用 7 个激光雷达传感器改为只在汽车顶部使用一个,这在汽车周围产生了一些“盲点”。这是什么原因呢?出于安全原因,是否有其他工程债务需要承保?传感器的放置是否存在任何设计缺陷?环境中是否存在任何干扰问题?传感器和中央计算机之间的通信通道是否顺畅?这并不是说这些是确切的情况,只是这些是需要被询问和解决的问题,解决这些问题的最佳人才类型是工程师,而不是数据科学家。

小数据

现在,小数据是一个需要解决的数据科学问题。这意味着要建立一个有效的模型,每种情况下都需要大量的数据来训练模型。但有时不平衡数据问题很难解决,而且成本很高。以自动驾驶汽车为例。说到安全,最重要的是什么时候出了问题。收集的不同事故类型的数据越多,就越有利于训练一个足够稳健的模型,使其能够在所有条件下自行处理。但与装有黑匣子的飞机不同,车祸数据更难收集。首先,很难“产生”或“制造”事故。其次,并不是所有的汽车都配备了传感器来收集事故发生时的数据(一些更“智能”的汽车,如特斯拉,可能可以,但大多数汽车还没有)。作为数据科学家,一个共识是高性能模型的瓶颈通常不是算法,而是数据。如果没有足够的车祸相关数据,数据科学家将很难开发出一个能够很好地处理这些事故类型的模型。要做出一个能在街上驾驶汽车,转弯,适当加速/减速的自动驾驶汽车系统,并不是最难的任务。最困难的任务是在没有足够数据的情况下,创建一个能很好地处理所有事故的模型。

处理边缘情况

这实际上是小数据问题的一个更极端的例子,但值得一提。安全的一个经验法则是考虑所有可能出错的边缘情况,并做好准备。这对人类来说不是问题,因为人类比任何算法都具有常识和更广泛的情境意识,所以人类更有准备来处理边缘情况,但算法通常不够复杂,因此需要更多的工作。

Photo from https://www.chron.com

让我们想象一些边缘情况。

道路上的洪水:人类会后退,或者选择一些更平坦的草地来穿越洪水,但如果汽车只接受在道路上驾驶的训练,它无法正确处理这一点。

非常滑的路:人类会改变他们的驾驶模式,非常轻柔地转弯以避免打滑。或者停下来放防雪链,AI 就很难达到同等水平的灵活度。

涂鸦之路:人类很容易知道发生了什么,不会出错,但 AI 如果没有受过涂鸦之路的训练,可能会把涂鸦误认为是真实的道路指引。

这个清单还在继续。如果你能从过去的驾驶经历中想到你遇到的其他边缘案例,请在下面留下回应。底线是,在现实世界中驾驶需要更复杂的系统来处理所有奇怪的情况,人类非常擅长这一点(因此这是有保证的)。而人工智能需要在每种情况下进行训练。没有捷径。提出这些边缘案例并围绕其设计自动驾驶系统的能力将获得鲁棒性和安全性分数,并可能在竞争中获得优势。

哪里需要改进

那么自动驾驶车祸应该阻止技术的发展吗?当然不是!这项技术在拯救许多生命方面有巨大的潜力。人工智能可能有偏见或不够复杂,但它有一个人类没有的优点。他们永远不会变得情绪化、鲁莽或困倦。如果做得好,在大多数情况下,它应该在安全性方面优于人类,但显然它还没有做到这一点。那么流程的哪些部分可以改进呢?(我本人并不是自动驾驶汽车专家,只是想在本文中探索各种可能性,所以对以下内容持保留态度。如果你有更好的想法,欢迎在下面留下回应!)

测试过程

同样,在深入研究技术之前,需要首先解决与人相关的问题。这起事故中特别令人惊讶的一点是,这辆车竟然有一名安全驾驶员。如果安全司机尽职尽责,不看手机,眼睛盯着路面,整件事本来是可以避免的。这并不难做到,但她未能做到这一点间接代价是一条生命。这与技术无关,但与如何改善自驾测试过程有关。让一名付费的安全司机开车,为测试增加一层安全,这是一个好的开始,但人类会犯错误。既然汽车已经有一个内部摄像头监控司机,为什么不开发一种算法来监控她/他的行为,并在她/他的眼睛离开道路时给出警告/分数?

五金器具

Photo from https://labs.sogeti.com

激光雷达/雷达在这起事故中未能触发。原因是什么?多加一个传感器会不会效果更好?添加更多类型的传感器?优化传感器的位置?传感器需要在任何天气条件下都能工作。炎热、高温、下雪、极度晒伤、刮风等。如果没有,要有后备计划。做好极端的准备。

软件

中央驾驶系统有一个优先控制系统,意味着传感器或图像识别系统上触发的一些特殊事件将导致汽车立即停止以避免严重事故,超越所有其他驾驶控制系统。(例如,硬代码确保前方净距离)优先系统需要仔细设计和调整,以实现最大的安全性。

算法

对于所有机器学习模型来说非常重要的一点是验证集。一个好的验证集定义了模型的泛化能力,从而在很大程度上决定了项目在现实生活中的成败。这也适用于自动驾驶汽车。这里什么是好的验证集?嗯,驾驶汽车不像我们的分类器问题那么简单,因此没有非常明确的定义。这正是问题所在。所有自动驾驶汽车公司和监管机构是否应该合作,开发一个良好的“测试例程”,捕捉所有极端情况、边缘情况、测试场景、自动测试软件等。,以有效地充当自动驾驶汽车的“验证集”?我认为,所有参与者在这方面达成一致并做出努力是至关重要的,但这一点还没有得到充分探讨。

最后的想法

Photo by Ciprian Morar on Unsplash

无论自动驾驶汽车取得了多大的进展,有时感觉就像只是触及表面,水下潜伏的冰山的大小仍然未知。此外,自动驾驶汽车事故通常会受到媒体的高度关注。据《连线》报道,去年仅在美国就有近 4 万人死于交通事故,但很少有人(如果有的话)像优步事件那样成为头条新闻。不公平?不真的。这其实是一件好事。严格和密切的审查是一件好事,可以推动自动驾驶汽车的安全极限。因为人命关天。

更新:调查的最终结果将于 2019 年 11 月 20 日公布。你可以参考这篇由 The Verge 撰写的文章。

觉得这篇文章有用?在 Medium 上关注我(李立伟)或者你可以在 Twitter @lymenlee 或者我的博客网站wayofnumbers.com上找到我。你也可以看看我下面最受欢迎的文章!

[## “这是 CS50”:开始数据科学教育的愉快方式

为什么 CS50 特别适合巩固你的软件工程基础

towardsdatascience.com](/this-is-cs50-a-pleasant-way-to-kick-off-your-data-science-education-d6075a6e761a) [## 一枚硬币的两面:杰瑞米·霍华德的 fast.ai vs 吴恩达的 deeplearning.ai

如何不通过同时参加 fast.ai 和 deeplearning.ai 课程来“过度适应”你的人工智能学习

towardsdatascience.com](/two-sides-of-the-same-coin-fast-ai-vs-deeplearning-ai-b67e9ec32133) [## 你需要了解网飞的“朱庇特黑仔”:冰穴📖

是时候让 Jupyter 笔记本有个有价值的竞争对手了

towardsdatascience.com](/what-you-need-to-know-about-netflixs-jupyter-killer-polynote-dbe7106145f5)

机器学习中特征选择的方差分析

原文:https://towardsdatascience.com/anova-for-feature-selection-in-machine-learning-d9305e228476?source=collection_archive---------2-----------------------

方差分析在特征选择中的应用

Photo by Fahrul Azmi

机器学习中最大的挑战是选择最佳特征来训练模型。我们只需要高度依赖于响应变量的特征。但是如果响应变量是连续的,而预测变量是分类的呢???

ANOVA(AnanalysisofVariance)帮助我们完成选择最佳特征的工作

在这篇文章中,我将带您了解

a.差异的影响

b.f 分布

c.方差分析

c.举例说明单因素方差分析

差异的影响

方差是一个变量中数字之间分布的度量。它衡量一个数字与平均值和变量中每个数字的距离。

特征的方差决定了它对响应变量的影响程度。如果方差较低,则意味着该特性对响应没有影响,反之亦然。

f 分布

通常用于方差分析的概率分布。它假设假设为

H0:两个方差相等

H1:两个方差不相等

自由度

自由度是指逻辑上独立的值的最大数量,这些值可以自由变化。简而言之,它可以定义为观测值的总数减去施加在观测值上的独立约束的数量。

Df = N -1 其中 N 是样本大小

f 值

它是两个卡方分布的比率除以它的自由度。

F value

让我们求解上面的方程,看看它对分析方差有什么用处。

F ratio

在现实世界中,我们总是处理样本,因此比较标准差几乎等于比较方差。

image from https://newonlinecourses.science.psu.edu

在上图中,我们可以观察到 F 分布的形状总是依赖于自由度。

方差分析

方差分析方差分析是一种统计方法,用于检验两个或两个以上显著不同的组的均值。它假设假设为

H0:所有群体的手段都是平等的。

H1:至少有一组是不同的。

均值比较如何转化为方差比较?

考虑下图中的两种分布及其行为。

Behavior of distributions

从上图中,我们可以说,如果分布重叠或接近,大平均值将类似于个体平均值,而如果分布较远,大平均值和个体平均值相差较大。

指各组之间的差异,因为各组中的值不同。所以在方差分析中,我们将比较组间差异和组内差异。

ANOVA 使用 F-tet 检查各组之间是否有任何显著差异。如果所有方差相等的组之间没有显著差异,ANOVA 的 F 比率结果将接近 1。

举例说明单因素方差分析

  1. 单向 ANOVA 检验分类预测值与连续反应之间的关系。
  2. 在这里,我们将检查连续反应的分类特征组之间是否有相等的方差。
  3. 如果组之间的方差相等,则意味着该特征对响应没有影响,并且可以不考虑用于模型训练。

让我们考虑一个包含学生表现数据的学校数据集。我们必须根据年龄、监护人、学习时间、失败、活动等特征来预测学生的最终成绩。

通过使用单因素方差分析,我们可以确定监护人对最终成绩是否有任何影响。下面是数据

Student final grades by the guardian

我们可以看到监护人(母亲、父亲、其他)为列,学生最终成绩为行。

执行单向方差分析的步骤

  1. 定义假设
  2. 计算平方和
  3. 确定自由度
  4. f 值
  5. 接受或拒绝零假设

定义假设

H0:“守护者”中的所有等级或团体都有相同的方差

H1:至少有一个群体是不同的。

计算平方和

平方和是用于确定数据点离差的统计技术。它是偏差的度量,可以写成

Sum of Squares

如 ANOVA 中所述,我们必须进行 f 检验,通过比较组间方差和组内方差来检查组间是否存在任何方差。这可以通过使用平方和来完成,定义如下。

总平方和

每个观察点 x 与大平均值 xbar 之间的距离是 x-xbar。如果您计算每个数据点之间的距离,请计算每个距离的平方,并将您得到的所有平方距离相加

Total Sum of Squares

之间的平方和

各组平均值 g 与 grand means xbar 之间的距离为 g-xbar。类似于我们得到的平方和

Between the Sum of Squares

平方和内

组 x 内的每个观察值与组均值 g 之间的距离为 x-g。类似于我们得到的平方和

Within the Sum of Squares

总平方和=间平方和+内平方和

确定自由度

我们已经讨论了自由度的定义,现在我们将计算组间和组内的自由度。

  1. 因为我们有 3 个组(母亲、父亲、其他),所以组之间的自由度可以给定为(3–1)= 2。
  2. 每组有 18 个样本,组内的自由度将是所有组的自由度之和,即(18–1)+(18–1)+(18–1)= 51。

f 值

因为我们比较的是组间方差和组内方差。F 值由下式给出

F value

计算平方和和 F 值这里是总结。

ANOVA table

接受或拒绝零假设

在 95%的置信度下,alpha = 0.05,df1 =2,df2 =51 从 F 表给定 F 值为 3.179,计算出的 F 值为 18.49。

F test

在上图中,我们看到计算出的 F 值落在超出我们置信水平的剔除区域内。所以我们拒绝零假设。

总之,由于零假设被拒绝,这意味着组之间存在差异,这表明监护人对学生的最终分数有影响。因此,我们将在模型训练中包含此功能。

使用单因素方差分析,我们可以只检查单个预测因子与反应,并确定关系,但如果你有两个预测因子呢?我们将使用双向方差分析,如果有两个以上的特征,我们将进行多因素方差分析。

使用双向或多因素方差分析,我们可以检查以下响应的关系

  1. 《卫报》会影响学生的最终成绩吗?
  2. 学生活动会影响学生的最终成绩吗?
  3. 《卫报》和学生活动一起会影响期末成绩吗?

得出以上结论做一个测试总是有趣的,对吗??我正在写一篇关于双向多因素方差分析的文章,会写得更有趣。

在这里,我们处理了连续响应和分类预测如果回答是分类的,预测器也是分类的,请查看我的文章 卡方检验机器学习中的特征选择

[## 机器学习中特征选择的卡方检验

我们总是想知道卡方检验在机器学习中的什么地方有用,以及这个检验有什么不同。功能…

towardsdatascience.com](/chi-square-test-for-feature-selection-in-machine-learning-206b1f0b8223)

希望你喜欢!!敬请期待!!!请对任何疑问或建议发表评论!!!!

ANOVA 估计平方和的三种类型:不要选错!

原文:https://towardsdatascience.com/anovas-three-types-of-estimating-sums-of-squares-don-t-make-the-wrong-choice-91107c77a27a?source=collection_archive---------0-----------------------

在本文中,我将解释计算方差分析平方和的三种不同方法,方差分析是一种使用统计显著性比较不同组平均值的常用统计方法。

这篇文章直接进入双向方差分析。如果你需要回到更基本的单因素方差分析,请查阅我以前的文章。

Ronald Fisher, the guy who invented ANOVA.

1.双向方差分析基础概述

双向方差分析的目的是将因变量的总变异(以平方和衡量)分成不同的变异源。这使我们能够发现我们的自变量是否对因变量有显著影响。

双向方差分析是有 2 个独立变量的方差分析。

存在三种不同的分裂变异方法:第一类、第二类和第三类平方和。在不平衡数据的情况下,它们不会给出相同的结果。

I 型、II 型和 III 型方差分析结果不同!

根据工作日和天气解释销售(笔记本在这里)

我将在一个实际的例子中应用这三种平方和来看它们的区别:

An example with data for two way ANOVA

2.第一类平方和

第一类平方和,也称为序列平方和,以序列顺序分配变量。

如果模型有两个自变量 A 和 B 以及交互作用效应,按顺序指定,I 类平方和将:

  • 首先给变量 A 分配一个最大变化量
  • 在剩余的变化中,将最大变化分配给变量 B
  • 在剩余的变化中,将最大变化分配给交互效果
  • 把剩下的分配给剩余平方和。

第一类平方和是连续的,因此模型中变量的顺序有所不同。这在实践中很少是我们想要的!

平方和在数学上定义为:

  • 自变量 A 的 SS(A)
  • 自变量 B 的 SS(B | A)
  • 相互作用效应的 SS(AB | B,A)

I 型方差分析结论为:

ANOVA table for the Type I Sums of Squares

在 I 型平方和中,weekday 被错误地选为最重要的变量,只是因为它在模型中首先被指定。

3.第二类平方和

第二类平方和在两个方面采取了不同的方法。

  • 首先,分配给自变量 A 的变化是对 B 的解释,而分配给 B 的变化是对 A 的解释。
  • 第二,第二类平方和没有交互作用的影响。

如果自变量之间没有交互作用,则应使用第二类平方和。

平方和在数学上定义为:

  • 自变量 A 的 SS(A | B)
  • 自变量 B 的 SS(B | A)
  • 无交互效应

第二类方差分析结果为:

ANOVA table for the Type II Sums of Squares

在第二类平方和中,天气是唯一重要的变量。这比 I 型平方和好得多。

4.第三类平方和

第三类平方和也称为部分平方和,这是计算平方和的另一种方法:

  • 与类型 II 一样,类型 III 的平方和不是连续的,因此说明的顺序并不重要。
  • 与第二类不同,第三类平方和确实规定了一种相互作用效应。

平方和在数学上定义为:

  • 独立变量 A 的 SS(A | B,AB)
  • 独立变量 B 的 SS(B | A,AB)

III 型方差分析结果为:

ANOVA table for Type III Sums of Squares

在第三类平方和中,天气和工作日都很重要。给定我们的示例数据,这似乎是一个可以接受的结果。

5.不同的软件—不同的结果

关于使用哪种平方和存在激烈的争论。

r 给出 I 型,Python 给出 II 型,SAS 给出 III 型。

I 型和 II 型在 R 软件社区更受欢迎。在 R 的 anova()aov() 函数中,平方和的实现类型是类型 I,即顺序计算。对于其他类型的平方和,使用 car 包中的 Anova() 函数,该函数带有一个类型参数。

SAS 软件社区中,类型 III 平方和被更多地使用,因为这通常是 SAS 的默认实现。

Python statsmodels 库中,默认实现是 Type II,但是 type 参数使得使用 Type I 或 Type II 变得非常容易。

Default Types of Sums of Squares for different programming languages

6.结论:不同的平方和——不同的问题

仔细观察,每种平方和都给出了划分共享变量的不同方法。在我们的例子中,我们根本不知道哪个答案是正确的,所以我们可以采取多种策略:

只有在理论上有充分理由时才使用 I 型,没有相互作用时使用 II 型,有相互作用时使用 III 型。

在类型 I 中,我们选择最“重要”的自变量,它将得到最大可能的变化量。

在类型 II 中,我们忽略了共享变量:没有假设交互作用。如果这是真的,第二类平方和在统计上更有力量。然而,如果在现实中有一个相互作用的影响,该模型将是错误的,将有一个问题的分析结论。

如果存在交互作用效应,并且我们正在寻找自变量之间的“相等”分割,则应使用类型 III。

Decision Tree for Different Types of Sums of Squares in ANOVA

所以这个综述的结论是:只有在有严肃的理论理由时才使用 I 型,没有相互作用时使用 II 型,有相互作用时使用 III 型。

回顾 ANOVA 理论真的很有趣,我希望这些内容能帮助你踏上数据科学之旅。 感谢阅读!

用蒙特卡洛回答蒙蒂·霍尔难题

原文:https://towardsdatascience.com/answering-monty-hall-problem-with-monte-carlo-6c6069e39bfe?source=collection_archive---------17-----------------------

Photo by Adam Rhodes on Unsplash. Adams’s Website

蒙特卡洛是一种概念简单但功能强大的技术,被广泛使用。它利用随机性来回答问题。

在这篇文章中,我将解释如何使用蒙特卡罗方法解决蒙蒂霍尔问题。这是用 python 实现的,Python 是一种编程语言,它的名字本身就是向英国喜剧团体——蒙蒂 Python 致敬。

蒙蒂·霍尔问题

我第一次接触到蒙蒂霍尔问题是在电影《21 世纪》。这个片段展示了这个问题。

Vsauce 的迈克尔大卫·史蒂文斯和 Vox 对此也有解释。

让我们跳入问题— 想象一下,你面前有三扇门。

游戏节目主持人让你选择其中一扇门。如果你选择了正确的门,你会赢得一辆车,否则你会得到一只山羊。

假设您选择了门№1

知道每扇门后是什么的游戏节目主持人打开 3 号门,露出一只山羊。

游戏节目主持人给你两个选择

  1. 贴着 1 号门
  2. 切换到 2 号门

你会选择哪一个?

蒙特卡罗实验

蒙特卡洛实验的定义根据维基百科 蒙特卡洛方法 ,或 蒙特卡洛实验 ,是一大类 计算 算法 即依靠重复 随机抽样 底层概念是用 随机性 来解决原则上可能是 确定性 的问题。

这意味着你可以模拟一个实验,基于某个或某些条件模拟任意次,然后分析模拟的结果以得出一个解决方案。

在电影《复仇者联盟 3:无限战争》中,奇异博士对未来进行了近 1400 万次模拟,以确定未来有多少结局,复仇者联盟会赢吗?本质上,他是在应用蒙特卡罗实验的原理。

用蒙特卡洛模拟蒙提霍尔

想象一下前面描述的游戏陷入了一个循环,就像电影土拨鼠日中的比利·穆雷一样。

每次游戏开始时,我们记录坚持第一个选择的门和切换到新的门的成功和失败。

假设这个游戏已经进行了 100 次。我们会检查在这 100 场比赛中,有多少场比赛的车是通过不开关车门和开关车门赢得的。

通过查看这些比率,我们将知道哪个选项增加了成功的机会。

编纂蒙蒂霍尔和蒙特卡洛

让我们定义一个模拟蒙蒂霍尔问题的函数

def monty_hall():
    ...

在该函数中,创建三个车门,并将汽车随机分配给其中一个车门。列表中的值“1”代表汽车

doors = [0, 1, 0]
shuffle(doors)

玩家选择打开一扇门。值 0、1 和 2 代表列表变量“门”的索引

door_selected = choice([0, 1, 2])

游戏节目主持人现在打开后面没有汽车的门

non_car_doors = list()
for i,d in enumerate(doors):
 if d == 0 and i != door_selected: non_car_doors.append(i)door_opened = choice(non_car_doors)

现在,评估以下两个选择

  1. 坚持最初的选择赢得一辆车
non_switch_success =  True if doors[door_selected] == 1 else False

2.通过切换到剩下的门赢得一辆车

remaining_door = set([0,1,2]).difference([door_selected, door_opened])
remaining_door = remaining_door.pop()
switch_success =  True if doors[remaining_door] == 1 else False

最后,返回每个选项的成功结果

return non_switch_success, switch_success

定义蒙特卡洛函数,该函数采用单个参数“n”来表示要运行的模拟数量。运行 Monte Hall 模拟“n”次,并返回每个选项的成功分布。

def monte_carlo(n):
    non_switch_success_count = 0
    switch_success_count = 0for i in range(n):
        ns, ss = monty_hall()
        non_switch_success_count += ns
        switch_success_count += ssprint(f"Number of plays: {n}")
    print(f"Number of success on switch: {switch_success_count}     
     {(switch_success_count/n)*100}%")
    print(f"Number of success on non-switch:                       {non_switch_success_count}  
     {(non_switch_success_count/n)*100}%")

完整的代码可以在下面找到,如何运行它在标题评论。

运行模拟

让我们模拟 100 个游戏

╰─$ ./main.py 100
Number of plays: 100
Number of success on switch: 71  71.0%
Number of success on non-switch: 29  28.999999999999996%

我们可以看到切换的成功率更高。

让我们再运行一次

╰─$ ./main.py 100
Number of plays: 100
Number of success on switch: 62  62.0%
Number of success on non-switch: 38  38.0%

我们仍然可以看到切换的成功率更高,但是成功率差别很大。

让我们对 100 万个游戏进行同样的模拟,然后做 3 次,看看成功率是否有很大的不同。

╰─$ ./main.py 1000000
Number of plays: 1000000
Number of success on switch: 666566  66.6566%
Number of success on non-switch: 333434  33.3434%╰─$ ./main.py 1000000
Number of plays: 1000000
Number of success on switch: 666588  66.6588%
Number of success on non-switch: 333412  33.3412%╰─$ ./main.py 1000000
Number of plays: 1000000
Number of success on switch: 666628  66.6628%
Number of success on non-switch: 333372  33.3372%

我们可以看到,成功的百分比变化不大,它告诉我们,如果我们进行转换,那么获胜的机会是三分之二。

进行切换!

结论

这篇文章的动机是介绍蒙特卡罗方法,并将其应用于一个对新手来说容易理解和有趣的问题。蒙特卡罗方法可能在概念上看起来很简单,但它是一种强大的方法,广泛用于金融行业、强化学习、物理科学、计算生物学等领域。

3 个最常见的数据科学问题的答案

原文:https://towardsdatascience.com/answers-to-the-3-most-common-data-science-questions-b2148568c85d?source=collection_archive---------22-----------------------

问我们任何事情

从“我该不该读研?”到“R vs. Python”

Photo by Bryan Minear on Unsplash

今年早些时候,我非常兴奋地作为一名编辑加入了《走向数据科学》。帮助社区成长是一件非常有趣的事情,在本文中,我将回答 3 个常见的数据科学问题,为“向我们提问”系列做出贡献。我希望你喜欢!

该不该读研?

这可能是我收到最多的问题,也可能是最难回答的。很难对这个问题给出一个通用的答案,因为答案确实需要针对您的具体情况。也就是说,我认为有些事情可以帮助你更容易做出决定。但是请记住这是我的一个观点,获得多个数据点通常是有帮助的(这个建议适用于我所有的回答)。

你不必在本科毕业后马上就去。大多数人似乎认为在他们的高年级有一颗滴答作响的定时炸弹,如果他们不立即去读研,那么机会肯定会与他们擦肩而过。以我的经验来看,肯定不是这样。如果你对读研没有把握,请考虑等待是否更有意义,获得几年经验,再做决定。

大多数数据科学家不是研究科学家。如果你正在考虑将博士学位作为获得高薪数据科学工作的捷径,那么我会重新考虑。一个博士项目需要至少4-5 年,而需要 6 年以上也不罕见。那是一段很长的时间。你所做的大部分深入研究不会直接应用到行业工作中。这并不意味着它没有价值,但绝对有一个不平凡的转变,除非你最终在一个工业实验室做研究。这就是为什么像 Insight Data Science 这样的公司存在,以帮助弥合这一差距。虽然你会比没有博士学位的人进入更高的层次,但以我的经验来看,这并不能解释大约 5 年的高工资损失。目前的货币甜点似乎是硕士学位。你花了 2 年时间获得硕士学位,然后又花了 2-3 年的时间积累经验,通常你现在是在一个新的博士学位开始的地方,但你在过去的 2-3 年里一直在赚钱。一些人认为博士学位有更高的上限,这可能是真的,但一般来说,真正做得好的数据科学家往往会这样做,因为他们可以弥合科学和公司价值之间的差距。我认为这种技能在不同的学术背景中分布相当均匀。注意:如果你的目标是成为一名研究科学家,博士学位显然更有意义。

你去哪所学校或加入哪所实验室可能比你学到的东西更重要。这是因为当前的招聘系统非常糟糕,而且可以在网上公开找到如此多的数据科学资源。我认为,你需要知道的通过数据科学面试的一切都可以在网上免费找到。甚至还有数不清的关于“最佳”资源的文章。那你问为什么要读研?因为虽然你可能知道你需要知道的一切,但你需要首先证明你的能力。公司筛选简历的一个重要方式是看你上的学校和你是否有高等学位。你刚从斯坦福毕业吗?你将比那些毕业于不知名大学的人更容易获得面试机会。此外,众所周知的项目也是建立关系网的绝佳机会。如果你就读于斯坦福这样的学校,你几乎肯定会认识许多顶尖科技公司以及成长中的“独角兽”公司的人。那个网络会让你进门。如果你正在考虑博士学位,同样的道理也适用于博士实验室。你要仔细考虑你加入哪个实验室,因为在某种程度上,你将你的价值与你的实验室和导师的声誉和价值联系在一起。

做你的研究。读研是你时间的一大投资。你的时间非常宝贵。花点时间在 LinkedIn 上联系那些参加过你正在考虑的项目的人。联系你认为你可能想与之共事的教授。打电话给学校办公室,问他们问题。你的目标应该是发现你对研究生院将如何帮助你的愿景是否与现实相符。例如,也许你正在考虑一个硕士项目,因为你认为它会帮助你过渡到像谷歌这样的公司工作。然后,你应该做你的研究,找出人们结束后的计划。如果几乎每个人都以咨询结束,那么这个项目可能不适合你。

预测未来很难。希望以上几点有助于你的决定,但最终,对于什么是“正确”的选择,总会有一个未知的因素。你能做的最好的事情就是尝试并确定你未来的目标,然后评估读研和其他途径相比如何帮助你实现目标。然后采取行动,不要害怕在学习的过程中重新评估和调整。

https://towardsdatascience.com/a-tutorial-on-fairness-in-machine-learning-3ff8ba1040cb

数据科学中最迫切的问题是什么?

我认为有太多太多了,无法计数,但这里有三个是我目前想得很多的。

公平与偏见。我们已经构建了一些令人惊叹的算法,但直到最近才开始考虑它们可能存在的偏见或不公平。这一领域的挑战之一是,机器学习的优势在于它从历史数据中学习并将这些模式应用于未来案例的能力。如果你的历史数据有偏差,你会怎么做?比如在娱乐圈,就有历史的性别偏见。在 2017 年的前 250 部电影中,88%没有女性导演,83%没有女性编剧,96%没有女性摄影师。因此,如果你要建立一个模型,利用历史数据来预测“好”董事,你的模型几乎肯定会有偏差。我认为你如何减轻这些偏见将有助于建立对社会产生更强更好影响的人工智能。

安全。我对自动驾驶汽车超级兴奋。我喜欢大规模深度学习的技术和应用。他们的现状也让我深感担忧。我们对这些车辆的安全性或性能几乎没有任何保证。对优步致命车祸的调查清楚地表明了这一点。

“虽然[自动驾驶系统]在撞击前近 6 秒感应到了行人,但该系统从未将她归类为行人——或正确预测她的目标是乱穿马路的行人或骑自行车的人——因为她正在穿越……在一个没有人行横道的位置,”报告称。"这个系统的设计没有考虑到乱穿马路的行人."

基本上,优步忘了考虑过马路的行人。我可以想象如此多类似的边缘案例,我不禁想知道我们如何量化甚至正式验证基于人工智能的系统的安全性。

小数据和计算。大数据和深度学习算法超级性感。事实证明,它们对 T2 环境非常不利,也不适用于许多重要问题。我对正在进行的使我们的算法更具计算和数据效率的研究感到兴奋。例如,谷歌的 MorphNet 有一个很好的推卸算法,允许你从一个大网络中提取一个更有效的网络。我认为这将使尖端算法更适用于没有大量计算预算的实体,以及适用于小数据问题,如预测罕见疾病。

我该学 Python 还是 R 还是别的?

实际上我对这个问题有很强烈的看法。不过,在我给出答案之前,我认为归根结底最重要的是学习数据科学。如果你有很强的知识基础,你用来实现它的编程语言并不重要。此外,编程语言来来去去,所以转换的能力肯定是有价值的。

也就是说,在今天的环境下,对于我主要研究的问题(在工业中应用人工智能),我认为你不从 Python 开始就是疯了。Python 是一种通用编程语言,具有强大的机器学习支持。r 是一种专门为统计计算和图形构建的语言,我认为这在今天的环境中限制了它。

Python 更容易发布到产品中,为您学习可能开发的不同编程语言做了更好的准备,具有更好的深度学习支持,并且更容易扩展。此外,开源机器学习社区对 Python 的支持是巨大的。几乎每个正在发布的流行包都是用 Python 编写的。我知道 R 也有一个很好的社区和支持,但它的优势更多地在于小众的统计需求(根据你工作的领域可能不那么小众)和探索性的数据分析。但是我认为对于大多数探索性的数据需求,Python 已经很好地满足了。

所以——对我来说,Python 是一个不用动脑筋的东西,但是我是一个样本大小为 1 的人。为什么不两个都试试?自己决定。

你也可以在这里找到这篇文章。

人脸识别解决方案的反欺骗技术

原文:https://towardsdatascience.com/anti-spoofing-techniques-for-face-recognition-solutions-4257c5b1dfc9?source=collection_archive---------7-----------------------

防止演示攻击的机器学习

Source

在我们日益数字化的世界中,网络犯罪呈上升趋势,这并不奇怪。许多公司现在正在探索由机器学习工程师提供的生物面部识别作为可行的安全解决方案。这项创新技术展现了巨大的前景,可能会彻底改变我们获取敏感信息的方式。

人脸识别技术将是决定人工智能未来前景的因素之一。

尽管面部识别很有前途,但它也有缺陷。用户照片可以很容易地通过社交网络找到,并用于欺骗面部识别软件。让我们说使用纸质照片,截图,或三维面部重建。

这就是为什么对公司来说,部署 face 反电子欺骗系统以保护敏感数据、减少盗窃和欺诈非常重要。这些系统通过提高检测欺诈的能力来增强现有的面部识别解决方案。

虽然这在理论上看起来很棒,但很明显弱点确实存在。是什么阻止了一个人用假脸获取敏感数据?

这就是反电子欺骗解决方案发挥作用的地方。我们依靠活体检测来验证个体的身份。这些检查可以验证个人是否实际存在或使用照片来欺骗系统。

最流行的人脸反欺骗技术

大多数面部欺骗攻击被称为表示攻击。这些攻击使用 2D 和 3D(静态或动态)来欺骗面部识别软件。

静态 2D 演示攻击依赖于照片、平面纸或面具,而动态版本使用屏幕视频回放或一系列照片。

静态 3D 呈现攻击可能使用 3D 打印、雕塑或面具,而动态版本使用复杂的机器人来再现表情,并完成化妆。

当然,这些例子并不是最终的真相。随着技术的发展,表示攻击也在发展。

如今,由于技术限制,2D 比 3D 更受欢迎。

在开发该问题的解决方案时,我们认为重点关注以下技术非常重要:

  • 防止静态和动态 2D 欺骗
  • 使用图像,而不是视频
  • 不需要用户的交互

一个可靠的解决方案需要达到最大的准确性,需要很少的时间,并优先考虑用户体验。

最重要的是,它需要与现有的面部识别软件集成。

眨眼检测

眨眼检测是一种非常准确的活体检测测试。自然眨眼是判断一张脸是否真实的简单方法。人类平均每分钟眨眼 15-30 次。在一次眨眼过程中,眼睛会保持大约 250 毫秒的闭着状态。现代相机记录视频的帧间隔要小得多(每秒 30 帧,50 毫秒)。

我们可以使用视频找到闭着眼睛的帧,并对它们进行计数,以获得预期的数量。眨眼检测的实现可以使用面部标志分析并计算眼睛的表面积。我们也可以将深度学习应用于这项任务。

深度学习特征:卷积神经网络

深度学习和卷积神经网络(CNN)是可以帮助反电子欺骗的附加解决方案。

在探索技术时,我们开始将反电子欺骗视为一个二元分类问题。我们可以训练 CNN 识别哪些是真实的照片,哪些是伪造的。会成功的。

但是有一个问题。

卷积网络没有“看到”和“理解”的一致(稳定)的功能集这整个模型依赖于希望系统能探测到我们肉眼看不到的东西。

这里有一个例子。

A trained CNN identifies both photos as spoofing

以上两张图都是恶搞。是的——我们训练有素的 CNN 能够识别出这两个都是欺骗。甚至在左边也有许多肉眼看不到的失真。但它只能在特定条件下处理特定数据集,包括相机质量、环境、光线等。

如果其中任何一个发生了变化,神经网络都不会提供准确的结果。因此,这种方法只在有限的用例中可行。

挑战-回应技术

挑战和响应是另一种可行的反欺骗技术。这种技术使用一种称为挑战的特殊动作。

该系统工作以验证挑战发生在视频序列期间。挑战应答系统依靠一系列挑战来验证个人的身份。

这些挑战可能包括:

  • 笑容
  • 悲伤或快乐的面部表情
  • 头部运动

然而,虽然有效,但这种方法需要额外的输入,并且会显著影响用户体验。

3D 相机

3D 摄像头是最可靠的反欺骗手段。精确的像素深度信息可以提供抵抗呈现攻击的高准确度,因为我们可以区分人脸和平面形状。

3D 攻击可能会造成困难,但摄像头仍然是可用的最可靠的人脸反欺骗技术之一。尽管有相机,但并不是所有用户的电脑上都有。

这就是为什么我们觉得处理常规 RGB 图像很重要。

活动闪光灯

主动闪存是一项有趣的技术,我们认为它很有前途。我们决定为我们的特定项目测试它。与其他一些解决方案不同,它没有“黑盒问题”

这种解决方案使我们能够利用人脸上的反光来检测电子欺骗。这个想法涉及到使用一个不断变化的光环境,这种光环境是由来自设备屏幕的额外光线提供的。白光在脸上产生适当的反射。

Active Flash anti-spoofing technique

我们可以用这种技术让真脸和假脸不同。

但是它是如何工作的呢?

我们在闪光发生前后取帧,并用这些数据训练我们的网络。主动闪光帮助我们分离面部特征并进行分类。

有可能建立一个独立于面角的模型(具有合理的限制)。但是,如果我们计算像素差异,人脸对齐就变得必要了。但是很明显这个方法是有效的。基于需要解决的特定用例,该技术可以变得更加复杂。

定义成功的衡量标准

我们提到的每一种反欺骗方法都有各自的可行性。但是像任何事情一样,它们有优点也有缺点。其中一些可以通过增加额外的复杂性来改进,另一些则适合单独使用,而某些解决方案在组合使用时会表现得更好。

但是你如何定义成功呢?我们认为度量标准对于衡量人脸反欺骗系统的准确性是必要的。

False Acceptance Rate (FAR) and False Rejection Rate (FRR) are common metrics

错误接受率(FAR)错误拒绝率(FRR) 是在生物特征验证中使用的常见度量,也适用于反电子欺骗。特定的任务定义了我们在解释错误时需要考虑的指标。

有几件事需要考虑。

如果最少遗漏的冒名顶替者是成功的衡量标准,我们应该消除 FAR。但是如果我们优先考虑用户体验,那么更重要的是关注 FRR。根据我们的经验,流畅的用户体验至关重要。

人脸反欺骗的下一步是什么?

依靠深度学习的反欺骗技术不仅仅是炒作。面部识别软件的成功将依赖于这些技术。但是,这种成功也需要反欺骗方法的组合和合理的成功度量标准。

无论如何,人工智能的未来令人兴奋,很明显,这项技术将改变我们进行身份验证的方式。

有兴趣知道如何运行具有 DS/ML 特性的软件开发项目吗?阅读我最近的文章数据科学咨询:从想法到部署。

蚂蚁和神经网络的问题

原文:https://towardsdatascience.com/ants-and-the-problems-with-neural-networks-778caa73f77b?source=collection_archive---------7-----------------------

认知科学可能如何改变神经科学

Photo by Mikhail Vasilyev on Unsplash

一个nt 是相当愚蠢的。它们能活一周,除了四处走动、寻找食物和为它们的蚁丘搬运小树枝之外,不做太多事情(现在我想起来,我们人类也不做太多其他事情)。

但是,除了过着平淡无奇的蚂蚁生活之外,他们也是愚蠢的。从技术角度来说,它们是愚蠢的:一只蚂蚁只有大约 250,000 (2,510⁵)个神经元。作为比较:一个普通的智人平均有 800 亿个神经元(810 ⁰),所以如果我们假设智力至少在某些方面与大脑的大小成比例(忽略一些动物的大脑比我们大的事实),那么我们大约是蚂蚁的 320,000 倍。

尽管蚂蚁的大脑很小,但它们也有自己的时刻。他们不断地做一些非常复杂的事情,以至于可以直接通过大学水平的数学考试。其中一个东西叫做 航位推算

航位推算

当像 双色斑翅蚁 这样的蚂蚁外出觅食时,它们会离开家,朝着预期食物来源的方向移动。由于他们不知道食物来源的确切位置,他们走在摇摆不定的路线和圆圈中(更多细节和图解见 Maroudas 和 Harkness 的论文)。如果你在野外观察过蚂蚁,你可能会认为这一切看起来完全是随机的。

但是一旦蚂蚁找到了食物来源并得到了它的那份食物,它就会直接回到它的家。而我说的直线,我指的是字面上沿着 的直线,不借助任何地标 来指引它们。

航位推算 是一种通过回忆自己从哪里来,从而知道自己在哪里的艺术。没有人真正知道为什么它被称为航位推算。你需要非常活跃才能做到。这不是一个简单的任务。

对于蚂蚁来说,要想知道它们在哪里,它们需要考虑它们在某个方向上行进的时间和速度。他们需要对长时间内路径上的所有微小位移进行汇总,并且他们需要能够随着时间的推移可靠且可访问地存储这些信息。

在数学中,你称这个过程为 路径积分 ,因为你在一段时间内对微小的位移进行积分,得到一个总和,然后你可以用它来计算有用的东西。

然后蚂蚁需要利用这些信息来计算出回家的最佳路线。为了做到这一点,蚂蚁必须 隐含地理解直角三角形的样子。 知道了它总共走过的路径的总位移(比方说,向北 10 米,向东 5 米),如果它想回到最优路径,它需要在直角三角形 的斜边上行进。

要沿着斜边行进,它需要找到合适的角度,这个角度就是北和东位移比例的反正切

我们并不知道蚂蚁是如何做到这一点的。

但是如果我们试图建造一个完成这项工作的设备,我们会假设我们需要以一种可靠的方式建造它,关于蚂蚁位置的信息以一种可靠的方式存储,并且在需要的时候也可以通过 计算访问 因为它需要它来计算蚂蚁在返回的路上将要采取的路线的角度,并且它需要能够独立于它去了哪里和它花了多少时间寻找食物来完成这项工作。

这一点在 A. King 和 C.R. Gallistel 的《改变思维的 记忆和计算大脑:为什么认知科学会改变神经科学 》中反复提到(我偷偷为我的标题修改了副标题)。

这篇文章是这本书的一些重要方面的 TL:DR 版本。这本书用了大得多的篇幅来阐述类似的观点。如果为了简洁起见,我不得不牺牲一些细节,我很抱歉,但我相信这些见解是高度相关的,并希望以一种不太耗时的格式来浓缩它们。

现在,记住 航位推算 是蚂蚁日常做的事情,也是过蚂蚁生活所需的许多其他任务之一。记住他们只有 25 万个神经元。

蚂蚁的大脑不是我们建造的,而是经过数百万年的进化而形成的。神经科学家面临的问题是,蚂蚁的大脑是如何连接的,以便以最佳方式进行这类计算。大自然已经一次又一次地证明了它在花费资源方面的吝啬,所以它很可能会认为它使用了一种为这项任务而优化的架构,尤其是考虑到蚂蚁大脑的大小。

作为一个物理过程,大脑必须遵守物理规则和计算的基本规则(由图灵等人制定),就像任何其他计算设备必须遵守的一样。尽管大脑确实“与普通计算机的工作方式非常不同”,进行“大量的并行处理”,并拥有“大量的神经元连接”,但大脑的这些特性不应该成为重新描述大脑本身某种神奇能力的借口。

所以我们可以继续提问:基于神经网络的神经元架构能在多大程度上完成这类任务?

神经网络的问题

“先说实话:机器不会学习”
—安德烈·布尔科夫在长达百页的机器学习书中

Photo by Franck V. on Unsplash

机器学习(ML)为我们提供了极其强大的分类学习算法。这是一种从数据中推断模式和结构的艺术,而无需给出如何推断这些模式的明确指示。

ML 方法让我们做了很多疯狂而有用的事情。如果目前围绕神经网络的大肆宣传是可信的,那么看起来它们可以学会做任何事情。我们需要注意,神经网络不会在未来几年失去控制,迎来由人工超级智能主导的人类反乌托邦未来。

但是根据安德烈·布尔科夫的说法,机器实际上“学习”的意义与我们或动物学习的意义相同,这有点牵强。对于通常的监督学习过程,我们只是进行大量的参数调整:我们试图找到由以下等式给出的决策边界(所谓的、、中的超平面,它们只是二维空间中的一条线)

wx -b=0,

为训练数据提供良好的分类结果。

当机器“学习”时,权重 w 被调整,以便在特征空间中找到决策边界,该边界为任何任意特征向量 x 给出最佳分类结果。

为了更加复杂,我们可以使用核方法来使特征空间中的度量在样本环境中非线性缩放,或者我们可以使用支持向量机来映射到具有其他维度的特征空间,我们可以调整神经元的激活函数等。

但这并没有改变机器学习算法的一个基本事实: 在神经网络中并没有进行实际的计算。

从这个意义上说,神经网络只不过是复杂的 查找表 (在计算机科学中,它被称为计算设备的有限状态架构,类似于图灵机,但没有读/写存储器):它们预先指定特定输入的特定输出。他们如何进行这种映射对用户是隐藏的(特别是当使用字面上称为 隐藏层 的东西时),并且关于网络如何分类的信息通常被编码在结构中并通过整个网络传播。

因此,它们的功能是 不具有代表性: 输入的任何表示都不会通过网络传送,并且可以通过网络中的每一步进行追踪。输入和输出就是一切。没有中间步骤, 网络不需要知道输入是什么意思就可以处理。

神经网络和联想学习

“所有的模型都是错的,但有些是有用的。”
—乔治·博克斯

虽然神经网络在某种程度上受到了大脑运作方式的启发,但神经科学家不一定认为神经网络足以代表大脑的工作方式。许多生物学的复杂性都被丢弃了,神经元通常以一种极其简化的方式来表示(树突的作用或突触处的钙流,以及许多其他东西,在模型中都被忽略或大大简化了)。

然而,神经网络目前的成功与心理学中可能最突出的学习理论不谋而合:即 联想学习 。信息是通过加强或削弱大脑不同神经元之间的连接来处理和整合的,遵循的规则是著名的流行语:“ 【什么东西把电线连在一起】 ”。

突触连接 是大脑在学习过程中调整的参数,因此它们的功能类似于人工神经网络中的权重。

就我自己而言,这让我相信神经网络真的可以在原则上解决他们面临的几乎所有任务,因此,大脑具有与人工神经网络非常相似的架构和学习机制。

但这种观点存在一些内在问题。

一个问题是,人工神经网络中最流行的学习方法(如【梯度下降】 )作为生物系统实际使用的方法是不现实的,因为它们需要用权重值进行计算,这又意味着网络外部的无所不知,可以访问权重值并相应地改变它们。**

但是突触权重是生物系统无法通过计算获得的。它们在人工神经网络中,但只是因为这些变量的值也存储在计算机的其他地方,而计算机本身不是神经网络。这反过来意味着神经元的功能结构对大脑本身来说是不透明的,它不能用来以一种允许大脑在需要时使用它的形式存储信息。

关于大脑是否使用符号表示它正在处理的事物,在神经科学界有一个持续的争议,就像基于图灵机概念的计算设备一样(我在这里详细介绍了图灵机的基础知识,,并解释了记忆和符号的功能)。

也就是说,这意味着一个读/写头可以访问它正在计算的符号,以及一种对计算进行编码的符号语言。正如我前面所描述的,神经网络是 而不是代表 ,它们不处理输入的符号表示。

这一点把我们带回到蚂蚁身上,以及它们是如何在觅食后返回它们的山丘的。

又是蚂蚁

Photo by Thomas Kinto on Unsplash

正如我们所看到的,对于一只成功导航回蚁丘的蚂蚁来说,它看起来很像是有一些方法来将其当前位置存储在变量 中,并使用该当前位置变量来计算返回的最佳路线。

King's 和 Gallistel 指出,对于由神经网络解决的航位推算任务,网络的计算和物理需求将**

这是因为网络不擅长记忆,即动态存储信息。在为学习程序优化后,它在运行时基本保持不变。这就是布尔科夫所说的网络不会学习的意思,因为它们只在学习任务时发挥灵活性,而不是在执行任务时。

作为记忆的循环反馈回路

鉴于这个问题,已经进行了一些尝试来在网络中建立能够动态存储信息的体系结构。它们基于所谓的 循环反馈回路,可以作为网络的记忆。

在这里,记忆这个术语再次在图灵的广义上使用: 作为一种可靠地携带计算所需信息的手段

循环反馈回路是神经网络中自我维持活动的突起。这种持续的活动可以起到符号的作用,因为活动 的信号需要时间来传播 ,因此将它编码的符号 在时间 上向前传送。由于权重在神经网络中是不可计算的,所以符号必须被动态编码,因此存储器将动态操作。

这种方法在早期的模拟计算机中使用,但当新的发展提供了更好的存储信息的方法时,这种方法很快就被放弃了。

在神经网络中实现该技术的一种方法是使用 连接到权重为 1 的自身的循环神经元,因此它们通过一次又一次地激活自身来存储信息。

例如,在航位推算模型中,神经网络中活动高峰的位置可以对蚂蚁的位置进行编码。网络中相应位置的神经元会继续自我激活,直到蚂蚁继续前进。

问题

当一个人试图在实践中实现这个想法时,事情变得复杂了(详见 Samsonovitch 和 McNaughton 的论文)。

这里不涉及太多的细节,作为记忆的循环反馈回路有几个固有的问题,特别是当它涉及到长期记忆时:

  1. 大脑在花费资源方面极其吝啬。任何一个头脑正常的计算机工程师都不会想到建造一个通过自持电流来存储信息的硬盘。摩擦和连续加热会导致 能量消耗 ,这是不必要的,也是不合理的。想象一下,为了不丢失其中的所有信息,你必须插上硬盘/u 盘并不断冷却它。
  2. 自然是凌乱的 。动力系统容易受到扰动,由于大多数动力系统的非线性,小扰动往往会随着时间的推移而放大(并非所有东西都是谐振子,因为本科物理学家往往会在花两年时间研究它后发现很多令人懊恼的事情)。如果您通过值为 1.01 的砝码发送值为 1 的信号,而不是通过值为 0.99 的砝码发送值为 1 的信号,那么在运行 50 次后,信号强度将为 1.64,而不是 0.61。当人们想到真实神经元的物理现实,及其所有的子结构、对神经递质的依赖性、钙流等时,对这种小扰动的定位一点也不牵强。假设它会将特定信号长时间保持在恒定的循环中,这可能是一种不切实际的简化。更有可能的假设是,自然界选择储存信息的实际机制以不同的方式工作,以一种更好地装备来校正扰动和错误。

加里斯特尔国王 写着:

从一开始,计算机科学家就意识到强大的计算机的关键特征是速度、效率和可靠性。

当在大脑中设计基于反馈回路的记忆机制时,这些问题都没有得到令人满意的解决。自然计算设备的效率使得大脑似乎不可能真的那样运作。记住蚂蚁只有大约 25 万个神经元。上面链接的由 Samsonovitch 和 McNaughton 建立的简化模型已经需要大约 50 000 个神经元来完成航位推算的工作,如果考虑到蚂蚁还必须做的所有其他复杂事情,这个数字就太高了。大自然不喜欢耗费资源,蚂蚁肯定没多少资源可以备用。

寻找记忆机制

这个故事的寓意是,对于许多认知任务来说,执行该任务的计算硬件需要某种类似于可访问的符号记忆机制的东西。当观察蚂蚁外出觅食后导航的效率时,这一点变得很明显。

总结一下我们遇到的两个问题:

*****突触强度*神经网络可能不会真正完成这项工作,因为它们执行计算的方式都是低效的(本质上是通过构建复杂的有限状态自动机,但它们的计算能力有限),而且存储在它们中的信息是分散的,对大脑本身来说是不透明的。因此,当谈到理解大脑如何计算时,通过调整突触强度实现的联想学习很可能不是全部答案。

网络中的循环反馈回路 同样似乎不适合作为良好的符号记忆,因为它们能量成本低且容易产生噪声,因此作为长期存储信息的手段并不可靠。

Gallistel 和 King 提出,它们太浪费了,不能成为大自然在构建大脑时实际采用的路线,大脑中需要有另一种我们尚未发现的记忆机制。

这绝不是说神经元不处理信息,或者信息在某种程度上与它们的活动、位置和连通性无关。这方面的一个例子是海马内位置细胞的作用,由 奥基夫陀思妥耶夫斯基 于 1971 年发现(他们因此获得了 2014 年诺贝尔医学奖)。它们的放电与动物(如老鼠)的空间位置有关,它们被认为是地点的认知地图(见这部动画中的插图)。

虽然它们可以为动物如何导航的问题提供更好的答案,但是它们作为路径整合者的功能还没有确定。而且它们也没有解决潜在的读/写符号记忆的问题,这在任何情况下也是许多其他任务 所必需的 ,我无法在这里介绍(比如间隔计时、学习一天中的时间、或者松鸦获取它们藏起来的食物)。

为什么认知科学会改变神经科学

这就把我们带回了这篇文章的副标题。

认知科学研究具有认知能力的设备,更具体地说,大脑,必须如何运行。计算约束表明,大脑作为计算设备的设置必须遵守某些基本原则,这些原则可以告知我们思考大脑神经科学基础的方式。

GallistelKing 提出相关的记忆机制可以驻留在大脑的不同层,例如分子或亚分子层。从物理学的角度来看,神经元绝对是巨大的,人类大约有 20 个微米 ,相比之下,平均原子大小为 30 pm 。正如费曼所说, 底部通常有很大的空间 ,在这六个数量级中(类似于你的体型与纽约和洛杉矶的距离之差),有很大的潜在空间来建立新的机制。

正如我们在 SSD 驱动器、蓝光甚至 DNA 的例子中所看到的,存储信息并不自动预设大量空间和大量资源,并且可以通过更节俭的方式来完成。

然而,国王 并没有提出任何具体的想法:

总之,我们不知道记忆的物理机制是什么。此外,我们拒绝猜测,除了举例说明,它可能是什么。我们拒绝,因为我们相信,面对我们目前的无知水平,我们不可能推测出正确的答案。

我认为这非常令人兴奋,因为这表明我们刚刚开始了解大脑的工作。如果我们甚至不知道它是如何存储和处理信息的,我们就无法理解它是如何计算的。神经网络很酷,也是一项伟大的发明,但看起来它们不会为我们提供所有的答案。

还有其他人力资源专业人士吗?这就是非专业开发者社区的样子。

原文:https://towardsdatascience.com/any-other-hr-out-there-this-is-how-the-non-professional-developer-community-looks-like-4c7101bd8dcf?source=collection_archive---------37-----------------------

一种基于数据的方法,使用 2019 Stack Overflow 的开发者调查数据。

介绍

我刚刚开始我的数据科学之旅,我可以告诉你:我不是天生的,作为一个成年人更难学习。

我的动机是相信通过“做”,我将能够理解这个新的数字企业世界,并有望与我的同行们——主要是人力资源专业人士——一起帮助翻译这个世界。

最近,我听到了很多关于未来最有价值的能力将是最基本的人类能力的说法。人工智能和自动化将出现在我们的工作场所,完成我们认为只有人类智能才能完成的任务。

这听起来像是一个为未来工作优先考虑人文科学和情商的论点。然而,我认为在我们到达那里之前,我们仍然有许多其他的积木要塑造。如果我们不认为功能知识和技术技能会被简单地推进机器,让机器神奇地自动运转,那将是明智的。

我的观点是:所有职业(办公室职员、工厂经营者、销售人员、教师、首席执行官……)都需要某种程度的数字素养,以了解我们如何才能以一种我们作为一个社会不会经历我们所担心的令人生畏的破坏性变化的方式来构建这个新的现实。

当我们用数据来检验想法和讲述故事时,我们的能力会更有效。对于一些专业人士来说,未来的数字素养可能会以学习一些编程技能的形式出现,以处理和理解复杂而混乱的数据集。

在这篇文章中,我想利用 2019 年 Stack Overflow 年度开发者调查来探索这一人群的一个片段。对于不熟悉的人来说, Stack Overflow 是开发者学习和分享编程知识的最大在线社区。

非专业开发人员的简介工作满意度薪酬是什么?让我们来看看…

第一部分:今天,非专业开发人员的开发人员是什么样的?

我用的是最近一次调查(2019 年),有 88,883 名受访者。只有 12.32%的人口:

  • 不是专业开发人员,但有时会将编写代码作为工作的一部分(8.53%)或
  • 编码主要作为爱好(3.78%)。

我将把选择这些答案中任何一个的所有回答者称为“非专业开发人员”。

Table 1: Type of respondent (excluding null answers) from 2019 survey.

与 2017 年的调查数据(11.78%)相比,我们可以观察到这一人口参与率略有增加。

这些回答者都不是专业开发人员,但是他们有多少编码经验呢?

Figure 1: Age of first code and current age (left) and years the respondents have been coding (right) of non-professional developers population (2019 survey results).

30 岁是受访者的年龄中位数。第一次编码经历的平均年龄是 15 岁。但回答者编码 8 年(中位数),所以有差距。

他们的就业状况如何?

Figure 2: Employment status of non-professional developers (2019 survey results).

大部分受访者(64.22%)是全职就业,其次是“独立承包人、自由职业者或个体户”,占 11.45%。

他们的最高学历和研究领域是什么?

Table 2: Educational level of non-professional developers, excluding null responses (2019 survey results).

64.18%的人口至少拥有学士学位。

最常见的学习领域是计算机科学/工程(35.40%),其次是另一个工程学科(15.99%)。

Table 3: Field of study of non-professional developers, excluding null responses (2019 survey results).

这部分人口主要是男性(86%)。妇女占总人口的 8%,其他类别占 6%。

第二部分:该人群和所有受访者的工作满意度相比如何?

以下是我们将要研究的问题:

  • 总的来说,到目前为止,你对自己的职业有多满意?
  • 你对目前的工作有多满意?
  • 你对你的经理知道他们在做什么有多少信心?
  • 以下哪一项最能描述您目前的求职状态?

为了给这些定性的答案打分,我对“工作满意度”做了如下分类,并添加了结果:

Table 4: Job satisfaction score based on answers available at the 2019 survey.

总体人口和非专业开发人员的平均得分相同(3.00),但是非专业开发人员的平均得分较低(2.50 比 2.85)。

Figure 3: Job satisfaction, all respondents (left) and non-professional developers (right).

第三部分:这个群体的薪酬与专业开发商相比如何?

为了进行薪酬分析,我选择了薪酬信息回复频率最高的前十个国家:

Table 5: Countries with the highest frequency of compensation information at the 2019 survey.

在准备可视化的工资信息时,我们需要考虑一些细节,更多细节请查看我的代码这里。

让我们比较一下专业开发人员和非专业开发人员的报酬。为了更好的可视化,补偿被标准化为国家最低工资的倍数,并进行对数转换。

Figure 4: Compensation distribution comparing professional developers and non-professional developers.

该数据库包含大量异常值,由最大值上方和最小值下方的点表示(可能是虚拟条目)。对比各国,我们可以发现薪资分配存在一些差异:

  • 在印度和巴西等国家,分布(由彩色方框表示)更大,表明受访者之间的工资差异更大;
  • 另一方面,我们有法国、德国、荷兰、加拿大和澳大利亚,分布较窄——这表明总体上工资差距较小;
  • 与其他国家相比,印度的最低工资高出许多倍。

看起来比较两组(专业开发人员和非专业开发人员)的分布是相似的。我们来看看中位数的绝对信息。

Figure 5: Median compensation (multiple of minimum wage), professional developer and non-professional developer.

  • 巴西、荷兰和法国的非专业开发人员和专业开发人员人口的中位数相似;
  • 与专业开发人员相比,印度和澳大利亚的非专业开发人员受访者的中位数更高。

总结和结论

这个小型的非专业开发人员社区似乎是由大多数在正规教育中接触过编码的人组成的。此外,他们将编码作为工作的一部分。

至于工作和职业满意度,将这一人群与所有受访者相比,我们没有发现任何明显的差异。

非专业开发者和专业开发者的薪酬分配也是如此。我们可以观察到国家之间的一些不同的行为,但是,总的来说,专业和非专业开发人员之间没有明显的差异。

这些只是观察发现。我很想知道这些年来这个种群会如何演变。

你会加入数字化转型吗?

要了解更多关于这个分析的信息,请查看链接到我的 Github。

AnzoGraph:一个基于 W3C 标准的图形数据库

原文:https://towardsdatascience.com/anzograph-a-w3c-standards-based-graph-database-9836fa64087e?source=collection_archive---------19-----------------------

剑桥语义学的巴里·赞访谈

Image by Kyle McDonald on Flickr CC BY 2.0

介绍

在这次采访中,我正赶上剑桥语义学的副总裁巴里·赞。巴里是 AnzoGraph 的创造者,这是一个本地的大规模并行处理(MPP)分布式图形数据库。Barry 在数据库领域经历了一段漫长的旅程。他在 2000 年至 2005 年期间担任 Netezza Corporation 的技术副总裁,负责指导软件架构和实施的所有方面,从最初的原型到批量出货,再到领先的电信、零售和互联网客户。Netezza 最终被出售给了 IBM,但在此之前,Barry 已经将注意力转向了其他地方,成立了另一家公司 ParAccel,该公司最终成为了 AWS Redshift 的核心技术。市场上开始出现对基于图形的在线分析处理(图形 OLAP)数据库的需求,基于这一市场需求,Barry 于 2013 年创立了 SPARQL City。

Barry 友好地同意本周与我交谈,此前最近宣布AnzoGraph 数据库现已可供下载,用于独立评估和在客户应用程序中使用,无论是在内部还是在云上。虽然还没有宣布,Barry 还透露 AnzoGraph 已经得到了增强,可以使用 RDF/SPARQL来提供完整的属性图功能。所以和他交谈并了解更多关于图形分析和 W3C 标准是如何结合在一起的是令人兴奋的。

首先,巴里,你能告诉我们一些关于剑桥语义学的事情吗?

剑桥语义学大约从 2007 年开始出现。我们多年来构建的解决方案之一是名为 Anzo 的语义层产品。Anzo 用于许多大型企业,如制药、金融服务、零售、石油和天然气、医疗保健公司和政府部门。这些企业都有一个共同的趋势,即拥有多样化的数据源,并且真正需要发现和分析数据。Anzo 提供的语义层将原始数据与业务含义和上下文结合起来并呈现出来。恰好图形数据库是这个解决方案的关键基础设施元素。

Cambridge Semantics 很早就看到了图形分析的价值,并且是 SPARQL City 的首批客户之一。他们在 2016 年收购了我们。2018 年末,我们将图形引擎置于 Anzo 之下,并将其分拆为自己的产品,名为 AnzoGraph。

请解释一下 AnzoGraph 的主要使用案例好吗?

在 OLTP 数据库方面,图形数据库市场得到了很好的覆盖。我们决定构建一个 OLAP 风格的图形数据库,而不是像 Neo4J 和最近的 AWS Neptune 那样的 OLTP 图形数据库。市场上确实需要执行数据仓库风格的分析,并获得处理结构化和非结构化数据的额外好处。借助 AnzoGraph,我们可以提供报告、BI 分析和聚合、图形算法(如页面排名和最短路径)、推理以及更多市场上缺失的数据仓库式分析。

客户使用 AnzoGraph 发现大规模多样化数据的新见解,包括历史和最近的数据。它非常适合在非常大的数据集上运行算法和分析,以找到相关的实体、关系和见解。我们将用户使用基于 W3C 标准的 RDF 数据库获得的价值与他们使用属性图获得的价值结合起来。

我们对将 AnzoGraph 用于多种用途很感兴趣。想一想,在所有需要执行分析的时候,连接数据的信息与数据本身同样重要。例如,知识图在许多试图将不同数据源连接在一起的公司中很流行,我们在 Anzo 中的经验对此有所帮助。各公司都在努力理解买家的意图,并建立推荐引擎。图表可以帮助解决“喜欢产品 A 的人可能也会喜欢产品 B”的问题。在金融服务领域,银行正在使用图表来“跟踪资金”。图表提供了跟踪衍生品和其他资产转移的能力,因此可以帮助银行管理风险。甚至 IT 组织也在关注复杂的网络,并试图更好地了解 IP 流量如何在设备之间流动。

有几个新出现的用例让我感到非常兴奋。首先,当与自然语言处理引擎或解析器配对时,AnzoGraph 非常擅长处理链接的结构化/非结构化数据和基于图形的基础设施,用于人工智能和机器学习中基于图形的算法。其次,关注图表分析如何对基因组研究产生影响是很有趣的。科学家们没有采用带来遗传学中许多分析驱动创新的蛮力技术,而是通过图形分析开发新的分析技术,允许用户找到新的见解,而无需像在关系数据库中那样为这些见解显式编程。

AnzoGraph 有什么不同于其他数据库仓库解决方案的地方?

这可能是您没有预料到的,并且与传统 RDBMS 数据仓库世界中共享模式的不灵活性有关,在传统 RDBMS 数据仓库世界中,我们的任务是创建表和固定模式。为了得到答案,我们可能需要创建复杂的连接来查询表。然而,在图形数据库世界中,由于一切都用三元组表示,我们用一个动词和一个描述来描述一个人、一个地方或一件事,所以很容易添加更多的三元组来进一步描述它,而不需要改变模式。标准的本体帮助我们描述关系,这在我们想要共享数据时尤其有用。数据库模式通常不那么灵活,因为它们通常从一开始就是固定的和定制的。

图形数据库中的本体非常灵活,可以更好地与你的伙伴共享数据。

当然,对分析的支持也是一个巨大的差异。虽然 AnzoGraph 提供了传统数据仓库的所有分析功能,但它还提供了图形算法、推理和其他功能。这使得处理我上面提到的用例变得非常容易。图形数据库更适合某些类型的机器学习算法,并提供基于机器的推理,这在机器学习中非常有价值。

与传统的数据仓库不同,AnzoGraph 非常适合部署灵活性和可伸缩性。由于可伸缩性因素,市场对用 Docker 和 Kubernetes 这样的容器构建的应用程序做出了响应。当您可以随意旋转多个容器并将其旋转回来时,这是一个非常经济的可扩展解决方案。在基准测试中,我们实现了比其他数据库快 100 倍的性能,前途无量。当然,AnzoGraph 可以部署在裸机、虚拟机或任何云中,但容器最受关注。

2018 年,机器学习的一系列技术领域都有了巨大的发展,而深度学习正在等待时机。图形数据库有什么可以提供给那些想要加入人工智能淘金热的海量数据的人吗?

我们正在看到机器学习和人工智能的更广泛采用,图形数据库将发挥作用。我们都知道机器学习最大的挑战是数据准备。然而,通过直接导入原始数据,然后在图形数据库本身而不是复杂的 ETL 管道中进行管理,这种准备和管理得到了简化。数据模型的简单性使得管理比关系数据库中的管理更加简单和快速。当复杂的模式消失时,用户将能够更容易地挖掘非结构化数据,并且他们可以利用容器的可伸缩性。

图形数据库使用户能够自由地“旋转”他们的分析,提出新的、特别的问题,而不受关系技术的限制。图形数据库可以为机器学习和人工智能提供很多东西。

图形数据库已经存在了一段时间,但现在才开始成熟。你对这个领域未来两年的预测是什么,AnzoGraph 将如何领导下一代图形数据库?

我期待在未来几年里,人们对执行大数据分析的一般类别有更深入的了解,而不是运营查询。AnzoGraph 非常关注跨图形空间聚合的大数据分析。我们可以超越狭窄的查询“告诉我关于史蒂夫的事情”来涵盖更广泛的分析,例如“告诉我关于人类的事情”。

我认为来年将会看到下一代标准查询语言的定义。

W3C 标准是目前唯一的正式标准,但是 Cypher 显然是标签属性图的事实标准。有一个组织已经成立来创建下一代正式标准,看看它是如何形成的会很有趣。在剑桥语义学,我们非常支持这一过程,拥有一种强大的图形语言是一件好事。因此,我对图形空间未来几年的预测是,专有模型即将过时。

市场将决定确切的标准,我们将调整我们的解决方案以符合标准,因为我们坚定地致力于标准。我不认为这种演变是一种威胁,而是一个巨大的机会,因为它符合我们的心态,只会增加图形技术的吸收。

最后

我要感谢 Barry 和剑桥语义的团队给我机会去了解更多关于 AnzoGraph 的知识。我与该公司没有任何关系,我应该指出,我没有从他们那里得到这次面试的报酬。

如果你想了解关于 AnzoGraph 的更多细节,从 2018 年 10 月开始,Slideshare 上有一个很棒的技术演示,或者查看一下网站。请在下面的评论中留下任何问题!

Apache Airflow:自动收集日常电子邮件附件

原文:https://towardsdatascience.com/apache-airflow-automating-the-collection-of-daily-email-attachments-213bc7128d3a?source=collection_archive---------14-----------------------

Photo by Mathyas Kurmann on Unsplash

这篇文章演示了如何使用 Apache airflow 和 IMAP 邮件协议从任何通用电子邮件服务器自动收集日常电子邮件附件。

俗话说,数据科学家 80%的时间都花在收集、清理和组织数据上。在很大程度上,这是真的,特别是在一次性洞察生成项目的情况下,然而一旦我们将模型投入生产,我认为表盘会移动得更远。我们不仅需要确保数据的完整性,还需要确保数据是最新的,并与内部系统无缝集成。

当集成一个新的数据源时,有许多方法可以探索,仅举几个例子:

  • 有报告 API 吗?
  • 有数据库吗?
  • 客户端或平台能支持 SFTP、S3、谷歌驱动等吗?

当所有希望都破灭时,我们可以求助于自动电子邮件报告。计划的电子邮件报告是一种在报告平台和最终用户之间共享数据的广泛支持的方法,并且在设置成本方面也相对便宜。因此,与其每天登录我们的电子邮件,下载报告并将文件复制到更永久的存储解决方案,我们可以使用 Airflow 插件和 DAG 来为我们完成这些工作。

这篇文章假设你有一个现有的气流环境和气流概念的基本知识。

IMAP 插件

Airflow 的一个很大的特性是插件,插件是扩展 Airflow 现有特性集的一个简单方法。要将新插件与现有气流环境集成,只需将插件文件移动到$AIRFLOW_HOME/plugins文件夹中。

IMAP 插件将包含一个钩子和操作符,钩子处理外部连接并构成操作符的构件。操作员将执行我们的任务。插件文件夹结构如下:


├── README.md
├── init。py
├──钩子
│ ├── init。py
│ └── imap_hook.py
└──运算符
├── init。py
└──IMAP _ attachment _ operator . py

要创建一个插件,你需要派生 AirflowPlugin 类并引用你想插入到 Airflow 中的对象,我们在 init 中做了这些。py 文件:

注意钩子和操作符是如何相对于文件夹结构导入的。

IMAP 挂钩

在创建一个钩子之前,气流连接需要到位,或者至少经过深思熟虑。这告诉气流如何连接到外部环境。IMAP 挂钩需要 IMAP 服务器 url、电子邮件地址和密码。可以在 Airflow UI 的管理选项卡中创建连接。以下是 iCloud 的 IMAP 连接示例。

IMAP 挂钩继承自 BaseHook 模块,它是所有挂钩的基类,并使用 get_connection 方法来访问连接模型。

请注意 init 方法中的“get_connection”是如何使用连接 id 来返回一个气流连接对象的,根据 UI 中创建的 IMAP 连接,它的属性是 host、login 和 password。

imaplib 库用于处理 Authenticate 方法中的邮件连接。IMAP4_SSL 类实现 is IMAP 协议,并通过 SSL 连接到服务器。login(user,password)方法授予 IMAP 对象对指定电子邮件帐户的访问权限。

既然钩子已经连接上了,它需要能够搜索特定的电子邮件。find_mail 方法就是这样做的:

mailbox 参数指示要搜索的邮箱,search_criteria 是一个搜索术语的字典,它定义了我们要查找的电子邮件。所有可接受的搜索词都可以在这里找到。

该方法返回相对于所搜索邮箱的电子邮件 id。如果没有找到电子邮件,则返回的 mail_id 为 None,如果找到了多个电子邮件,则只返回最新的 mail_id。

最后,get_mail_attachment 方法将电子邮件附件保存到本地目录。

mail_id 参数应该是 find_mail 方法的输出,邮箱已经设置好了。附加参数是可选的,local_path 指示保存附件的位置,file_name 允许您选择是否重命名附件。

fetch 方法使用 mail_id 返回电子邮件部分,这些部分被解码并使用 message_from_string 命令转换为消息对象。遍历用于“遍历”消息树并产生每个部分;最后一部分总是包含使用 get payload 函数检索的附件。

IMAP 附件操作员

如前所述,气流挂钩是操作员的构建模块。下面的操作员使用 IMAP hook 命令和 Airflow 的执行上下文来下载任务执行日期前一天(总是昨天)收到的电子邮件的附件,并将其保存到本地目录。

所有气流操作符必须继承 BaseOperator 类,该类创建成为 DAG 中节点的对象。下面所有的参数都已经在 IMAP 钩子中提到了。唯一的新参数是 execute 方法中的上下文变量;这是一个描述任务执行环境的字典,即 execution_date & run_id。气流执行上下文的全部内容可以在这里找到。

Airflow 操作符的一个重要特性是能够定义模板字段;这些是 Jinjaified 字段,在执行时可以接受 Airflow 宏。文件名是一个 template_field,这意味着它可以在运行时使用宏动态设置。在 8 月 1 日运行 DAG 将产生以下结果:file_name = {{ ds }}_attachment = 2019-08-01_attachment

execute 命令使用上下文变量将搜索标准的 date received 元素预设为执行日期的前一天。这是通过使用“yesterday_ds”宏设置或更新“ON”值来实现的。这背后的想法是,如果每天都有电子邮件报告发送,我们只需要最新的附件。

我使用“yesterday_ds”宏,因为有时报告和数据会在一天的不同时间合并,所以我们只是给它额外的交付时间。我不要求我的数据比几天前更新,但如果速度是最重要的,气流传感器会更合适。

get_attachment 方法验证 IMAP 挂钩,并调用每个方法将附件下载到 disc。

S3 达格的电子邮件附件

既然插件现在已经完成了,下一步就是在气流 DAG 中将它投入使用。下面是一个简单的 DAG,每天运行,下载电子邮件附件并保存到 S3。

已经定义了 IMAP 附件操作符,下面的代码描述了将附件上传到 S3 和删除本地存储的附件所需的两个函数。

这些将使用 Python 操作符的扩展版本在 DAG 中执行。扩展的 Python 运算符继承了 Python 运算符,并将 op_kwargs 字段定义为模板字段,这意味着 upload_file_to_s3 和 remove_file 函数中的关键字参数现在都可以被 Jinjaified(接受 airflow 宏)。

下一步是定义 DAG。下面的 DAG 在八月份每天运行,在出现故障时重试 3 次,每次尝试之间有 5 分钟的延迟。

最后一步是将所有任务放在一起并定义依赖关系。file_name 变量是使用 yesterday_ds_macro 定义的(我们正在提取昨天的电子邮件附件)。由于 file_name 在所有操作符中都是一个模板化的字段,因此它将用于跨任务跟踪附件。

描述这个 DAG 的最佳方式是想象一下 8 月 1 日的一场挤兑。动态变量定义如下:

  • DAG 以一个伪操作符开始;虚拟操作符不做任何事情,但是对于分组任务非常有用。
  • DAG 启动后,下一步是下载电子邮件附件。这是使用 IMAP 附件操作符来完成的,该操作符使用新的文件名保存附件:email _ Attachment _ received _ on _ 2018 07 31。
  • 将附件上传至 s3 任务将文件 staging _ folder/email _ attachment _ received _ on _ 2018 07 31 上传至 S3 存储桶:email_attachment_bucket。
  • “删除本地附件”任务从暂存文件夹中删除文件:email _ attachment _ received _ on _ 2018 07 31。
  • 最后,DAG 以另一个伪操作符结束。

我希望你喜欢这篇文章;如果你有任何问题或建议,甚至是对未来帖子的想法,请在评论区告诉我,我会尽最大努力回复你。

Apache Drill 与 Apache Spark —哪个 SQL 查询引擎更适合您?

原文:https://towardsdatascience.com/apache-drill-vs-apache-spark-which-sql-query-engine-is-better-for-you-2a43f381bcd7?source=collection_archive---------15-----------------------

原文发布于此:https://blog . contact sunny . com/tech/Apache-drill-vs-Apache-spark-which-SQL-query-engine-is-better-for-you

如果您在大数据、数据科学或 BI 领域,您可能听说过 Apache Spark。你们中的一些人可能也听说过 Apache Drill,你们中的一小部分人可能实际上使用过它。我最近发现了 Apache Drill。但从那以后,我开始喜欢它所提供的东西。但是当我浏览 Apache Drill 的功能时,我想知道的第一件事是,它与 Apache Spark 有什么不同?我能互换使用这两个吗?我做了一些研究,找到了答案。在这里,我将回答这些问题,为我自己,也许也为你们。

理解这两者之间的根本区别、它们是如何实现的以及它们能够做什么是非常重要的。

使用 Apache Drill,我们编写 SQL 查询来从各种来源获取数据,例如 SQL 数据库、MongoDB、AWS S3、Apache Kafka、JSON 文件等等。但是使用 Apache Spark,我们编写“类似 SQL”的查询来从各种数据源获取数据。这里的区别在于,Drill 是一个 ANSI SQL:2003 查询引擎,具有比传统 SQL 查询引擎更强大的功能。另一方面,Apache Spark 只支持 SQL 查询的一个子集,而且是有限的。Spark 是一个通用的计算引擎,它支持类似 SQL 的查询来获取运行这些计算所需的数据。Spark 还为您希望运行查询的各种存储服务提供了驱动程序。

SparkSQL 支持的数据源列表也相当长,但没有 Drill 那么长。长期使用 BI 工具的人会发现自己对 SQL 查询驾轻就熟。将这些知识带到 Apache Drill 中,将使他们能够从对他们来说可能是新的数据源中查询数据,如 NoSQL 数据库、拼花文件、S3 文件等。这样的人可以使用 Apache Drill 运行复杂的聚合查询;而且大多数时候,他们得到了他们需要的结果。SparkSQL 就不一样了。

SparkSQL 非常适合在 Spark 内部处理数据,并且希望通过一些简单的连接和 where 条件从外部数据源获取数据。一旦将数据放入 Spark 数据集,就可以应用转换并执行操作。

这两个工具处理底层数据的方式非常不同。Apache Drill 能够接受在多个数据源上运行的复杂查询,并且能够将这些查询下推到相关数据源的本地驱动程序。它在内部将数据映射为 JSON 格式,并且它使用 JSON 的能力使得 Drill 在某种程度上比 Spark 更加灵活。

Drill 还使用 FLATTEN 和 KVGEN 等命令扩展了 ANSI SQL 查询,这使得处理简单甚至复杂的 JSON 数据变得更加容易。由于 Drill 在内部使用 JSON,它使 Drill 能够动态地发现模式。

总之,如果您想做大量的数学、数据转换和机器学习工作,最好坚持使用 Apache Spark。如果不是这样,而您只想运行一些聚合查询来分析数据,那么您可以使用 Apache Drill。

有意思的是,Drill 支持 JDBC 驱动,Spark 可以在 SparkSQL 内使用 JDBC 驱动来取数据。因此,如果您希望对导入 Spark 的数据进行精细控制,并希望对这些数据进行复杂的转换,您可以使用 Spark 中的 Drill 将数据导入 Spark。这种组合对于大多数应用来说应该足够了。

Apache Druid(第 1 部分):可伸缩的 Timeseries OLAP 数据库系统

原文:https://towardsdatascience.com/apache-druid-part-1-a-scalable-timeseries-olap-database-system-af8c18fc766d?source=collection_archive---------7-----------------------

在线分析处理(OLAP)系统通常用于许多商业智能、分析和数据科学应用中。根据维基百科,“OLAP 是一种在计算中快速回答多维分析查询的方法”。

与传统的关系数据库系统相比,主要区别在于 OLAP 系统中的数据是以预聚集和多维形式存储的。以这种形式存储数据的主要好处是,它针对特定的复杂聚合进行了优化。例如,通过使用不同的粒度级别(每小时、每天、每周等)存储预聚合。),我们可以高效地回答类似“两年前的月销售额是多少?”,或者“在过去的 90 天里,用户每天使用我们服务的特定功能的平均时间是多少?”。此外,我们可能需要随时深入到更详细的视图,并在数据的任何其他维度上重新计算聚合。例如,现在我们想重新计算上述问题,并对世界上每个国家的结果进行分组,以便生成更详细的可视化/报告/仪表板,并帮助制定决策。

从关系数据库中收集这样的答案并非不可能,但是模式设计和维护的复杂性,以及能够“有效地”回答这种复杂的特别聚合的需求,可能会导致数据工程的噩梦(多个表、索引、可能的多个数据库和定制 ETL 任务)。

简而言之,OLAP 系统的主要特征概述如下:

  • 保留数据的时间序列—例如,能够了解指标值的演变。
  • 分析师通常执行的查询是特定的,因此系统应该能够回答任何业务问题,而不需要模式工程。应该快速收集和查询任何维度的数据。
  • 与关系数据库相比,数据可能以大量冗余存储。这是期望的,或者是为了提高收集结果的速度(例如,避免连接),或者是因为需要具有时间序列中的数据演变。
  • 为了回答业务问题,可能需要扫描大量数据。

OLAP 系统背后的主要概念如下:

  1. OLAP 立方体:你可以把立方体看作是电子表格的多维概括。例如,考虑我们想要按国家、按某些时间段(例如,每周、每月、每季度和每年)以及按任何其他可能的维度(例如,按地区、城市、服务特征等)进行销售。).
  2. 对于任何查询来说,预先计算一个多维数据集中所有可能的聚合将是最快的答案响应时间的理想情况,但是这需要大量的处理时间和存储。根据业务需求、系统配置和聚合类型,我们通常设置哪些聚合将在数据接收期间完全预先计算,因此,任何其他聚合都是在查询计算期间按需计算的。

有许多商业和开源的 OLAP 系统,一个简单的比较可以在维基百科中找到。正如本文标题所揭示的,我们将重点关注 Apache Druid ,这是一个分布式数据存储,旨在对大型数据集进行高性能切片分析(OLAP 式)。

阿帕奇德鲁伊

Apache Druid 由广告分析公司 Metamarkets 创建,目前已经被许多公司使用,包括 Airbnb、网飞、尼尔森、易贝、Paypal 和雅虎。它结合了来自 OLAP 数据库、时间序列数据库和搜索系统的想法,为广泛的用例创建了一个统一的系统。最初,Apache Druid 在 2012 年成为 GPL 许可下的开源软件,此后在 2015 年改为 Apache 2 许可,并在 2018 年加入 Apache 软件基金会作为孵化项目。

Druid 提供了什么来处理类似 OLAP 的查询:

  • 为了存储效率和对数据维度的快速过滤,Druid 以面向列的压缩格式存储数据(参见面向列的系统和面向列的数据库系统)。因此,它可以处理数据冗余,同时使用有效的格式对多维聚合和分组执行查询。
  • 为了回答查询,它只加载所需的精确列。
  • 每一列都针对其特定的数据类型进行了优化存储。
  • 为了提供跨多列的快速过滤和搜索,Druid 使用了最先进的压缩位图索引(详情见简明和咆哮)。
  • 任何数据源的模式(例如,Druid 中的一个表)都非常灵活,可以很容易地发展。
  • 数据基于时间进行分区,因此时间序列查询比传统数据库快得多。
  • Druid 提供了开箱即用的算法,用于近似计数区分、近似排序以及近似直方图和分位数的计算。
  • 它具有高度的可伸缩性,已经在生产环境中使用,每秒钟处理数百万个事件,存储数年的数据。
  • 查询的亚秒级平均响应时间。
  • 容错架构。
  • 集成最先进的大数据技术,包括 Apache Kafka 、 Apache Flink 、 Apache Spark 和 Apache Hive 。
  • 提供了一种基于本地 JSON 的语言,以及基于 HTTP 或 JDBC 的 SQL(实验性的)。
  • 由高级商业智能和分析数据探索和可视化工具支持,如元数据库和 Apache 超集。

数据是如何存储的

Druid 中的表被命名为数据源,它们按照时间间隔进行划分。每个时间间隔被命名为组块,由片段组成。段是一种不可变的数据结构,它被周期性地持久化。例如,您可以设置每天或每小时创建一次分段,等等。如图 1 所示,一个段由以下三种列类型组成:

  • 时间戳:数据的时间戳(是否汇总)。
  • 维度:输入数据的字段,可用于过滤和分组。
  • 指标:预聚合(例如,第一、最后、总和、最大值等。).

图 1 ~分段核心数据结构

每个可以由一个或多个段文件组成。根据数据摄取的配置,当其记录的数量达到某个最大阈值(例如,五百万个记录)时,或者当存在多个并发摄取任务并且因此每个任务创建单独的段文件时,或者当任务中的段文件的文件大小超过某个阈值(例如,超过 512MB)时,可以创建段。有关细分市场的更多详细信息,您可以阅读官方文档。

此外,您可以指定段内数据的粒度。例如,假设您在用例中需要一个小时级别的粒度。您可以设置 druid 按小时自动聚合您的实时数据。为了说明 rollup 在 Druid 中是如何工作的,例如,考虑以下 JSON 中的输入数据片段:

{"timestamp":"2018-01-01T01:01:31Z","user_name":"Boxer","city":"San Fransisco","characters_added":1000} {"timestamp":"2018-01-01T01:02:16Z","user_name":"Boxer","city":"San Fransisco","characters_added":400} {"timestamp":"2018-01-01T01:03:21Z","user_name":"Boxer","city":"San Fransisco","characters_removed":25} {"timestamp":"2018-01-01T01:03:46Z","user_name":"Boxer","city":"San Fransisco","characters_added":400} {"timestamp":"2018-01-01T02:05:41Z","user_name":"Helz","city":"Calgary","characters_added":1800} {"timestamp":"2018-01-01T02:07:36Z","user_name":"Helz","city":"Calgary","characters_removed":17} {"timestamp":"2018-01-01T02:10:06Z","user_name":"Helz","city":"Calgary","characters_added":153}

每一行都是一个 json,代表一个输入事件。字段时间戳是使用 ISO-8601 标准表示的事件的时间戳,而 characters_addedcharacters_removed 是度量。为了简化起见,给定的数据片段在示例 JSON 中只包括两个维度,即用户名城市。通过将 rollup 设置为小时级别的粒度,上面的示例将被聚合到每小时的记录中,如图 1 所示。例如,在对应于区间2018–01–01t 01:00:00Z2018–01–01t 02:00:00Z的段中添加的 characters 的值就是其在该区间内的所有值的总和(即 1000 + 400 + 400 = 1800 )。有关汇总的更多细节,请参见官方教程。

架构的简要概述

Druid 有一个分布式和可伸缩的架构。Druid 的设计是由具有高可用性系统的需求驱动的,具有灵活的配置,同时是云友好的和易于操作的。下面的图 2 显示了该架构的示意图。

图 2 ~德鲁伊教建筑

首先,Druid 平台依赖于以下三个外部依赖:

  1. 深度存储:它可以是任何分布式文件系统或对象存储,如亚马逊 S3、Azure Blob 存储、阿帕奇 HDFS(或任何 HDFS 兼容系统),或网络挂载文件系统。深度存储的目的是持久存储 Druid 获取的所有数据,作为备份解决方案,同时在需要时可供所有 Druid 组件和集群使用。
  2. 元数据存储:由传统的关系数据库系统支持,如 PostgreSQL 或 MySQL。所有元数据对任何 Druid 组件都可用。Druid 中有各种类型的元数据,有些与深层存储中的持久段有关,例如段文件的路径、它们的时间戳、它们的版本等等。其他可能与外部系统相关,如来自 Apache Kafka 主题的摄取的分区偏移,其余与各种内部进程的元数据相关(例如,其中现在正在创建片段)。
  3. 动物园管理员:用于内部服务发现,协调,领袖选举。

Druid 的架构由以下处理类型的组件组成:

  • 中间管理器进程处理集群的数据接收。例如,他们负责从 Apache Kafka 接收实时流数据,或者从其他来源加载批量数据(例如,来自 HDFS 的文件)。
  • 历史进程处理“历史”数据的存储和查询。运行历史进程的节点从深层存储中提取数据段到本地磁盘,并响应关于这些数据段的查询。
  • 代理进程接收来自外部客户端的查询。它们识别哪些历史中间管理器节点正在服务这些段,并向这些进程中的每一个发送重写的子查询。此后,他们收集和合并结果,并回复呼叫者。在内部,历史进程响应对应于已经保存到深度存储的数据段的子查询,而中间管理器响应对应于最近摄取的数据(即,还没有发布到深度存储的内存中的数据)的子查询。
  • 为了平衡历史中层管理者流程上的数据,德鲁伊分别拥有协调者流程和霸主流程。协调器进程,具体来说,负责将段分配给运行历史进程的特定节点。类似地,霸王流程负责向中层经理分配摄取任务,并负责协调部门发布。
  • 最后路由器处理,在经纪人领主协调人面前提供统一的 API 网关。它们的使用是可选的,因为你也可以直接联系经纪人上司协调员

如前所述,Druid 由用于摄取、查询和协调的独立组件组成。每个 Druid 流程组件都可以独立地配置和伸缩,为您提供了最大的灵活性,以及对容错的健壮性(因为一个组件的中断不会立即影响其他组件)。此外,将深度存储和元数据存储与 Druid 系统的其余部分分离开来,可以从深度存储和元数据存储中保存的数据重新启动组件或整个集群。

数据摄取流程

数据接收流程分为两个部分。在第一部分中,中层管理人员正在运行索引任务,这些任务创建段并将其发布到深层存储。第二部分,通过历史进程从深层存储中获取发布的片段,以便在查询回答中使用。

索引:线段创建和发布

中层管理人员负责外部数据源的接收,例如在 HDFS 批量接收文件或从 Kafka 流式接收。图 3 中的图表突出显示了在数据摄取过程中参与的组件,而其余的组件是灰色的。在摄取期间,数据被索引、预聚合、分割成段(记录数量以及汇总间隔),然后发布到深层存储

图 3~索引:段创建和发布

来自数据源的数据摄取可对应于一个或多个摄取任务。对于日志和资源隔离,中间管理器进程创建摄取任务并将其转发给Peons——也就是每次处理单个摄取任务的独立 JVM 实例。

在索引任务开始时,会创建一个新的段。片段的输入数据可以来源于实时流(例如,卡夫卡主题)或一批文件(例如,HDFS 的 CSV 文件)。有两种摄入模式:

  • 附加模式:当输入数据源是一个流(例如,Kafka 主题)或者批量索引任务被设置为附加模式(即,读取文件并附加一个现有的 Druid 数据源)时,任务将新的段添加到相同时间间隔的现有段集合中。
  • 覆盖模式:旧段被停用,并被具有相同时间间隔的新版本号的新段替换。

Druid 的一个重要特性是,当前从实时任务中创建的片段是可立即查询的——例如,从 Kafka 消费的记录是可立即查询的,尽管它们尚未发布到深层存储

当任务已经索引了每个段的最大数量的记录(例如,五百万条记录)或者达到了期望的汇总时间间隔(例如,每小时聚集)时,任务完成。此时,通过将其数据保存到深层存储并将元数据保存到元数据存储来发布该段。

移交:为查询应答提取已发布的段

图 4 中的图表突出显示了在切换期间参与的组件,其余的组件是灰色的。

图 4 ~移交:为查询应答提取已发布的片段

协调器进程定期轮询元数据存储,以便从数据摄取任务中找到任何新发布的片段。一旦一个新创建的段被一个协调器进程发现,它选择哪个历史进程应该从深层存储器中获取该段。当该段成功加载后,历史流程准备好为其提供查询服务。

查询回答

客户端直接向代理发送查询(或者通过路由器间接发送)。可以使用基于本地 JSON 的语言或实验性 SQL 语言来表达查询。查询的类型可以是时间序列、 TopN 或 GroupBy 中的任何一种。所有类型的前述查询至少包含目标间隔时间,以及感兴趣的维度和/或度量。目标时间间隔是 Druid 用来决定需要处理哪些片段来回答查询的信息。图 5 中的图表突出显示了在查询应答期间参与的组件,其余的组件是灰色的。

图 5 ~查询回答

一旦客户请求查询,代理的初始任务之一就是识别哪些流程服务于所需的细分市场。例如,假设 a 我们有兴趣找到“从现在开始过去 48 小时内每小时平均时间最高的前 10 名用户”。该查询既需要已经被索引并发布到深层存储的数据,也需要当前从中层管理器进程获取数据的片段。此时,代理将相应的子查询发送到历史中间管理器节点,每个节点将计算请求的聚合和过滤,然后发回结果。最后,代理收集并合并所需的数据,然后将最终结果返回给客户机。

结论

OLAP 系统是非常强大的数据库,用于处理商业智能、分析和数据科学应用程序常用的复杂聚合的即席查询。其设计背后的特征和概念将它们与传统的关系数据库区分开来,并使它们成为这类应用程序的理想选择。本文简要介绍了类似 OLAP 的 timeseries 数据库 Apache Druid ,概述了它的架构以及它的组件为数据接收、索引和查询应答而交互的方式。正如已经说明的,该架构是云友好的、易于操作的、高度可扩展的和灵活配置的。已经了解了数据是如何组织的,查询是如何计算的,在下一篇文章中,我们将通过使用开源库 Scruid 的示例查询来关注 Druid 的实际使用。

原载于 2019 年 3 月 29 日anskarl . github . io

Apache Hive 挂钩和 Metastore 监听器:元数据的故事

原文:https://towardsdatascience.com/apache-hive-hooks-and-metastore-listeners-a-tale-of-your-metadata-903b751ee99f?source=collection_archive---------7-----------------------

元数据介绍,什么是 hive 挂钩和 metastore 侦听器,何时使用它们,以及使用它们的一些探索

Photo by Dennis Kummer on Unsplash

开始前的假设

本文的目标读者应该对 Hive 和 Hadoop 生态系统特性有基本的了解。本文着重于比较和展示编写一个 Hive 钩子和一个 Metastore 侦听器需要什么,使您能够自动化元数据管理。

本帖涵盖的主题将是:

  • 元数据管理的需求
  • 元数据
  • 元数据管理
  • 为什么是阿帕奇蜂房?
  • 配置单元挂钩和 Metastore 监听器
  • 蜂巢挂钩概要
  • Metastore 侦听器摘要
  • 开始使用 Hive 环境
  • 探索钩子
  • 探索听者

元数据管理的需求

据 Gartner " 称,到 2020 年,大多数数据和分析用例 将需要连接到分布式数据源 ,这将导致企业在元数据管理方面的投资翻倍。

读完这句话后,您可能想知道:元数据到底代表什么?为什么它需要管理?

我可以告诉你,这是几个月前我想到的第一个问题…

[计]元数据

我们可以将元数据分类为:

  • 技术元数据:关于资产的详细信息,比如它的名称、类型、创建者的名字、对象的大小,或者最后一次更新的时间。
  • 业务元数据:提供关于资产的附加业务上下文,例如,它是否包含 PII(个人身份信息)、它应该被删除的日期以及许多其他信息。
  • 运营元数据 : 通常是关于资产使用情况的信息,如查询日志、数据采样和数据分析。

您还可以考虑关于资产的物理和逻辑信息,让我通过查看 Hive 和 Hadoop 生态系统来澄清这一点…

您的数据可以物理地存储在 hdfs 位置,并且在 Hive 上有许多不同的逻辑表指向它。

Photo by Amy Chen on Unsplash

这是一个很大的过程,但它会变得更加清晰…

元数据管理

元数据管理解决方案有助于回答与您的数据资产相关的问题,例如:

  • 我的数据资产安全吗?
  • 我是否符合所有这些新的数据保护法规?如 CCPA 、 GDPR 、 HIPAA
  • 谁具有可见性,谁可以对这些资产进行更改?

管理的本质通常始于维基、电子表格和各种文档,但当我们开始进入大数据世界时,它们很容易失去同步,我们变得无法回答这些问题。

你还记得关于脸书用户数据隐私的 50 亿美元罚款吗?你不想被放在一个无法回答这些问题的地方。

我们需要开始自动化我们的元数据管理!

A Data Dashboard. Photo by Carlos Muza on Unsplash

为什么是阿帕奇蜂房?

正如 Gartner 所言:“大多数数据和分析用例都需要连接到分布式数据源”。虽然Hive 只是其中之一,但它是一个开源项目,仍然被许多组织使用。

通过深入研究配置单元挂钩和 Metastore 侦听器,我们将了解如何在这种环境中连接到数据源,并收集有关其元数据更改的信息。值得一提的是,对于更复杂的元数据场景,像 Apache Atlas 这样的健壮数据治理和元数据框架可以在这个过程中为您提供帮助。

因此,我们将在本文中展示的是非常简单的实现,可以帮助您入门。

配置单元挂钩和 Metastore 侦听器

为了节省您的时间,让我简单地说一下,从概念上讲,它们基本上是相同的。重点是如何将每一个注册到 Hive 中,以及为他们提供什么信息。

本质上,我们创建了一个扩展接口或抽象类的类,带有我们的自定义逻辑,它将被钩子或监听器事件调用。

根据事件的不同,我们将获得不同的工作对象,让我们看一些例子:

  • 蜂巢挂钩:

Hive Hooks: Properties and Classes

  • Metastore 侦听器:

Metastore Listeners: Properties and Classes

对于它们中的每一个,你都有一对属性

属性是触发事件的地方,而类是您必须扩展的,所以配置单元运行器知道如何调用它。

为了演示如何以及何时使用它们,我们将探索**hive.exec.post.hook****hive.metastore.event.listener**属性。

蜂巢挂钩概述

让我们来看看使用 Hive 钩子的优缺点:

优点

  • 在查询处理的各个步骤中,可以更加灵活地运行/注入一些代码。
  • 可用于更新您的资产元数据,如表的访问时间,例如UpdateInputAccessTimeHook

缺点

  • 关于您的资产的元数据可能很难理解,您可能必须解析它,因为您正在处理钩子对象。
  • 您可以更改挂钩对象并影响配置单元查询处理。

对于 hive hook 方法,我们将使用**hive.exec.post.hook** 属性,这个属性在查询执行之后和结果返回给用户之前运行,一旦我们看到它运行,它将变得更加清晰。

Metastore 侦听器摘要

让我们来看看使用 Metastore 侦听器的一些优点和缺点:

优点

  • 关于您的资产的元数据已经被解析,更容易处理。
  • 不能影响查询处理,它是只读的。

缺点

  • 灵活性较差,您只能访问属于您的事件的对象。

对于 metastore 监听器方法,我们将使用**hive.metastore.event.listener**属性

在该属性中,我们能够从**MetaStoreEventListener**抽象类的事件列表中进行选择。

Methods from the MetaStoreEventListener with their Parameters

为了使用它,我们覆盖我们想要的方法,当事件发生时,我们将接收参数对。为了展示这一点,我们将覆盖两个方法:**onCreateTable****onAlterTable**

是时候动手了,让我们探索这两种策略。

开始使用 Hive 环境

我们将使用通常推荐的生产配置单元环境,在该环境中,我们为配置单元服务器、metastore 和底层 RDBMS(代表配置单元存储元数据)提供了单独的进程。

Hive Environment showcasing Hook and Listener usage

需要指出的是,钩子和监听器连接到不同的进程,正如你在上面的图片中看到的。

如果你想建立一个如图所示的环境,有一个很好的 repo: docker-hive ,可以帮助你开始。

探索钩子

让我们来看看我们的定制钩子代码:

在 hook 上下文中,我们可以访问执行的查询、执行的操作以及查询执行的输入和输出。在这种情况下,我们只是过滤资产中的修改操作,并记录输入和输出值,这样我们就可以看到它们的结果。

出于测试目的,让我们在一个连接到我们的 Hive 服务器的直线终端中注册这个钩子。

现在让我们运行一些命令来查看它们的结果:

  • show tables

在我们的钩子中这是一个不受监控的操作,所以在这种情况下没有关于对象的日志,但是您能发现操作元数据吗?

我们正在记录执行的查询:)

  • CREATE TABLE post (code INT, text STRING);

让我们看看 JSON 日志对象:

Full JSON file here

你能在这个 JSON 对象中找到所有的技术元数据吗?!看看所有这些字段和布尔标志,并开始思考我们可以监控的一切!

如果您注意到 JSON 中没有关于列名(codetext)的信息,那么在CREATETABLE事件中,如果我们需要这些信息,我们将需要额外的工作。

  • ALTER TABLE post ADD COLUMNS (release_date string COMMENT ‘Release date for this post’);

让我们看看 JSON 日志对象:

Some fields were suppressed to keep it short

与 Create Table 语句相比,我们有两个output对象,一个代表数据库,另一个代表表。
现在,对于 Alter Table 语句,我们有一个input对象和一个output对象,两者都表示表。

这里有一个问题,output对象不包含新列release_date,它表示应用更改之前的目标对象。

让我们使用侦听器运行相同的操作进行比较。

你可以在这个 git repo 上找到完整的实现。关于注册钩子需要改变什么文件的更多细节,请查看README.md文件。

探索听者

让我们看一下我们的定制监听器代码:

这里我们订阅了两个事件:**onCreateTable****onAlterTable**。如您所见,我们访问的对象与它们的事件相关联,对于**onCreateTable** 我们获得事件表元数据,对于**onAlterTable** 我们获得新旧表元数据。

当使用监听器时,我们不能像使用自定义钩子那样注册它,因为它运行在 Metastore 进程上。如果你想看到你需要修改的配置文件,请查看本主题底部的README.md

现在让我们运行一些命令来查看它们的结果:

在运行命令之前,我清除了配置单元环境,以便我们能够使用相同的表名。

  • CREATE TABLE post (code INT, text STRING);

让我们看看 JSON 日志对象:

Full JSON file here

  • ALTER TABLE post ADD COLUMNS (release_date string COMMENT ‘Release date for this post’);

Some fields were suppressed to keep it short

这里我们可以看到新的表元数据包含了添加的列release_date,因此使用已经解析的对象有其优势。

你可以在这个 git repo 上找到完整的实现。有关注册监听器需要更改哪些文件的更多详细信息,请查看README.md 文件。

结束语

在本文中,我们介绍了如何在 Hive 环境中连接来自资产的元数据,使您能够自动化元数据管理。我们演示了一个简单的实现,只是记录了操作性的元数据,但是正如我们在本文开头看到的,我们可能会处理许多分布式数据源。下一步是扩展代码,将元数据事件发布到消息系统,如 Kafka、Pub/Sub 或 SQS,并更新您的元数据管理工具。这样做将使我们能够将业务元数据添加到我们的资产中,所以敬请关注!

希望你觉得有用!如果你喜欢这篇文章并想看更多,一定要关注我的简介。

参考

  • 蜂巢钩:【http://dharmeshkakadia.github.io/hive-hook/
  • 码头工人蜂巢环境:https://github.com/big-data-europe/docker-hive
  • 蜂巢挂钩的 Git repo:https://github.com/mesmacosta/hive-custom-hook
  • metastore 侦听器的 Git repo:https://github . com/mes macosta/hive-custom-metastore-listener

Apache Hive 优化技术— 1

原文:https://towardsdatascience.com/apache-hive-optimization-techniques-1-ce55331dbf5e?source=collection_archive---------5-----------------------

Apache Hive 是一个查询和分析引擎,构建在 Apache Hadoop 之上,使用 MapReduce 编程模型。它提供了一个抽象层,通过使用 Java API 实现传统的 SQL 查询,使用 SQL 语法查询大数据。蜂巢的主要组件如下:

  • Metastore
  • 驾驶员
  • 编译程序
  • 【计算机】优化程序
  • 执行者
  • 客户

虽然 Hadoop/hive 可以处理几乎任何数量的数据,但优化可以在处理时间和成本方面带来与数据量成比例的巨大节省。在 hive 中可以应用大量的优化。让我们来看看我们将要涉及的优化技术:

  1. 分割
  2. 桶装
  3. 使用 Tez 作为执行引擎
  4. 使用压缩
  5. 使用 ORC 格式
  6. 连接优化
  7. 基于成本的优化器

分区

分区根据特定列的值将表分成几个部分。一个表可以有多个分区列来标识一个特定的分区。使用分区很容易对数据切片进行查询。分区列的数据不保存在文件中。在检查文件结构时,您会注意到它根据分区列值创建文件夹。这确保了在执行特定作业时只读取相关数据,减少了查询所需的 I/O 时间。因此,提高了查询性能。

当我们在分区表上查询数据时,它只会扫描要查询的相关分区,跳过不相关的分区。现在,假设即使进行分区,分区中的数据也相当大,为了进一步将它分成更易于管理的块,我们可以使用分块。

创建由(partition1 data_type,partition2 data_type,…)分区的表 table_name (column1 data_type,column2 data_type,…)。);

  • 表的列列表中未定义分区列。
  • 在插入查询中,分区在开头被提及,并且它们的列值也与其他列的值一起被给出,但是在结尾。

向表中插入 table_name 分区(partition1 = 'partition1_val ',partition2 = 'partition2_val ',…)值(col1_val,col2_val,…,partition1_val,partition2_val,…);

  • 分区基本上有两种类型:静态动态。名字是不言自明的。
  • 静态分区 当我们知道将要加载的数据的分区时,就可以进行静态分区。当从大文件中加载表中的数据时,这应该是首选方法。它在严格模式下执行:

设置 hive . mapred . mode = strict;

  • 动态分区 当我们不知道数据的分区时,就使用它。在表中加载数据需要更多时间。通常,我们使用另一个包含未分区数据的表来装载表中的数据。
    在配置单元中启用动态分区:

设置 hive . exec . dynamic . partition = true;

动态分区有两种模式:
严格:这需要在加载数据时至少有一列是静态的。
非严格:这允许我们拥有所有分区列的动态值。

SET hive . exec . dynamic . partition . mode = non strict;

使用动态分区时,还需要配置其他一些东西,比如

hive . exec . max . dynamic . partitions . pernode:每个映射器/缩减器节点中要创建的最大分区数

hive . exec . max . dynamic . partitions:总共允许创建的最大动态分区数

hive . exec . max . created . files:MapReduce 作业中所有 mapper/reducer 创建的最大 HDFS 文件数

hive . error . on . empty . partition:如果动态分区插入生成空结果,是否抛出异常

桶装

存储桶提供了灵活性,可以进一步将数据分成更易于管理的部分,称为存储桶或集群。存储基于哈希函数,哈希函数取决于存储列的类型。由相同列值存储的记录将始终保存在相同的存储桶中。 CLUSTERED BY 子句用于将表分成桶。对于具有高基数的列,它工作得很好。

创建由(partition1 data_type,partition2 data_type,…)分区的表 table_name (column1 data_type,column2 data_type,…)。)按(clus_col1)聚类按(sort_col2)排序到 n 个桶中;

在 Hive 分区中,每个分区将被创建为一个目录。但是在 Hive 桶中,每个将被创建为一个文件

设置 hive . enforce . bucket ing = true;

使用分桶,我们还可以使用一个或多个列对数据进行排序。因为数据文件是大小相等的部分,所以分桶表上的映射端连接会更快。

当与 ORC 文件一起使用并用作连接列时,分段也有它自己的好处。我们将进一步讨论这些好处。

使用 Tez 作为执行引擎

Apache Tez 是一个客户端库,它像一个执行引擎一样运行,是传统 MapReduce 引擎的替代引擎,在 Hive 和 Pig 下,它允许使用 DAG 格式更快地处理作业。

为了研究 Tez 如何帮助优化作业,我们将首先研究 MapReduce 作业的定型处理序列:

  • Mapper 函数从文件系统中读取数据,将其处理成键值对,然后临时存储在本地磁盘上。这些按键值分组的键值对通过网络发送给 reducers。
  • 在要运行 Reducers 的节点上,数据被接收并保存在本地磁盘上,等待来自所有映射器的数据到达。然后,将一个键的整组值读入一个 reducer,进行处理,并进一步写入输出,然后根据配置进一步复制输出。
  • 正如您所注意到的,单个 MapReduce 作业中包含了大量不必要的读/写开销。运行多个 MapReduce 作业来完成单个配置单元查询,并且 MapReduce 作业的所有输出首先被写入 DFS,然后被传输到节点,并且由于两个 MapReduce 作业之间没有协调,所以循环被重复。

Apache Tez 通过不中断多个 MapReduce 作业中的 Hive-query 来优化它。因为,Tez 是一个客户端库,用于编排 MapReduce 作业的处理。Tez 使用如下步骤优化作业:

  • 跳过缩减器的 DFS 写入,并将缩减器的输出直接作为输入管道传输到后续映射器中。
  • 级联一系列减速器,而不插入映射器步骤。
  • 连续加工阶段容器的重复使用。
  • 使用预热容器实现最佳资源利用。
  • 基于成本的优化。
  • 矢量化查询处理。

我们可以使用下面的查询来设置执行引擎,或者在 hive-site.xml 中设置它。

设置 hive . execution . engine = tez/Mr

使用压缩

正如您可能已经注意到的,hive 查询涉及大量的磁盘 I/O 或网络 I/O 操作,通过压缩减少数据的大小可以很容易地减少这些操作。Hive 中的大多数数据格式都是基于文本的格式,可压缩性很强,可以节省大量成本。但是,当我们考虑压缩时,有一个权衡,压缩和解压缩的 CPU 成本。

以下是执行 I/O 操作和压缩可以节省成本的主要情况:

  • 从本地 DFS 目录中读取数据
  • 从非本地 DFS 目录读取数据
  • 将数据从缩减器移动到下一级映射器/缩减器
  • 将最终输出移回 DFS。

此外,DFS 复制数据也是为了容错,当我们复制数据时,会涉及更多的 I/O 操作。

您可以将使用 Gzip 或 Bzip2 压缩的文本文件直接导入存储为 TextFile 的表格中。使用 LOAD 语句或通过在压缩数据位置上创建表,可以将压缩数据直接加载到 Hive 中。将自动检测压缩,并在查询执行期间动态解压缩文件。然而,在这种情况下,Hadoop 将无法将您的文件分割成块/块,并并行运行多个映射。但是,压缩的序列文件可以分割成多个。

上面的优化将会节省大量的执行成本,并且会使作业执行得更快。在下一篇文章的中,我们将讨论剩下的技术:使用 ORC 文件的优化、连接查询的优化以及基于成本的优化。

我希望你会发现这篇文章内容丰富且简单易学。如果你有任何疑问,请随时拨打 info.ankitp@gmail.com的电话联系我

Apache Hive 优化技术— 2

原文:https://towardsdatascience.com/apache-hive-optimization-techniques-2-e60b6200eeca?source=collection_archive---------2-----------------------

在早期文章中,我们介绍了如何使用分区和分桶进行适当的数据建模,选择 Tez 作为执行引擎以及压缩可以证明是非常大的成本节约因素。现在,让我们深入研究其他可以带来丰硕成果的优化因素。

使用 ORC 格式

选择正确的文件格式可以在很大程度上优化处理工作。Hive 支持一大系列文件格式:

  • 文本文件
  • 序列文件
  • RC 文件
  • Avro 文件
  • ORC 文件
  • 镶木地板
  • 自定义输入格式和输出格式

以前,这些列格式的大多数数据都是以分隔文本文件的形式存储的。在这些文件中,即使我们必须只读取一列,我们也必须读取和解析每行的整个记录。ORC 文件在 Hive 中支持多种优化,如下所示:

  • 实现更高级别的压缩,可以使用配置单元中的 orc.compress 设置来更改压缩算法。默认情况下,它使用 Zlib 压缩。
  • 如果与查询无关,它能够使用存储在文件中的轻量级索引跳过扫描块中的整个范围的行。
  • 如果与查询无关,它能够跳过块内行的解压缩。
  • 单个文件作为每个任务的输出,减少了名称节点上的负载。
  • 它支持多个流同时读取文件。
  • 它使用协议缓冲区将元数据保存在文件中,用于序列化结构化数据。

ORC 存储策略是面向列和面向行的。ORC 格式文件包含以适当大小的“条带”形式写入的表格数据,以便在单个映射器中进行处理(常见大小为 256 MB 和 512 MB。)条带可以由单独的任务处理,也可以不由单独的任务处理,一个 ORC 文件可以包含许多条带,每个条带都是独立的。在条带中,列是单独压缩的,只有查询投影中的列需要解压缩。

在一个条带中,数据分为 3 组:

  1. 条带页脚包含流位置的目录。
  2. 行数据用于表格扫描,默认包含 10,000 行。
  3. 索引数据包括每列的最小值和最大值以及每列中的行位置。行索引条目提供偏移量,使得能够在解压缩的块中寻找到正确的压缩块和字节。请注意,ORC 索引仅用于选择条带和行组,而不用于回答查询。

仅使用 ORC 格式,就会产生以下优化:

  • 下推谓词
  • 布隆过滤器
  • ORC 压缩
  • …向量化…

下推谓词

ORC 读取器使用条带的索引数据中存在的信息来确定条带中的数据是否与查询相关。因此,在从行数据块中解包相关列之前,查询的 where 条件被传递给 ORC 阅读器。例如,如果 where 条件中的值不在块的最小/最大范围内,则可以跳过整个块。

布隆过滤器

Bloom Filters 是一种概率数据结构,它通过使用最少量的内存来告诉我们一个元素是否存在于一个集合中。布鲁姆过滤器的一个引人注意的地方是,它们偶尔会错误地回答某个元素存在,而实际上它并不存在。然而,他们的可取之处在于,如果某个元素存在,他们永远不会告诉你它不存在。

Bloom Filters 同样有助于 ORC 文件格式的下推谓词。如果为列指定了 Bloom filter,即使行组索引中的 min/max 值表明给定的列值在该行组的范围内,Bloom filter 也可以明确回答该值是否实际存在。如果 where 子句中的值很有可能不存在,这可以节省大量无意义的数据操作。

我们可以使用以下表属性设置布隆过滤器列和布隆过滤器的误报概率:

  • orc . bloom . filter . columns:应该为其创建 bloom filter 的列名的逗号分隔列表
  • orc.bloom.filter.fpp: 布隆过滤器的误报概率。

ORC 压缩

ORC 格式不仅压缩列的值,还压缩整个条带。它还提供了对整体压缩算法的选择。它允许使用以下压缩算法:

  • Zlib: 更高的压缩率。使用更多 CPU 并节省空间。
  • 爽快:压缩量少。使用更少的 CPU 和更多的空间。
  • 无:完全没有压缩。

如果 CPU 很紧张,你可能想用 Snappy。您很少希望使用 none,它主要用于诊断目的。此外,蜂巢的作者是聪明的,如果它没有预见到任何边际收益,它不会压缩数据。

…向量化…

使用矢量化查询执行,可以在很大程度上优化扫描、过滤、聚合和连接等查询操作。标准的查询执行一次处理一行,经历一个很长的代码路径以及大量的元数据解释。

矢量化通过一次处理一个包含 1024 行的块来优化查询执行,其中每一行都保存为一个矢量。在向量上,简单的算术和比较运算可以很快完成。执行速度加快是因为在同一类型的大数据块中,编译器可以生成代码以在一个紧循环中执行相同的函数,而无需经过独立函数调用所需的长代码路径。这种类似 SIMD 的行为导致了许多低层次的效率:更少的执行指令,更好的缓存行为,改进的流水线操作,更好的 TLB 行为,等等。

不是每种数据类型和操作都可以从矢量化中受益,但是大多数简单的操作可以,而且网络通常是一个显著的加速。

要使用矢量化查询执行,必须以 ORC 格式存储数据,并设置以下变量,如 Hive SQL 所示:

设置 hive . vectorized . execution . enabled = true;

设置 hive . vectorized . execution . reduce . enabled = true

设置 hive . vectorized . execution . reduce . group by . enabled = true

我们可以使用 Explain 命令检查查询是否以矢量化的方式执行。在 Explain 命令的输出中,您可能会在不同阶段看到以下内容:

执行方式:矢量化

连接优化

因此,在深入研究连接优化之前,让我们了解一个普通的连接查询实际上是如何使用 MapReduce 执行的。

  • 映射器对连接键上的表进行并行排序,然后传递给 reducers。
  • 具有相同关键字的所有元组被给予相同的缩减器。一个缩减器可以为多个键获取元组。元组的键还将包括表 id,因此可以识别具有相同键的两个不同表的排序输出。Reducers 将合并排序后的流以获得连接输出。

在编写连接查询时要记住的一点是,最后提到的表是通过 reducer 传输的,其余的都缓存在 reducer 的内存中。因此,我们应该始终记住,大表是在最后提到的,这将减少 reducer 所需的内存,或者我们可以使用 STREAMTABLE 提示。

SELECT/+stream table(a)/a . val,b.val,c . val FROM a JOIN b ON(a . key = b . key 1)JOIN c ON(c . key = b . key 1)

另一件需要注意的事情是,当 where 子句用于连接时,首先执行连接部分,然后使用 where 子句过滤结果。比如,在下面的查询中:

SELECT a.val,b . val FROM a LEFT OUTER JOIN b ON(a . key = b . key)其中 a . ds = ' 2009–07–07 '和 b . ds = ' 2009–07–07 '

而在连接表时也可以执行相同的记录过滤。这可以通过包含过滤条件和连接条件来实现。

SELECT a.val,b . val FROM a LEFT OUTER JOIN b
ON(a . key = b . key AND b . ds = ' 2009–07–07 ' AND a . ds = ' 2009–07–07 ')

该连接包括混洗阶段,在该阶段中,映射器的输出被排序并用连接键混洗,这在处理、I/O 和数据传输成本方面需要很大的执行成本。因此,为了降低上述成本,已经开发了许多连接算法,例如:

  • 多路连接
  • 地图连接
  • 桶图连接
  • 中小企业加入
  • 倾斜连接

多路连接

如果多个连接共享同一个驱动端连接键,那么所有这些连接都可以在一个任务中完成。
示例:(R1 pr1 . x = R2 . a—R2)pr1 . x = R3 . b—R3)pr1 . x = R4 . c—R4
所有连接都可以在同一个归约器中完成,因为 R1 已经根据连接键 x 进行了排序。
因此,通过在一个归约器中完成所有归约任务,减少了归约器的数量。Hive 自己做这个优化,内部管理。如下面的查询所示:

从 JOIN b ON(a . key = b . key 1)JOIN c ON(c . key = b . key 1)中选择 a.val,b.val,c.val

映射连接(广播连接或广播哈希连接)

对于星型模式连接非常有用,这种连接算法将所有小表(维度表)保存在所有映射器的内存中,而大表(事实表)在映射器中通过它进行流式传输。这避免了普通连接中固有的洗牌成本。对于每个小表(维度表),将使用连接键作为哈希表键来创建哈希表,并且当在映射器函数中合并数据时,数据将与映射哈希值相匹配。

但是约束条件是,除了一个表之外,所有被连接的表都很小,所以连接可以作为仅映射作业来执行。

如果我们允许 Hive 通过执行以下设置来优化连接,则 hive 可以将连接优化到映射端连接中:

设置 hive . auto . convert . join = true;

设置 hive . auto . convert . join . noconditionaltask = true;

设置 hive . auto . convert . join . noconditionaltask . size = 10000000;

前两个设置将允许 hive 优化连接,第三个设置将让 hive 了解 mapper 函数中的可用内存,以保存小表的哈希表。

或者,我们也可以在查询中使用 MAPJOIN 提示,例如:

*SELECT /*+ MAPJOIN(b) / a.key,a.value

从 a.key = b.key 上的 a JOIN b

但是限制是,不能对表 b 执行全外连接和右外连接。

桶图连接

让我们假设表的大小更大,以适合映射器的内存。但是,当分块到存储桶中可以放入内存时,被连接的表在连接列上分桶,并且一个表中的存储桶数量是另一个表中存储桶数量的倍数,可以通过在内存中创建较小表的存储桶的哈希表并在映射器中流式传输另一个表的内容来将存储桶相互连接。假设,如果表 A 和 B 各有 4 个桶,那么下面的连接只能在映射器上完成。

S ELECT /*+ MAPJOIN(b) */ a.key,a.value
从 a.key = b.key 上的 JOIN b

不是为 A 的每个映射器完全提取 B,而是只提取所需的桶。对于上面的查询,A 的映射器处理桶 1 将只提取 b 的桶 1。这不是默认行为,由以下参数控制。

设置 hive . optimize . bucketmapjoin = true

排序-合并-桶联接

这是对存储桶映射连接的优化;如果要连接的数据已经按照连接键进行了排序,则避免创建哈希表,而是使用排序-合并连接算法。可以使用以下设置来使用此连接:

set hive . input . format = org . Apache . Hadoop . hive . QL . io . bucketizedhiveinputformat;
设置 hive . optimize . bucketmapjoin = true;
设置 hive . optimize . bucketmapjoin . sorted merge = true;

该查询将与上面的查询相同,并且 hive 将形成它的执行策略。

SELECT /*+ MAPJOIN(b) */ a.key,a.value
来自 a.key = b.key 上的一个 JOIN b

倾斜连接

如果数据的分布对于某些特定值是倾斜的,那么连接性能可能会受到影响,因为连接操作符的一些实例(map-reduce 世界中的 reducers)可能会过载,而其他实例可能会利用不足。在用户提示下,hive 会将 skew 值周围的连接查询重写为连接的联合。因此,它将执行一个查询来实现偏斜键的连接,另一个查询用于其余的连接键,并进一步合并两个查询的输出。

示例 R1 PR1.x=R2.a — R2,其中大部分数据分布在 x=1 附近,则此连接可以重写为(R1 PR1.x=R2.a 和 pr1 . x = 1—R2)union all(R1 pr1 . x = R2 . a 和 PR1.x <> 1 — R2)

设置 hive . optimize . skew join = true;
设置 hive . skew join . key = 500000;

基于成本的优化

因此,我们都同意一个问题可能有多个解决方案的说法,直到基于成本的优化器出现,hive 才使用硬编码的查询计划来执行单个查询。CBO 让 hive 根据收集的元数据优化查询计划。CBO 提供了两种类型的优化:逻辑优化和物理优化。

逻辑优化:

  • 投影剪枝
  • 推导及物谓词
  • 谓词下推
  • 将选择-选择、过滤-过滤合并到一个运算符中
  • 多路连接
  • 重写查询以适应某些列值的连接偏差

物理优化:

  • 分区修剪
  • 基于分区和存储桶的扫描修剪
  • 如果查询基于采样,则进行扫描修剪
  • 在某些情况下,在地图端应用分组依据
  • 优化联合,以便只能在地图端执行联合
  • 在多路连接中,根据用户提示决定最后传输哪个表
  • 删除不必要的 reduce sink 运算符
  • 对于带有 limit 子句的查询,减少需要为表扫描的文件数量。

打开 CBO 通常会将查询的执行时间减半,而且效果可能会更好。除了这些优化,CBO 还将使用保存在 metastore 中的表的统计信息,将连接查询转换为可能的最佳连接。

可以使用 hive-site.xml 文件中的以下设置打开 CBO:

hive.cbo.enable=true

如果 hive.stats.autogather 设置为 True,则表的统计信息由 hive 自动收集,否则可以使用 ANALYZE 命令进行计算。

我希望这篇文章和之前的文章能够给你一个关于如何优化 hive 查询以及 Hive 的关键特性如何在后台使用 MapReduce 的完整概述。

我希望你会发现这篇文章内容丰富且易于学习。如果你有任何疑问,请随时拨打 info.ankitp@gmail.com的电话联系我,并通过 LinkedIn 与我联系。

阿帕奇卡夫卡:平台架构和流分析

原文:https://towardsdatascience.com/apache-kafka-platform-architecture-and-streaming-analysis-68ee8488561d?source=collection_archive---------20-----------------------

Kafka 是一个分布式流媒体平台,允许用户发送和接收包含大量数据的实时消息。

本文将详细讨论 Kafka 的体系结构,这对于理解如何正确设置您的流分析环境至关重要。稍后,我将通过用 Kafka 创建一个即时消息环境来提供一个实时数据分析的例子。到本文结束时,你将能够理解使卡夫卡如此有用的主要特征,它们是:

  • 分布
  • 提交日志
  • 水平可扩展性
  • 容错

现在,让我们记住它们,而不解释它们的含义,在介绍一些进一步的概念后,它们的含义会清楚得多。

让我们从卡夫卡建筑开始。主要思想是,发送者将把它的消息发送到 Kafka 服务器,接收者将要求 Kafka 服务器向他显示他感兴趣的消息。然后由 Apache 发布的软件 Zookeeper 跟踪 Kafka 服务器的状态,并管理消息的所有信息和配置。当然,架构要复杂得多,但底层框架就是这样。

现在,让我们通过初始化一些术语和“角色”,开始深入卡夫卡的结构:

  • 生产者:是应用程序发送消息
  • 消息:它被 Kafka 作为一个字节数组读取
  • 消费者:接收消息的是应用程序
  • 主题:卡夫卡流的独特名称

到目前为止,我们已经对它是如何工作的有了一个更具体的想法:

如前所述,卡夫卡不断收到收发信息的请求。这些订单处理和这些数据传输的方式是通过所谓的 Kafka broker,由 Zookeeper 进行协调和管理。代理只不过是一个 Kafka 服务器,这是一个有意义的名称。代理的概念直接导致了集群的概念。事实上,代理运行在 Kafka 集群上,Kafka 集群是一组机器,每个机器执行 Kafka 代理的一个实例。让我们将这两个进一步的概念添加到我们的列表中:

  • Broker:在集群上运行的 Kafka 服务器。它管理收到的消息并将它们发送给消费者
  • 集群:一组机器,每个机器执行 Kafka broker 的一个实例

注意,机器集群的概念解释了分布的含义。事实上,分布式系统是一个分成多个运行机器(每个机器执行一个代理)在一个集群上一起工作的系统。

有时,生产者发送的数据量巨大而沉重,集群中的一台计算机可能无法存储和处理这些数据。这就是为什么 Kafka 提供了将我们的数据分割成更小部分的可能性,称为分区。每个分区都有一个唯一的 ID。分区的数量和大小由用户在创建主题时设置,然后 Kafka 将按照这些指示相应地拆分您的数据。

请注意,分区是基于只支持追加的持久有序数据结构的:您不能删除也不能修改已经发送到代理的消息,您只能向它们添加更多的消息。这个数据结构被称为提交日志

因此,每个分区将包含一系列需要识别的消息,这就是偏移量应该做的事情。它是一个数字数组,按照消息发送的顺序标识一个分区的每条消息(因此第一条消息的 offset=0)。注意偏移是局部的,而不是全局的,这一点很重要:每个分区都有一个用等于 0 的偏移标识的消息,但是当然这些不是相同的数据!这就是为什么每条消息都有特定的标识路径:主题名、分区号(ID)、偏移量。总而言之:

  • 分区:Kafka brokers 可以在其中拆分数据的“片段”之一
  • 偏移量:一个 ID 号序列,在本地标识每个分区中消息的顺序

在上一张图中,我假设一个集群只有一台机器,因此只有一个代理。但是,当经纪人很多的时候,就需要引入 Kafka 生态系统的另一个特征。我说的是复制的概念:事实上,Kafka 能够在可配置数量的服务器(或代理)上存储 topic 的分区,这样每个分区都可以在其他代理上复制。因此,每个代理拥有几个分区,每个分区可以是一个主题的领导者或复制品。对于每个分区,有权管理它的代理是存储其“leader”版本的代理。但是,如果这个代理的机器出现故障,这个分区的处理将在它的一个副本上继续,该副本将成为新的领导者。

让我们把它形象化,让它更清楚:

这里我们有三个代理和三个复制因子为 3 的分区(每个分区有三个副本)。如果三个代理都没有崩溃,代理 1 将只处理存储在分区 0 中的数据,因为它是“主要”版本,而它的副本将与它同步。类似地,代理 2 和 3 将分别处理分区 1 和 2。这种处理数据的方式基于水平可伸缩性的概念,也就是说,通过投入更多的机器来解决同样的问题。

现在想象一下正在执行代理 1 崩溃的机器。发生的情况如下:

现在代理 2 的分区 0 是新的领导者,所以代理 2 将处理分区 0 和 1。这个概念有助于我们解释容错:如果一个分区有 n 个副本,那么即使发生 n-1 个故障也可以处理。

我想介绍的最后一个概念与消费者有关。假设我们只有一个消费者,但有大量的数据要发送给他:他可能无法处理所有这些数据。我们希望我们的数据被并行处理,但是我们如何实现呢?答案是通过创造一个消费群体。它是由几个消费者组成的单个接收应用程序,每个消费者从一个或多个分区中读取数据(但是同一个分区不能从两个不同的消费者中读取:没有重复)。因此,消费者的最大数量是分区的数量,否则一些消费者将什么也不做。请注意,当一个组中有多个用户时,消息在一个分区内按顺序读取,但是跨分区并行读取。

因此,一个示例情况可能如下:

我们将一个主题分成三个分区,并且我们有一个由三个成员组成的消费者组,每个成员阅读一个分区。

但是,如果有新的消费者喜欢这个群体,或者实际消费者离开,会发生什么呢?Kafka 如何决定重新分配分区并在新消费者的配置中重新平衡工作?

卡夫卡需要的是一个团体协调员,因此其中一个经纪人被选为团体协调员。当消费者想要享受或离开团体时,他必须将请求发送给团体协调员。第一个享受群体的消费者成为群体的领导者。因此,当需要某种重新平衡时,组协调者决定如何重新分配分区(记住消费者数量的上限),而组长负责执行这个操作。

好了,现在你对卡夫卡的架构有了一个概念,让我们来运行一个非常基本的例子。

在为 Kafka 创建了我的虚拟环境之后,我创建了一个新的主题,叫做“test”,它不会被划分分区(的确,它只会有一个分区),也不会被复制很多次(它的复制因子等于 1);

现在,我正在创建我的生产者,编写他将发送给消费者的三条消息:

(kafka) [root@quickstart kafka] kafka-console-producer --broker-list localhost:9092 --topic test 
>hello 
>this is my first message 
>this is my second message

最后,让我们设置我们的消费者,它将能够接收生产者在上面写的消息:

(kafka) [root@quickstart kafka] kafka-console-consumer --bootstrap-server localhost:9092 --topic test --from-beginning hello 
this is mt first message 
this is my second message

如果使用 Spark Streaming 实现 Apache Kafka,您不仅可以跟踪流数据,还可以在其上构建相关分析。如果您需要跟踪工作的引擎并关注延迟或次优执行,或者如果您需要了解市场对您的新业务战略的反应,该工具尤其强大。

无论涉及哪个业务部门,实时数据分析都可以为其增加相关价值。

原载于 2019 年 7 月 9 日http://datasciencechalktalk.com

阿帕奇卡夫卡流和表,流表二元性

原文:https://towardsdatascience.com/apache-kafka-streams-and-tables-the-stream-table-duality-ee904251a7e?source=collection_archive---------13-----------------------

最初发表于我的个人博客。

在之前的帖子中,我们试图理解阿帕奇的卡夫卡流的基础。在本帖中,我们将基于这些知识,看看 Kafka 流如何既可以用作流,也可以用作表。

当今,流处理在大多数现代应用程序中已经变得非常普遍。您将至少有一个流进入您的系统进行处理。根据您的应用程序,它通常是无状态的。但并非所有应用都是如此。我们将在数据流之间进行某种数据浓缩。

假设您有一个用户活动流进来。理想情况下,您会将一个用户 ID 附加到该流中的每个事实上。但是在管道中,用户 ID 不足以进行处理。也许您需要更多关于用户的信息才能出现在事实中。为此,您将查询数据库,获取用户记录,并将所需的数据添加到事实中。这个丰富的事实将被发送到另一个流进行进一步处理。

可以想象,流与数据库密切相关,至少在大多数实际应用程序中是如此。这也是为什么 Apache 在 Kafka 流中引入了 KTables 的概念。这使得流表二元性成为可能。

流表对偶

在阿帕奇卡夫卡中,流和表一起工作。流可以是表,表可以是流。这是卡夫卡作品的一个特性,我们可以用它来获得这种多样性。让我们看看我的意思。

  • —一个表可以被看作是一个流的变更日志的集合。这就是说,一个表在给定的时间点将具有特定事实的最新值。例如,如果我们在一个电子商务应用程序中维护购物车上每个事件的流,那么一个表将具有购物车的最新状态。如果我们回放 changelog,我们应该能够创建一个实际的表。
  • Stream —类似地,一个表可以被视为一个流,特定字段的最新值进入其中。它只是在给定时间点流中某个键的最新值的快照。

现在让我们看看 KStream 和 KTable。

KStream

KStream 也不过如此,一个卡夫卡式的流。这是一个永无止境的数据流。每条数据——一条记录或一个事实——都是键值对的集合。还要注意的是,进入流的每个事实本质上都是不可变的。在将一个事实发送到流中之后,可以更改任何值的唯一方法是在更新值之后发送另一个事实。

KTable

KTable 只是流的抽象,其中只保存最新的值。例如,假设我们将以下事实推入表中:

{
  "name": "Sunny Srinidhi",
  "city": "Mysore",
  "country": "India"
}

在这个事实出现一天后,我搬到了一个新的城市,这个变化必须被系统捕捉到。因此,我将另一个事实与以下数据一起发送到流中:

{
  "name": "Sunny Srinidhi",
  "city": "Bangalore",
  "country": "India"
}

现在,KTable 中以前的事实将被更新以反映新的值,而不是将其视为一条新的信息。

正如您所看到的,KTable 主要作为数据库中的传统表工作。唯一的区别是,KTable 中的每个条目都被认为是一个 UPSERT(插入或更新)。这意味着,如果 KTable 中有旧版本的数据,它将被更新为最新的值。但是如果没有旧版本,事实将被插入到 KTable 中。

这里需要注意的一点是,KTables 对于值 null 有特殊的含义。如果您向一个值为 null 的 KTable 发送一个键-值对,它将被认为是一个删除指令,这个事实将从 KTable 中删除。你必须确保不会意外地将程序中的任何 null 值发送到 KTable 中,否则你可能会丢失已经存储的数据。

全球表格

GlobalKTable 是对已经抽象的 KTable 的抽象。当我们处理分布式应用程序时,这很方便。为了更好的理解,我们举个例子。假设我们有一个正在填充 KTable 的应用程序。由于流量激增,我们在集群中部署了更多的应用程序实例,比如 10 个实例。并且每个实例都从底层 Kafka 主题的单独分区中读取数据。

现在,每个实例都有自己的 KTable 副本。这个本地 KTable 将只填充来自分配给该应用程序实例的特定分区的数据。所以没有一个本地 KTables 拥有所有需要的数据。如果您在表上运行连接或聚合,您的结果会有偏差,因为数据不完整。

在这种情况下,如果使用 GlobalKTable,而不是使用 KTable,该表将填充所有分区的数据。所以在你的 GlobalKTable 的所有本地实例中,你有一个更加完整的数据集。除此之外,GlobalKTables 还有一些聚合和连接好处。

在以后的文章中,我们将看到一些代码示例,其中我们使用 Kafka Streams APIs 来实际实现我们刚刚试图理解的所有概念。

在 Twitter 上关注我,了解更多数据科学、机器学习,以及通用技术更新。此外,你可以关注我的个人博客,因为我在 Medium 之前发布了许多我的教程、操作方法帖子和机器学习的优点。

如果你喜欢我在 Medium 或我的个人博客上的帖子,并希望我继续做这项工作,请考虑在 Patreon 上支持我。

阿帕奇火花-3.0 斯内克峰

原文:https://towardsdatascience.com/apache-spark-3-0-sneek-peak-284da5ad4166?source=collection_archive---------18-----------------------

Apache Spark 多年来一直保持强劲,现在带着其主要版本之一回归,其持续的目标是统一分析,将批处理和流世界融合为一。让我们来看看它的一些特点。

  1. 改进的优化器和目录
  2. 三角洲湖(酸性交易)+ Linux 基金会
  3. 考拉:给熊猫带来火花尺度
  4. Python 升级
  5. 深度学习
  6. 库伯内特斯
  7. Scala 版本升级
  8. 图形 API —图形和密码脚本。
  9. GPU 支持以及氢项目
  10. Java 升级
  11. 纱线升级
  12. 二进制文件

改进的优化器和目录:

i) 可插拔数据目录:(DataSourceV2)

  • 可插拔目录集成
  • 改进的下推
  • 面向流和批处理的统一 API
eg: df.writeTo(“catalog.db.table”).overwrite($”year” === “2019”)

ii) 自适应查询执行

  • 在查询执行期间做出更好的优化决策

例如:它解释表的大小,并自动从排序合并连接变为广播连接等等..如果其中一张桌子很小

  • 动态分区修剪加速昂贵的连接

基于维度表(小表)过滤器查询事实表(大表)也将被过滤,使连接更容易和最佳

三角洲湖:

Delta Lake 已经开源了很长一段时间,并且由于其易于实现和升级到任何现有的 Spark 应用程序而广受欢迎。我相信,这是下一代的数据湖,有助于克服数据沼泽以及 Lambda 和 Kappa 架构的局限性。现在有了 Linux 基金会的支持,这个程序将会更上一层楼。

以下是一些有助于我们向统一分析迈进一步的功能。

  • 酸性交易
  • 架构实施
  • 可扩展元数据处理
  • 时间旅行

注:关于 DeltaLake 的更多细节将会在我不久后的每日帖子中更新——(同时 关注我 或标签 #jayReddy )

考拉:给熊猫带来火花尺度:

考拉最近已经发布,它是 Python 开发人员的一个很大的附加产品,对于数据工程师和数据科学家来说都是如此,因为它在数据帧和熊猫之间有相似之处。现在,他们可以从单节点环境扩展到分布式环境,而不必单独学习 Spark 数据帧。

  • 集成到 Python 数据科学生态系统中。例如:numpy,matpotlib
  • 数据框架/系列 API 的 60%
  • 60%的数据帧分组依据
  • 指数/多指数 API 的 15%
  • 如果图起作用,80%
  • 90%的多索引列

Python 升级:

Python 有望完全从版本 2 迁移到版本 3。

深度学习:

  • 请求 RDD 操作中的 GPU。也就是说,您可以指定在 RDD 操作中每个任务使用多少个 GPU,例如用于 DL 训练和推理。
  • YARN+Docker 支持用 GPU 资源推出我的 Spark 应用。所以您可以很容易地在 docker 文件中定义 DL 环境。

Kubernetes:

通过 Kubernetes 的主机集群是下一件大事,它可能是内部部署或云。与其他编排容器(如 Mesos 和 Docker Swarm)所用的时间相比,部署、管理和启动时间的简易性将会大大提高。

  • Spark-submit 使用变异的 webhook confs 在运行时修改 pods
  • GPU 资源的自动发现
  • 执行程序 pod 级别的 GPU 隔离
  • spark-使用 pod 模板提交
  • 指定用于任务的 GPU 数量(RDD 舞台,熊猫 UDF)

Kubernetes 编排容器并支持一些容器运行时,包括 Docker。Spark(版本 2.3 以上)附带了一个 docker 文件,可以用于此目的,并根据特定的应用程序需求进行定制。

Scala 版本升级:

  • Scala 2.12

图形 API —图形和密码脚本:

火花图形 Api 有一个新的附加组件。

  • 一个图形以及属性图和密码脚本。

密码查询执行、查询结果处理和属性图存储/加载。为 API 提供一个独立模块的想法是允许一个 Cypher 查询引擎的多种实现。

  • Graph query 将有自己的催化剂&它将遵循与 SparkSQL 相似的原则。

GPU 支持以及氢项目:

NVIDIA 拥有最好的 GPU,它已经远远超过了任何其他供应商。Spark 3.0 最适合这种情况。(英伟达 RTX——2080)是值得警惕的。

  • 列出 GPU 资源
  • 自动发现 GPU
  • GPU 分配给作业和回退
  • 熊猫 UDF 的 GPU
  • GPU 利用和监控
  • 支持异构 GPU (AMD、Intel、Nvidia)

Java 升级:

随着 Java 社区每一个新的 JDK 版本的发布,我们都可以看到它向函数式编程迈近了一步。

Java-8 版本的发布是它的开始,从 Lambda 表达式开始。

下面是一个变量声明的例子:

Java 10 版本之前:

String text = "HelloO Java 9";

来自 Java 10 及更高版本:

var text = "HelloO Java 10 or Java 11";

纱线升级:

  • GPU 调度支持
  • GPU 的自动发现
  • 进程级的 GPU 隔离

下面是支持从 Spark 或 Yarn 3 版本开始的 GPU 的配置设置

GPU 调度

在 resource-types.xml 中

configuration>
  <property>
     <name>yarn.resource-types</name>
     <value>yarn.io/gpu</value>
  </property>
</configuration>

在 yarn-site.xml 中

<property>
    <name>yarn.nodemanager.resource-plugins</name>
    <value>yarn.io/gpu</value>
  </property>

二进制文件:

为支持非结构化数据而添加的另一种文件格式。你可以用它来加载图像、视频等等。限制是它不能执行写操作。

val df = spark.read.format(BINARY_FILE).load("Path")

现在你已经知道了 Spark 下一个主要版本,你可以看看 Spark 3.0 预览版。

如果你喜欢这篇文章,那么你可以看看我的文章

  • 深入火花内部架构
  • 大数据生态系统架构

注: Delta-Lake 和考拉既可以是 Spark-3.0 的一部分,也可以作为单独的实体作为 Databricks 的一部分。

如果你也愿意,可以在 LinkedIn 上与我联系— Jayvardhan Reddy 。

Apachespark # bigdata #数据工程师#数据科学#深度学习# ai # jayReddy # python # Scala # spark

Apache Spark:概念导向

原文:https://towardsdatascience.com/apache-spark-a-conceptual-orientation-e326f8c57a64?source=collection_archive---------10-----------------------

这是什么?为什么重要?

什么是阿帕奇火花?

Apache Spark ,曾经是 Hadoop 生态系统的一部分,是一个强大的开源、通用分布式数据处理引擎,提供实时流处理、交互式处理、图形处理、内存处理、非常快速的批处理和易用性。应用程序开发人员和数据科学家将 Spark 集成到他们的应用程序中,以快速查询、分析和转换大规模数据。Spark 最常见的任务包括跨大型数据集的 ETL 和 SQL 批处理作业,处理来自传感器、物联网或金融系统的流数据,以及机器学习任务。领先的科技公司现在希望有一个强大的引擎可以做所有这些事情,幸运的是,如果你已经知道 Python 和 SQL,Spark 并不太难学。

Spark 最初于 2009 年在加州大学伯克利分校开发,此后许多互联网巨头都采用了 Spark,在 8K+节点的集群上集体处理数 Pb 的数据。它已经成为大数据领域最大的开源社区,拥有超过 1K+代码贡献者、180,000+成员和 400+会议。

重要术语

  • Apache Spark:“Apache Spark 是一个开源的分布式通用集群计算框架。”抱歉,你说什么?
  • 分布式计算 —简而言之,Apache Spark 解决了数据集太大,或者新数据太快,单台计算机无法处理的问题。进入分布式计算。这些任务可以在相互通信的多台计算机之间分配,而不是试图在单台计算机上处理计算量大的程序。当 Spark 说它与分布式数据有关时,这意味着它被设计来处理非常大的数据集,并在分布式计算系统上处理它们。
  • 通用 — Spark 非常灵活,有许多应用领域。它支持 Scala、Python、Java、R 和 SQL。它有一个专用的 SQL 模块,能够实时处理流数据,并有一个机器学习库和现成的图形计算引擎。
  • 集群计算— 计算机集群是一组松散或紧密连接的计算机,它们协同工作,因此可以被视为一个单一系统。他们将每个节点设置为执行相同的任务,由软件控制和调度。
  • 分区数据是指经过优化,能够在多个节点上处理的数据。
  • RDDs—Spark 的核心组件,弹性分布式数据集是数据元素的不可变分布式集合,可以存储在机器集群的内存中。它们可以与提供转换和动作的低级 API 并行操作。rdd 是容错的,因为它们跟踪数据沿袭信息,以便在出现故障时自动重建丢失的数据。
  • 容错 — Spark 是容错的。简而言之,容错指的是分布式系统即使发生故障也能继续正常工作的能力。如果一个节点发生故障,流程仍然可以运行。
  • 懒评价 — Spark 是“懒”,好的方面。当一个不“懒惰”的编译器编译代码时,它会依次计算每个表达式。一个懒惰的编译器不会不断地计算表达式,而是等待,直到它被真正告知输出一个结果,一次执行所有的计算。
  • PySpark——又名“Spark Python API”,py Spark 是与 Python 编程语言一起使用的 Spark,使数据科学专业人员更容易使用 Spark 的实用程序,他们对 Python 比对 Scala 更熟悉。
  • Spark DataFrames —组织成命名列的不可变分布式数据集合,就像关系数据库中的表一样,这允许开发人员将结构强加到分布式数据集合上。对于那些熟悉 Pandas 数据框架的人来说,这是相似的,只需要稍微长一点的时间来适应,并且对于较大的数据集更好。
  • MLlib —一个通用的机器学习库,旨在实现简单性、可扩展性和与其他工具的轻松集成。借助 Spark 的可伸缩性、语言兼容性和速度,数据科学家可以更快地解决和迭代他们的数据问题。
  • GraphX —一个用于图形和图形并行计算的 Spark 组件/库,它包括一个不断增长的图形算法和构建器集合,以简化图形分析。
  • Spark Streaming—Spark API 的扩展,允许数据工程师/科学家处理来自 Kafka、Flume 和 Amazon Kinesis 等来源的实时数据,并将其推送到数据库和实时仪表盘。它的关键抽象是一个离散化流(d Stream),因为它是建立在 Spark RDDs 上的,所以允许与 MLlib 和 Spark SQL 无缝集成。

从 MapReduce 到 Spark:简史

在 Spark 之前,Google 使用 MapReduce(2004 年发布的框架白皮书),这是一个弹性分布式处理框架,用于索引大型商用服务器集群中的大量 web 内容。他们想要分布数据:将数据文件分割成称为数据块的块,这些块可以分布在许多节点上,并在集群中复制。他们希望分配计算能力,在大型商用机器集群上自动并行化和执行任务,每个机器处理一个数据子集。他们希望通过将故障推迟到另一个节点来处理数据和计算,从而很好地处理故障。

一年后(2005 年),Apache Hadoop 诞生了——这是一个开源框架,旨在跨计算机集群分布式存储和处理超大型数据集。该框架支持 Hadoop 分布式文件系统(HDFS ),这是存储的底层组件,它将文件分解成块,并将它们分布在集群节点上。它支持 Yarn 进行作业调度和集群资源管理,支持 MapReduce 进行并行处理,等等。

2009 年,加州大学伯克利分校的 AMP 实验室开始了 Apache Spark 的初步工作。2013-2014 年,Apache Software Foundation 决定将 Spark 作为重中之重,与 Databricks、IBM 和华为等富裕的支持者并列。目标是做一个更好的 MapReduce 版本。Spark 通过跨多个并行操作在内存中缓存数据来执行速度更快,而 MapReduce 涉及更多的磁盘读写。Spark 的启动速度更快,并行性更好,CPU 利用率更高。它提供了比 MapReduce 更丰富的函数式编程模型,并支持迭代算法。

Spark 真正为科技行业带来了什么?

Spark 能够一次处理数 Pb 的数据。它很灵活,拥有一套跨 Java、Python、R 和 Scala 的丰富的开发人员库和 API。Spark 经常与 MapR XD、Hadoop 的 HDFS 和 Amazon 的 S3 等分布式数据存储、MapR Database、Apache HBase、Apache Cassandra 和 MongoDB 等流行的 NoSQL 数据库以及 MapR Event Store 和 Apache Kafka 等分布式消息存储一起使用。

具体优势:

  1. 简单: Spark 的功能可以通过丰富的 API 来访问,这些 API 都有良好的文档记录和结构,使数据科学家和开发人员能够轻松快速地开始工作。
  2. 速度: Spark 是为速度而设计的,在内存和磁盘上都可以运行。当支持存储在内存中的数据的交互式查询时,Spark 可以表现得很好。在这些情况下,有人声称 Spark 可以比 MapReduce 快 100 倍。
  3. 支持: Spark 支持多种编程语言,包括 Java、Python、R、Scala,以及众多前沿存储解决方案。开发人员社区规模庞大、活跃且遍布全球。更多的商业提供商,包括 Databricks、IBM 和主要的 Hadoop 供应商,为基于 Spark 的解决方案提供技术支持。

特定功能:

  1. 流数据:从活动日志到传感器数据,开发人员越来越多地被源源不断的新数据淹没,这些新数据往往同时来自多个来源。在数据到来时对其进行处理和操作通常是有意义的(例如识别欺诈性金融交易)。
  2. 机器学习:随着数据量的增加,机器学习模型往往会变得更加有用和准确。Spark 将数据存储在内存中并快速运行重复查询的能力使其成为训练 ML 算法的良好选择。大规模地重复类似的查询减少了为了找到最有效的算法而评估可能的解决方案所需的时间。
  3. 交互式/自定义分析:预定义的查询和静态仪表板效率较低,可扩展性较差,因为业务分析师和数据科学家希望通过提问、查看结果和实时深入研究来探索他们的数据。Spark 能够快速响应和适应,支持实时定制分析部署。
  4. 数据集成& ETL: 来自不同业务系统的数据很少干净到足以方便地为报告/分析做准备。提取、转换和加载(ETL)过程通常用于将数据提取、清理、标准化和加载到新系统中进行分析。Spark 可以减少这个 ETL 过程所需的成本和时间。

An Example of Possible Data Ecosystems Built Around Spark

感谢您的阅读,

亚历克斯

我们来连线!我鼓励你评论、分享或直接给我发消息,告诉我你对这里提出的想法的想法,或者对我今后应该关注的有趣话题的建议。

www.linkedin.com/in/alexandershropshire

medium.com/@as6140

github.com/as6140

特征转换

原文:https://towardsdatascience.com/apache-spark-mllib-tutorial-7aba8a1dce6e?source=collection_archive---------2-----------------------

Apache Spark ML 教程

如何处理数据集中的不同要素类型

注意:本文是系列文章的一部分。查看完整系列: 第 1 部分:回归 第 2 部分:特征转化 第 3 部分:分类 ,第 4 部分及以上即将推出。

在之前的文章中,我们谈到了 Spark ML 以及如何用它来训练回归模型。本文关注特性转换。我们会了解概念,以及如何在 Spark ML 中直接实现。

Photo by Suzanne D. Williams

特征转换

特征变换只是将特征从一种表示形式变换到另一种表示形式的函数。但是我们为什么要改变我们的特征呢?原因有很多,比如:

  1. 数据类型不适合输入到机器学习算法中,例如文本、类别
  2. 特征值可能会在学习过程中造成问题,例如,数据以不同的尺度表示
  3. 我们希望减少用于绘制和可视化数据的要素数量,加快训练速度或提高特定模型的准确性

在本文中,我们将关注三种主要的转换技术:

  • 处理分类变量
  • 特征缩放
  • 主成分分析

处理分类变量

分类数据

分类值是可以表示为类别或组的值。它们可以分为两种主要类型:标称序数

  • 标称值只是没有定义顺序的名称或标签。例子:性别,颜色。
  • 序数值是顺序很重要的类别。例如:t 恤尺寸、等级、级别。

机器学习算法无法处理以类别或标签表示的数据。因此,我们需要将这些值转换成更相关的格式。

资料组

我们将使用一个非常简单的数据集,这样我们就可以将全部注意力放在我们将要学习的技术上。数据集只是一个 CSV 文件,包含两个字段: IDColor 。[从这里下载]

设置环境

对于本文的其余部分,以下是设置开发环境的常见步骤:

  1. 打开一本 Jupyter 笔记本
  2. 导入 findspark 并初始化它
  3. 创建一个 spark 会话
  4. 加载并显示数据
import findspark
findspark.init('/opt/spark')
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
data = spark.read.csv('./datasets/colors.csv', header=True, inferSchema=True)
data.show()

Data

即使数据非常简单,我们也不能处理颜色列,因为它包含分类数据。

为了解决这个问题,我们将介绍两种主要的方法以及如何在 Spark ML 中实现:字符串索引一热编码

字符串索引

字符串索引背后的概念非常直观。我们只是用一个数字来代替每个类别。然后我们在模型中使用这个数字来代替标签。

我们是这样做的。首先,我们需要定义一个 StringIndexer

from pyspark.ml.feature import StringIndexer
indexer = StringIndexer(inputCol="color", outputCol="color_indexed")

注意这里的索引器是一个类型为估算器的对象。

估算器抽象了学习算法或任何适合或训练数据的算法的概念。从技术上来说,估算器实现了一个方法 fit() ,它接受一个数据帧并产生一个模型,这是一个转换器
来源:https://spark . Apache . org/docs/1 . 6 . 1/ml-guide . html # estimators

这里估计器的目标是学习从颜色标签到颜色索引的映射。

接下来我们调用fit()方法来启动学习过程。

*indexer_model = indexer.fit(data)*

返回的 indexer_model 是类型 Transformer 的对象。

转换器是一个抽象,包括特性转换器和学习模型。它实现了一个方法 transform() ,该方法将一个数据帧转换成另一个数据帧,通常通过追加一个或多个列来实现。
来源:https://spark . Apache . org/docs/1 . 6 . 1/ml-guide . html # transformers

在拟合估计器并得到我们的转换器之后,是时候通过调用 transform() 对我们的数据使用它了。

*indexed_data= indexer_model.transform(data)
# to view the data
indexed_data.show()*

请注意如何在我们的 outputCol 字段中添加一个新列“color _ indexed”

Data after running the StringIndexer

新列代表每个颜色值的索引。相似的颜色值具有相似的索引。这里我们看到红色、白色、橙色和蓝色分别被赋予数字 0、1、2 和 3。

这些数字将通过 VectorAssembler 收集到特征向量中,并传递给机器学习算法。

但是等等!我们还有一个问题。颜色是名义值,而不是序数。这意味着颜色名称之间没有顺序。比如:红色不大于,小于等于绿色。然而,基于当前的表示,机器学习模型可能以某种方式认为存在基于给定值的顺序。别担心,我们会用另一种叫做 One Hot Encoding 的技术来解决这个问题。

一个热编码

我们使用一个热编码(OHE)** 来打破分类列中的排序。应用 OHE 的过程如下:**

  1. 将分类列分成 n 个不同的列,其中 n 是列中唯一类别的数量
  2. 在每一列中指定一个二进制值(0 或 1 ),表示数据点中颜色的存在

回到我们的例子,我们有四种独特的颜色:红色,白色,橙色蓝色。因此,我们需要四列。我们将它们命名为:红色、白色、橙色和蓝色。现在,我们将把 1 放在 is_red 列中,把 0 放在其他列中,而不是给颜色红色设置一个值 x 。然后,我们将对数组中的值进行分组,以用作颜色特征,而不是由 StringIndexer 计算的单值索引。[参见下表以获得更好的想法]

One Hot Encoding Process

为了应用 OHE,我们首先导入 OneHotEncoderEstimator 类并创建一个估计变量。

**from pyspark.ml.feature import OneHotEncoderEstimator
ohe = OneHotEncoderEstimator(inputCols=["color_indexed"], outputCols=["color_ohe"])**

现在,我们对数据进行估计,以了解需要对多少类别进行编码。

**ohe_model = ohe.fit(indexed_data)**

我们得到了训练好的模型,是时候把它应用到我们的数据上了。

**encoded_data = ohe_model.transform(indexed_data)
encoded_data.show()**

Data after applying the One Hot Encoder

搞定了。我们有一个 color_ohe 列,它包含了我们的一次性编码数据。但是这个奇怪的表示是什么呢?它被称为 DenseVector 数据类型,用于减少存储空间。例如,数字 (3,[0],[1]) 意味着我们有一个 3 值的数组,这样我们在索引 0 处得到值 1 ,在所有其他位置得到值 0。但是,我们有四个独特的类别,为什么有三个值呢?这就是 Spark ML 的工作方式。它省略了最后一个类别,以打破特征之间的相关性。通常你不必为此担心。但是如果您想强制 Spark ML 不删除最后一列,只需在构造函数中添加 dropLast=False

**ohe = OneHotEncoderEstimator(inputCols=["color_indexed"], outputCols=["color_ohe"], dropLast=False)**

现在 color_ohe 列已经准备好被您的 VectorAssembler 收集,而不用担心颜色之间的顺序关系。

特征缩放

让我们从分类值转移到数字值。但是我们为什么需要烦恼呢?这种数据已经是数字了,可以直接用在机器学习模型中,对吗?不幸的是,情况并非总是如此。接下来,我们将了解什么是特征缩放,以及它如何改进我们的模型。

资料组

我们将使用流行的 葡萄酒数据集 【从这里下载】。让我们装上看看。

注意:为了节省空间,我省略了列名。

**data = spark.read.csv('./datasets/wine.csv', header=False, inferSchema=True)
data.show()**

Wine dataset

你可能会问数据有什么问题?那么,仔细看看每一列中的值。有些值是小分数< 1, some range between 10 and 20 and others are in thousands. Notice for each column, the difference in means, standard deviations, minimum and maximum values. [Calculated with data.describe()。显示()方法】

Wine data statistics

这种规模上的多样性可能会在一些机器学习算法(如 KMeans)中导致许多问题。这是因为算法可能会根据变量的取值范围将某些变量视为更重要的变量。例如:考虑一个关于雇员的数据集。我们可能有一个范围在 0 → 30 之间的年资列和一个以千为单位的薪水列。但这并不意味着薪资一栏更占优势!

为了解决这个问题,我们将这些值转换为相同的比例。有很多转换方法,我们将研究其中的两种。

请注意,缩放器应用于 矢量数据类型 这就是为什么我们需要首先使用矢量汇编器来收集特征:

**from pyspark.ml.feature import VectorAssembler
assembler = VectorAssembler(inputCols=data.columns[1:], outputCol="features")
data_2 = assembler.transform(data)**

****重要提示:我们省略了 _c0 列,因为它是一个分类列。Scaler 应该只应用于数值。

这里我们得到了我们的特性专栏。

标准缩放器

标准定标器**使用列-汇总-统计,通过移除平均值并定标到单位标准偏差来标准化特征。

定义一个标准定标器:

**from pyspark.ml.feature import StandardScaler
scaler = StandardScaler(inputCol="features", outputCol="scaled_features")**

****标准缩放器可以接受两个附加参数:

  • 经受:默认为真。将数据缩放到单位标准偏差。
  • withMean :默认为假。缩放前将数据以平均值为中心。

现在我们在数据集上拟合我们的估计量。

**scaler_model = scaler.fit(data_2)**

最后,我们将我们的转换器应用于数据,以获得我们的缩放特征。

**scaled_data = scaler_model.transform(data_2)**

搞定了。我们已经准备好了我们的缩放功能。

最小最大缩放器

应用任何其他定标器的过程与上面完全相同,但是使用不同的类名及其相关参数。

MinMaxScaler 将数据值转换到特定的范围内(默认为[0,1])。

完整示例:

**from pyspark.ml.feature import MinMaxScaler
scaler = MinMaxScaler(min=0, max=1, inputCol='features', outputCol='features_minmax')
scaler_model = scaler.fit(data_2)
data_3 = scaler_model.transform(data_2)**

主成分分析

主成分分析 (PCA)是在分析变量的相关特征后,将一组观测值从 m 转换到 n(m > n) 的过程。它用于将数据从高维移动到低维,以实现可视化或降维的目的。我不会说太多细节,因为我的目标是教你如何应用它。

应用 PCA 与应用其他估计量没有什么不同:

  1. 创建一个估算器
  2. 把它安装在模型上,得到一个变压器,
  3. 将转换器应用于数据。

为了看看 PCA 有多强大,我们将把它应用于手写图像数据集【从这里下载】。该数据有 785 列。第一列表示定义数字类(0 →9)的标签,其他 784 列表示 28*28 图像的像素值。

我们的大脑很难想象比三维更高的东西。这里我们的数据有 784 个维度!所以在这个表示中,use 不可能理解它。幸运的是,我们可以使用 PCA 将尺寸减少到只有 2!

首先,我们读取数据并将像素收集到特征列中:

**data = spark.read.csv('./datasets/digits.csv', header=True, inferSchema=True)
from pyspark.ml.feature import VectorAssembler
assembler = VectorAssembler(inputCols=data.columns[1:], outputCol='features')
data_2 = assembler.transform(data)**

给定 k = 2 (输出维数),我们创建 PCA 模型:

**from pyspark.ml.feature import PCA
pca = PCA(k=2, inputCol='features', outputCol='features_pca')**

我们训练评估者:

**pca_model = pca.fit(data_2)**

最后,我们将模型应用于数据:

**pca_data = pca_model.transform(data_2).select('features_pca')**

注意 features_pca 列只有两个值。这些值是从 784 → 2 减少的维数。

PCA features with K = 2

现在,请注意,当我们绘制这些值并用每个数字标签标注时会发生什么。

Digits plotted with 2 dimensions

看看我们如何漂亮地只用二维来绘制数字的分布。我们看到相似的数字形成了一个簇,这种洞察力对于后面的处理非常有用。

PCA 使用得当是非常强大的。它可以帮助你可视化数据,或者为其他机器学习算法做准备。

最后的想法

在本文中,我们介绍了特性转换的基础知识。一套帮助将我们的数据转换为更相关或优化的格式以用于机器学习算法的技术。我们讨论了最常见的方法以及如何在 Spark ML 中实现它们。接下来,我们将学习如何将这些技术付诸实践,以及如何在完整的工作流程中组织它们。敬请关注…

如果你喜欢这篇文章,请点击“鼓掌”按钮,我将不胜感激👏所以可能会传染给他人。也可以在 推特脸书上关注我直接发邮件给我 或者在LinkedIn*上找到我。***

线性回归

原文:https://towardsdatascience.com/apache-spark-mllib-tutorial-ec6f1cb336a9?source=collection_archive---------8-----------------------

Apache Spark ML 教程

介绍 Spark ML 以及如何使用它来训练线性回归模型

注意:本文是系列文章的一部分。查看完整系列: 第 1 部分:回归 第 2 部分:特征转化 第 3 部分:分类 ,第 4 部分及以上即将推出。

本系列的目标是帮助您开始使用 Apache Spark 的 ML 库。我们将一起探索如何以一种结构良好的方式解决各种有趣的机器学习用例。最后,您将能够满怀信心地使用 Spark ML,并学会为您未来的项目实现一个有组织且易于维护的工作流

在本系列的第一部分,我们将重点关注 Spark ML 的基础知识。我们将介绍创建回归模型来预测房价的必要步骤。更复杂的 Spark ML 特性和功能将在本系列的后续文章中发布。

在进一步讨论之前,让我们从一些定义开始。

定义

阿帕奇火花

Apache Spark 是一个开源的集群计算框架。Spark 代码库最初是由加州大学伯克利分校的 AMPLab 开发的,后来被捐赠给了 Apache Software Foundation,该基金会一直维护着它。Spark 提供了一个接口,通过隐式数据并行和容错对整个集群进行编程。

火花毫升

Apache Spark ML 是由常用学习算法和实用程序组成的机器学习库,包括分类、回归、聚类、协同过滤、降维以及底层优化原语。

为什么选择 Spark ML?

迈向大数据时代需要对非常大的数据集进行大量迭代计算。机器学习算法的标准实现需要非常强大的机器才能运行。依赖高端机器并不有利,因为它们价格高昂,而且不适合扩大规模。使用分布式计算引擎的想法是将计算分布到多个低端机器(商用硬件),而不是一个高端机器。这无疑加速了学习阶段,并允许我们创建更好的模型。

软件要求

为了继续学习本教程,您必须安装以下软件:

  • 计算机编程语言
  • 阿帕奇火花
  • findspark 库
  • Numpy
  • 朱皮特

阿帕奇火花

安装 Apache Spark 是如此简单。你只要从官网下载包就可以了。

要测试您的实现:

  1. 解压缩文件
  2. 转到 bin 目录
  3. 运行以下命令
% ./pyspark --version

输出应该如下所示:

Testing Apache Spark version

findspark 库

为了更容易到达 Apache Spark,我们将使用 findspark 。这是一个非常简单的库,可以自动设置开发环境来导入 Apache Spark 库。

要安装 findspark,请在 shell 中运行以下命令:

% pip install findspark

Numpy

Numpy 是 Python 中著名的数值计算库。Spark ML 在内部使用它进行计算。

使用以下命令安装它:

% pip install numpy

Jupyter

Jupyter Notebook是一个开源的网络应用程序,允许你创建和共享包含实时代码、公式、可视化和叙述性文本的文档。用途包括:数据清理和转换、数值模拟、统计建模、数据可视化、机器学习等等。

要安装 Jupyter:

% pip install jupyter

问题定义

这个系列的第一个问题是 回归 。我们将训练一个模型来预测著名的 波士顿房屋 数据集(从这里下载)。

该数据集包含由美国人口普查局收集的有关马萨诸塞州波士顿地区住房的信息。它是从 StatLib 档案中获得的,并在整个文献中被广泛用于基准算法。

数据集很小,只有 506 个案例。它包含 14 个特征,描述如下:

  1. CRIM:城镇人均犯罪率
  2. ZN:面积超过 25,000 平方英尺的住宅用地比例
  3. 印度河流域:每个城镇非零售商业英亩数的比例。
  4. CHAS: Charles River 虚拟变量(如果区域边界为河流,则为 1;否则为 0)
  5. NOX:氮氧化物浓度(百万分之一)
  6. RM:每个住宅的平均房间数
  7. 年龄:1940 年以前建造的自有住房的比例
  8. DIS:到五个波士顿就业中心的加权距离
  9. RAD:放射状公路可达性指数
  10. 税收:每 1 万美元的全价值财产税税率
  11. PTRATIO:按城镇分列的师生比率
  12. B: 1000(Bk — 0.63),其中 Bk 是按城镇划分的黑人比例
  13. LSTAT: %人口的较低地位
  14. MEDV:以千美元为单位的自有住房中值

目标是使用这 13 个特征来预测 MEDV 的价值(代表房价)。

是时候把手弄脏了。让我们跳跃到火花和火花中。

履行

设置 Apache Spark

准备好你的开发环境午餐 Jupyter 并创建一个新的笔记本。

% jupyter notebook

我们首先导入 findspark 库,并通过传递 Apache Spark 文件夹的路径来初始化它。

import findspark
findspark.init('/opt/spark')

每个 Spark 应用程序都需要一个 SparkSession

为了创建一个 SparkSession 我们写:

from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()

加载数据

data = spark.read.csv('./boston_housing.csv', header=True, inferSchema=True)
  • header=True 表示第一行包含标题
  • inferSchema=True 启用底层数据模式的自动检测

要显示数据:

data.show()

Top 20 rows of the data

设置功能

现在是有趣的部分… Spark ML 的算法期望数据以两列表示:特征标签。Features 是用于预测的所有特征的数据点数组。标签包含每个数据点的输出标签。

在我们的例子中,特性是从 1 → 13 的列,标签是包含价格的 MEDV 列。

目标是从特征中预测标签。

创建特征数组非常简单。您只需导入vector assembler类,并传入一个特性列名列表。

feature_columns = data.columns[:-1] # here we omit the final columnfrom pyspark.ml.feature import VectorAssemblerassembler = VectorAssembler(inputCols=feature_columns,outputCol="features")
  • outputCol="features "定义组合所有值的输出向量的名称

现在我们使用汇编程序来创建特性列:

data_2 = assembler.transform(data)

就是这样!如果打印 data_2 的值,您会注意到一个名为“features”的新列,它包含所有组合在一个列表中的值:

data_2.show()

Data after VectorAssembler

训练\测试分割

正如在任何机器学习工作流程中一样,我们将数据分为训练集和测试集。这里我们把它分成 70%的训练样本和 30%的测试样本。

train, test = data_2.randomSplit([0.7, 0.3])

训练机器学习算法

我们转到另一个有趣的部分,让我们根据我们的数据训练一个简单的 线性回归 模型。首先,我们导入必要的类。

from pyspark.ml.regression import LinearRegression

接下来我们定义 算法 变量。我们需要指定特性列和标签列的名称。

algo = LinearRegression(featuresCol="features", labelCol="medv")

训练时间…我们调用 fit 方法,开始在训练集上训练我们的模型。

model = algo.fit(train)

瞧啊。您已经使用 Spark ML 训练了您的第一个模型!

评估模型性能

完成培训阶段是不够的。我们必须计算我们的模型有多好。幸好模型对象有一个 求值 的方法:

evaluation_summary = model.evaluate(test)

使用evaluation _ summary对象访问大量指标:

evaluation_summary.meanAbsoluteError
# Output: 3.39
evaluation_summary.rootMeanSquaredError
# Output: 5.16
evaluation_summary.r2
# Output: 0.58

嗯,对于一个简单的模型来说还不错。

预测值

为了预测未标记数据的输出,在传递 DataFrame 时调用model . transform函数。

例如,让我们从测试集中预测值:

predictions = model.transform(test)

预测 是一个数据帧,包含:模型生成的原始列、特征列和预测列。

predictions.select(predictions.columns[13:]).show() # here I am filtering out some columns just for the figure to fit

Predictions

完整代码

Full Code

最后的想法

我知道这是一篇很长的文章,但我希望它值得你花时间。我们介绍了 Apache Spark 及其令人惊叹的 ML 库。我们在一个回归问题上使用了 Spark ML 来预测房价。接下来,我将介绍其他用例的更多特性。敬请关注…

如果你喜欢这篇文章,请点击“鼓掌”按钮,我将不胜感激👏所以可能会传染给他人。也可以在 推特 脸书 上关注我直接发邮件给我 或者在LinkedIn上找我。

分类

原文:https://towardsdatascience.com/apache-spark-mllib-tutorial-part-3-complete-classification-workflow-a1eb430ad069?source=collection_archive---------15-----------------------

Apache Spark ML 教程

构建完整的分类工作流程

注意:本文是系列文章的一部分。查看完整系列: 第 1 部分:回归 第 2 部分:特征转化 第 3 部分:分类 ,第 4 部分及以上即将推出。

Image by pixel2013 from Pixabay

介绍

在这个系列的这一部分中,我们将把我们所学的一切放在一起训练一个分类模型。目标是学习如何从头到尾建立一个完整的分类工作流程。

问题定义

我们要解决的问题是臭名昭著的 泰坦尼克号生存问题 。我们被要求建立一个机器学习模型,该模型获取乘客信息,并预测他/她是否幸存。数据集包含 12 列,描述如下:[从这里下载]

准备开发环境

你现在应该很熟悉这一步了。我们将打开一个新的 Jyputer 笔记本,导入并初始化 findspark ,创建 spark 会话,最后加载数据。

import findspark
findspark.init('/opt/spark')
from pyspark.sql import SparkSession
spark = SparkSession.builder.getOrCreate()
data = spark.read.csv('./datasets/titanic.csv', inferSchema=True, header=True)

让我们看看数据及其统计:

Top 20 rows of the dataset

Statistics

下面是一个关于某人如何通过分析上述表格来选择/更新其特征的示例:

  • 包含一些功能是没有意义的,例如:乘客 ID姓名车票 →我们将删除它们
  • 小屋有很多空值→我们也会删除它
  • 也许登上柱与生存无关→让我们移除它
  • 我们在年龄列中缺少 177 个值→ 年龄很重要,我们需要找到一种方法来处理缺少的值
  • 性别有标称值→需要编码

让我们过滤掉不需要的列:

data = data.select(['Survived', 'Pclass', 'Gender', 'Age', 'SibSp', 'Parch', 'Fare'])

特征转换

我们将逐个处理转换。在以后的文章中,我将讨论如何使用管道来改进这个过程。但是让我们先用无聊的方法来做。

计算年龄缺失值

年龄是重要特征;因为一些缺失的值而丢弃它是不明智的。我们能做的是在现有价值的帮助下填补缺失的价值。这个过程被称为数据插补。有许多可用的策略,但我们将遵循一个简单的策略,用从样本中计算出的平均值来填充缺失值。

使用估算器类,Spark ML 使这项工作变得简单。首先,我们定义估计量,使其适合模型,然后我们对数据应用转换器。

from pyspark.ml.feature import Imputer
imputer = Imputer(strategy='mean', inputCols=['Age'], outputCols=['AgeImputed'])
imputer_model = imputer.fit(data)
data = imputer_model.transform(data)

不再有缺失值!让我们继续下一步…

性别价值观编码

我们了解到机器学习算法无法处理分类特征。所以,我们需要索引性别值:

from pyspark.ml.feature import StringIndexer
gender_indexer = StringIndexer(inputCol='Gender', outputCol='GenderIndexed')
gender_indexer_model = gender_indexer.fit(data)
data = gender_indexer_model.transform(data)

没有更多的分类值…注意,我们不需要对索引值进行一次热编码,它们自然是用 0 和 1 值进行二进制编码的。

创建特征向量

我们之前了解到 Spark ML 期望数据在两列中表示:一个特征向量和一个标签列。我们已经准备好了标签列(幸存,所以让我们准备特征向量

注意,我们添加了年龄估算性别索引,而不是年龄性别

from pyspark.ml.feature import VectorAssembler
assembler = VectorAssembler(inputCols=['Pclass', 'SibSp', 'Parch', 'Fare', 'AgeImputed', 'GenderIndexed'], outputCol='features')
data = assembler.transform(data)

我们准备出发了!机器学习时间到了…

训练模型

对于这个问题,我们将使用一个随机森林分类器。您可以自由选择任何其他您认为合适的分类器。

步骤:

  1. 创建评估者
  2. 指定要素列和标注列的名称
  3. 符合模型
from pyspark.ml.classification import RandomForestClassifier
algo = RandomForestClassifier(featuresCol='features', labelCol='Survived')
model = algo.fit(data)

搞定了。

生成预测

我们调用模型的变换方法来获得我们的预测:

predictions = model.transform(data)

让我们检查一下预测值:

predictions.select(['Survived','prediction', 'probability']).show()

到目前为止一切顺利,但是仔细检查记录并逐一验证这些记录不符合逻辑。我们需要计算一些指标来获得模型的整体性能。评估时间…

模型评估

我们将使用一个binary classification evaluator来评估我们的模型。它需要知道标签列的名称公制名称。这里我们将使用 ROC 曲线 下的 区域。

from pyspark.ml.evaluation import BinaryClassificationEvaluator
evaluator = BinaryClassificationEvaluator(labelCol='Survived', metricName='areaUnderROC')

调用 evaluate 方法获得结果:

evaluator.evaluate(predictions)

通过使用上述设置,我的评估器返回: 0.90

鉴于我们没有配置预处理程序,最初的结果是有希望的。我知道我没有根据测试数据进行评估,但我相信你能做到。

使用 SciKit-Learn 进行模型评估

如果您想生成其他评估,如混淆矩阵或分类报告,您总是可以使用 scikit-learn 库。

你只需要从你的数据帧中提取 y_truey_pred 。别担心,我会告诉你怎么做:

y_true = predictions.select(['Survived']).collect()
y_pred = predictions.select(['prediction']).collect()

导入您的指标:

from sklearn.metrics import classification_report, confusion_matrix

通过传递 y_truey_pred 调用函数:

print(classification_report(y_true, y_pred))

print(confusion_matrix(y_true, y_pred))

最后的想法

恭喜你。您已经成功完成了另一个教程。你现在应该对自己的 Spark ML 技能更有信心了。在未来的教程中,我们将通过使用 管道 来改进预处理阶段,我将向您展示更多令人兴奋的 Spark ML 特性。敬请关注…

如果你喜欢这篇文章,请点击“鼓掌”按钮,我将不胜感激👏所以可能会传染给他人。也可以在 推特 脸书 上关注我直接发邮件给我 或者在LinkedIn上找我。

REST API 的授权方案

原文:https://towardsdatascience.com/api-authentication-schemes-dc3f73753b29?source=collection_archive---------8-----------------------

Image by Gerd Altmann from Pixabay

策略、密钥管理、安全性和 OAuth

用户数据是驱动 API 经济的基础货币。像任何货币一样,你需要小心处理,小心运输,以防被盗。

不同的设备和平台有不同的漏洞。你家里的桌面不像手机那么不堪一击。手机更容易丢。有人可以访问你手机上应用程序存储的本地文件。这改变了移动应用的认证和授权流程。

类似地,对于单页 web 应用程序(SPA ),整个 Javascript 可以被视为一个源代码。您不希望您的凭据成为 SPA 中本地数据存储的一部分。

有许多安全模型。根据设备和用途,有多种身份验证方式。不同的认证方式被称为方案。

没有一种方法可以保证您的 API 适用于所有情况。但是,你可以学习这些方案,研究最大的社交网络是如何处理的,并找出行业标准;然后以你认为合适的方式应用到你的项目中。

REST API 认证的 4 个主要方案是

  1. 基本认证
  2. 基于令牌的认证
  3. 基于 API 密钥的认证
  4. 开放授权

您可能已经注意到 OAuth 说的是授权而不是认证。这两个术语不能互换。我们将在本文的后面讨论这些区别。

在这篇文章的结尾,你会对不同的方案有一个清晰的理解。

在我们开始讨论这些方案之前,让我们先来讨论一些建立在讨论基础上的基本概念。

秘密和钥匙

认证是用秘密打开事物的艺术。每个认证的核心是一个共享的秘密!

您的 ATM 卡密码是您和银行之间的共享秘密。

你银行保险箱的密码是另一个共享的秘密。

您登录电子邮件的密码是您和电子邮件提供商之间共享的秘密。

这个秘密可以给你,就像进入夜总会的密码,或者你可以生成这个秘密,并像你的银行卡的 pin 码一样存储在系统中。

不管怎样,这个秘密有两份。一份在系统,一份在你。你的副本被称为私有密钥。

你能控制系统里的拷贝吗?不,但是存储在他们服务器上的拷贝不能被另一个人或另一台机器读取。服务器只有您的机密的高度加密版本;它不知道解密后的值是什么样的。服务器可能需要几千年才能解密。

这就是为什么如果你忘记了密码,你需要重新设置。你可以在这里找到破解密码需要多长时间。

公钥和私钥

你的前门锁是公开的。任何人都可以来到你的前门,用他们的钥匙试你的锁,但只有你的钥匙能打开它。你的钥匙是私人的,而你家的锁是公开的。

在数字世界里,钥匙叫钥匙,锁也叫钥匙。所以有两把钥匙。一个是你的秘密副本——你的私钥,另一个是任何人都可以访问的公钥。这是公钥/私钥对。

例如,任何人都可以去 hotmail.com,输入你的电子邮件地址,但除非他们有你的密码(你的私人密钥),否则他们无法登录。

有不同的方法来管理您最终拥有的所有私钥,也有不同的方法来存储它们,使它们不容易被破坏。

找出窃取您的私钥的方法是黑客工作描述的一部分,找出安全管理、存储和传输密钥的方法是 API 工作的一部分;直接或通过第三方 API 管理服务。

因素

因素通过你是谁、你知道什么、你拥有什么来认证你。

除了用户名和密码之外,认证还可以包括称为因素的附加信息。

  1. 单因素—这是我们讨论过的用户名和密码。这是“你是谁”类型的认证。
  2. 两个因素——除了用户名和密码,您还需要回答另一个在注册时设置的机密问题。所以你有两把秘密钥匙。一个是你是谁,另一个是你知道什么。
  3. 多因素身份认证(MFA) —这是最难破解的。您使用您的密钥,并为服务器设置一个秘密位置,以便向您发送另一个密钥。当您使用第一个密钥时,服务器会将另一个密钥发送到您在注册过程中共同约定的秘密位置(通常人们会将此设置为他们的电话号码或电子邮件地址)。这个第二密钥通常只在几分钟内有效。在这段时间内,您需要使用第二个密钥登录。这将决定你是谁,你有什么(手机)类型的认证。
  4. 生物认证——这是指纹 ID,它正成为手机认证的常见部分。我写这篇文章的戴尔笔记本电脑有生物识别登录功能。我必须把食指放在电源按钮上才能登录。这是一个自动的“你是谁”类型的认证,你不需要手动输入用户名和密码。
  5. 验证码——有两种。一个你必须破译你看到的弯弯曲曲的单词并输入的地方。另一个是你必须在图片网格中识别山脉、汽车、店面或任何数量的事物。这些是最讨厌的,希望它们快点消失。有时候歪歪扭扭的字太让人费解,我不得不要第二套,然后打开音响听。

认证和认证

认证授权是两回事。

身份验证让您登录到服务器。授权使您能够访问服务器上的资源。

,是资源拥有者。你把你的资源交给服务器存储。像你的个人资料、爱好、你的购买、你的欲望、想要和需要(亚马逊上的愿望清单)、你的位置数据、你的关系状态、你的周年纪念日、你配偶的详细资料、你的孩子、孙子的名字、他们的照片、生日……以及你给例如脸书的更多生活数据!

需要访问该数据的其他应用程序将需要您的许可。

认证发生在授权之前。仅仅因为你已经登录并不意味着你可以访问一切。

认证是通过用户名、密码和其他我们讨论过的因素来协商的。授权是基于帐户上的策略协商的,例如管理员用户、超级用户、访客……等。

认证方案

在 REST API 中,发送一次凭证并登录是不够的。正如我们在本文中所讨论的,REST 是无状态的。因为是无状态的,REST API 不能记住你的凭证。所以你每次跟它说话都要告诉它你是谁!

记住这一点,让我们按照复杂程度的顺序深入研究这些方案。

1.基本认证

这是保护 API 的最简单的方法。每次发送请求时,让用户输入用户名和密码来标识自己。

在标准 HTTP 规范中,有一个授权头字段可用于此目的。用户名和密码使用 Base 64 编码进行编码。任何人在数据传输到服务器的过程中截取数据,都会看到一长串的胡言乱语。不过,Base 64 编码可以在不到一秒的时间内轻松解码。

黑客如何破解你的密码

拦截器可以复制这些胡言乱语,并将其粘贴到一个在线解码器中,以取回你的用户名和密码。这被称为中间人(MiTM)攻击。他们可能正坐在一家咖啡店里,用咖啡店的名字设置了 wifi。你可能没有注意到不同,而是和他们联系起来。现在你所有的数据都在他们的笔记本上流动。

这就是为什么基本认证是很好的…基本的。

对于移动应用程序和单页应用程序,基本身份验证不是一个好的方案,因为您不想将用户名和密码存储在设备上或 SPA 的 Javascript 代码中。

对于移动和 SPA,您可以改用基于令牌的身份验证。

2.基于令牌的认证

在这个方案中,用户将输入他们的用户名和密码(凭证),服务器将根据这些凭证生成一个令牌。

然后,服务器将这个令牌发送给用户。

现在,用户不需要在每次请求时都发送登录凭证。相反,他们只是发送编码的令牌,服务器验证令牌。

有多种方法可以将日期和时间编码到该令牌中,这样拦截该令牌的人就无法在特定时间后再次使用它。

当用户调用端点来访问资源时,需要通过头、体或作为查询参数传递该令牌。

最流行的令牌格式是 JSON Web 令牌(JWT)。令牌的字段是键/值对。这些密钥被称为声明。这些声明本质上是告诉 API 这些值应该是什么意思。您可以在 RFC 7519 中找到所有标准声明的列表

这是 JWT 声明集的一个例子。 aud 字段是受众声明,它告诉服务器它包含客户端 ID。如果缺少这个,那么这个令牌将被拒绝。

{   
"iss": "http://www.mysite.com",   
"aud": "Client Secret",   
"name": "first last",   
"email": "firstlast@mysite.com",   
}

JWT 令牌基于 OpenID 连接协议(OIDC)进行协商。

令牌可以设置为在一定时间后过期,因此用户需要再次登录。如果存在任何危害,也可以在服务器端撤销令牌。

3.API 密钥和客户端机密

在这个方案中,需要访问资源的客户机需要向 API 注册自己。API 为每个注册的客户端生成一个密钥和一个秘密。然后,这些文件被存储在服务器中,并将它们的副本发送给客户端。当客户端尝试连接时,需要将这些内容传入。

例如,如果你需要一个开发者来编写你的应用程序的一部分,那么你可以生成这个密钥和秘密,并把它交给他们。如果你需要向许多开发者分发密钥,你需要手动设置。问题是这很难扩展。

API 密钥和客户端机密的另一个问题是密钥管理。你需要为他们提供一种方法—

a. 生成密钥和秘密

b. 发送给他们——这可以通过电子邮件或在 API 的开发人员帐户中显示

c. 保护密钥和秘密

存储和管理密钥可能会变得复杂。这就是为什么一些组织更愿意雇佣第三方服务来完成这项工作。IBM、微软和其他供应商(如 Akana、Apigee 等)提供了许多 API 管理工具。这里的是十大 API 管理工具的列表。

如果您想自己完成,而不是雇佣第三方服务,那么您会希望自动生成和交换密钥,这样您就可以扩展。对这种自动化的需求是开发 OAuth 这样的授权框架的主要原因之一。

4.OAuth 2.0(开放式授权)

OAuth 自动生成和交换密钥。当应用程序需要您的许可/授权来代表您访问数据时,它会要求您登录到 API 提供程序。

让我们看一个真实的例子。如果您希望 Joe 能够访问您的个人银行帐户以提取资金,下面是在这种情况下如何“OAuth”Joe。

  1. 你去银行,出示你的身份证—( 验证你自己)
  2. 告诉他们您希望 Joe 能够访问您的帐户— ( 授权 Joe )
  3. 给银行 Joe 的电子邮件地址,这样银行可以给 Joe 发送一个访问令牌—( API Provider 调用一个网站重定向 URI,在响应体中使用访问令牌)
  4. Joe 带着访问令牌和他的 ID 来到银行— ( 客户验证自己并出示访问令牌)
  5. 银行授权 Joe 访问您的帐户— ( API 提供者授权客户访问您的资源)

摘要

在本文中,您了解了一些不同的身份验证因素,如单因素、双因素和多因素身份验证。

我们讨论了身份验证和授权之间的区别,所以现在您知道了,即使这些术语被随意使用,有时它们还是有很大的不同。

我们讨论了不同的认证方案,比如基本认证、令牌、jwt、API 密钥和 OAuth2.0

至此,您应该对保护 API 的方法有了一个很好的概述。如果你想深入了解我们在这里提到的主题,这里有一些参考资料—

RFC 6749-OAuth 2.0 授权框架

RFC 2617-HTTP 认证:基本和摘要访问认证

RFC7235 -超文本传输协议(HTTP/1.1):认证

RFC 7519-JSON Web Token(JWT)

苹果将语音转文本功能提升至 Xcode 11

原文:https://towardsdatascience.com/apple-cranks-speech-to-text-up-to-xcode-11-e1848e42252b?source=collection_archive---------30-----------------------

SFSpeechRecognizer 的新好东西及其 ML 驱动的未来

毫无疑问,语音识别对许多用户来说是一个强大的工具。用户的应用范围从可访问性需求、语言帮助、记录保存,或者仅仅是偏好。在我们目前生活的虚拟助手时代,语音到文本是这一切的支柱,转录语音命令以供理解和执行。仅仅是这个市场所需的进步,就已经推动开发人员围绕口音、词汇和不同层次的语法改进技术。

难怪我们最终会看到技术进步的速度越来越快。

今年的 WWDC 2019 是苹果最新版本SFSpeechRecognizer的更大飞跃,同样的 API 支持 Siri 转录。在 WWDC 2016 大会上推出(在同一活动中,苹果强调了应用 s 中丰富的辅助功能),它为开发者提供了第一方工具,能够转录录制的现场音频。由于当时苹果已经依赖这项技术 5 年了,它在社区中受到了热烈的欢迎。

脱离电网

今年最受欢迎的新特性是新的离线模式。你不会真正意识到语音转文本使用数据来转录,直到你在死区中使用它。原因是因为这些年一直依赖云马力。然而,现在苹果公司有足够的信心在一个适合你口袋的设备上完成这项工作。

在这里,每个人都有多种好处。最明显的是,它节省了用户的移动数据和时间,因为它不需要等待发送和响应。这也是一个很好的隐私功能,因为你的演讲(和转录)留在手机上,而不是通过网络或某个地方的服务器。

对于开发者来说,它解除了对SFSpeechRecognizer的最大限制之一。局限性在于,它一次只能转录 1 分钟的音频,而且每天的点击次数有限。之所以把它放在首位,是因为 API 的初衷是转录简短的 Siri 命令。此外,虽然苹果公司承担了在其云上免费运行服务的费用,但这种权衡是有限度的,这样它就不会负担过重。

最后一点给苹果带来了新的好处。这一更新可能会释放大量资源,只需在本地转录 Siri 命令即可。Siri 很可能是 API 的最大消费者,因此将这样一个核心功能从云端转移到用户设备上是苹果在技术、物流和财务上的一大胜利。

成长空间

还是有一些弊端的。最主要的一点是准确性受限于手机已经加载的任何知识(可能会随着每个操作系统版本而更新?).虽然苹果声称它仍然很好,但服务器准确性不断提高新的边缘案例,因为它有能力不断学习和再培训。另一个缺点是对离线可用语言数量的限制,尽管这可以在后续版本中很容易地弥补。

Screenshot taken from WWDC 2019

拾起苹果的音调

苹果还推出了SFVoiceAnalytics,它提供了转录的 4 个关键数据点(详见下面摘自苹果开发者文档的截图)。音频程序员可能会喜欢与分析一起工作,我已经可以看到新一代的自动调谐功能。

Screenshot taken from Apple Developer Docs

但我这一部分的标题实际上是一个双关语,因为苹果公司对这些分析有计划,他们希望开发者注意到这一点。

从说话中学习

WWDC 2019 上的另一项重大宣布是对苹果机器学习工具包 Core ML 和 Create ML 的最新改进。具体来说,他们引入了使用MLSoundClassifier创建声音分类模型的新功能。这种新的分类和新的语音分析是专门针对彼此的,为 ML 支持的语音识别开辟了许多潜在的机会(想想检测某人的情绪,方言,甚至可能是真实性)。

很明显,苹果认为未来是机器学习,并正在大力投资于此(见我关于 iPhone 的机器学习曲线的文章),语音无疑是最大的受益者之一。最近几年引入的机器学习引擎正是体面的离线/设备上语音识别现在甚至成为可能的原因。

苹果在这方面才刚刚起步。

[## iPhone 的进化并没有受阻,它正处于(机器)学习曲线上

苹果在 ML 上的进步正在改变 iOS 的一切

towardsdatascience.com](/iphone-evolution-hasnt-stunted-it-s-on-a-machine-learning-curve-b29237c0adbe)

有很多要说的

虽然改进的数量很少,但质量却非常丰富。苹果生态系统可能的演讲机会已经打开了不少(特别是因为SFSpeechRecognizer现在也可以在 macOS 上使用)。它推进了苹果在可访问性方面的使命,同时也改善了 Siri,这是他们在虚拟助理领域的斗士。随着我们看到当前和新的应用程序采用这些进步并利用它们开发新的创新,应用程序场景也将开始改变。

ML 和 AI 不是下一个大东西,它们已经在这里了。然而,随着 ML 驱动的能力和特征在用户口袋中变得越来越可用,应用变得更加多样化。拥有丰富的移动语音识别功能还为时尚早,但我们应该期待在不久的将来会有很大的发展。

苹果,领英,网飞的大数据声明

原文:https://towardsdatascience.com/apple-linkedin-netflixs-big-data-statement-fe937b7e96db?source=collection_archive---------25-----------------------

大数据证明其价值

介绍

我们生活在一个数字世界中,公司通过多个来源(如社交媒体、交易、客户反馈、医疗保健、教育机构)以评论、赞、视频、音频、文件、XML、二进制文件等形式收集大量数据,这些数据超过了 Pb 和 EB 的大小。

这些关于大数据的数字将让您深入了解我们今天所处的数据量。

  • 每秒在谷歌上进行 63,000 次网络搜索。
  • 脸书的 20 亿活跃用户每天产生 500 的数据。
  • Twitter 上每天产生 12tb 的数据。
  • Snapchat 用户分享 527,760 张照片/分钟。
  • 每分钟有超过 120 名专业人士加入 LinkedIn。
  • 用户每分钟观看 414.66 万个 YouTube 视频。
  • Instagram 用户每分钟发布 46740 张照片。

征服你的数据科学梦想

顶级公司的大数据努力

苹果

苹果是大数据世界的后来者,但苹果凭借 iWatch 的进入将可穿戴设备带入了主流。有了 iWatch,苹果通过其灵敏的传感器收集用户的所有数据。

收集的数据是关于其产品——iphone、Macbooks、iPads 和 iWatches 的使用方式、时间和地点。根据这些信息,他们决定应该添加哪些新功能,以及如何调整它们的操作方式,以提供最舒适、最合理的用户体验。

苹果的 Siri 收集所有用户的语音数据,并试图分析这些数据,将用户与他们正在寻找的信息联系起来。这些数据用于通过改善用户的语音识别模式来为用户提供信息。

凭借其 iWatch,苹果与 IBM 联手促进健康相关移动应用的开发。苹果公司希望用这个来监测所有顾客的健康状况,改善他们的生活方式,到目前为止已经挽救了许多人的生命。

iTunes 是苹果利用大数据分析来分析客户的音乐品味并据此向他们提供建议的又一个例子。

是时候选择大数据了

商务化人际关系网

LinkedIn 拥有超过 5.75 亿的用户群,由此,你可以想象它定期处理的数据量。

凭借大数据,LinkedIn 开发了许多产品或服务,帮助用户在需要的时候联系和找到更多有用的人和工作。

LinkedIn 使用的一些服务有:

  • 你可能认识的人
    LinkedIn 收集用户数据,如登录详情、电子邮件、申请的工作、查看的个人资料、浏览器设置等。运行分析数据的作业,并向用户提供关于他们可能想要联系的人的建议。 LinkedIn 有 5 个连续运行的测试算法,为“你可能认识的人”功能生成 700 GB 的输出数据。
  • 这是 LinkedIn 最有帮助的功能,对于许多招聘人员来说,这是提取他们可以雇佣的最合适的资源的关键。用户可以为其网络中的另一个用户背书某项技能,该技能在用户的个人资料中显示为“技能&背书”
  • 你可能感兴趣的工作 90%的财富 100 强公司使用 LinkedIn 招聘顶尖人才,89%的专业人士使用 LinkedIn 寻找工作。该网站约 50%的参与度来自这一功能,大数据是其支柱。

使用大数据和机器学习,LinkedIn 根据用户的个人资料设置和搜索历史向用户显示工作建议。

让你的下一次数据科学机会盘点

网飞

在大数据和分析的帮助下,网飞已经成为在线流媒体之王。网飞有超过 1 亿的用户,他们使用来自这些用户的数据为他们的用户提供推荐,这些推荐影响了网飞 80%的观看内容。网飞会员在选择观看内容的 60 到 90 秒后失去兴趣,已经查看了 10 到 20 个标题,这是大数据分析最大限度利用的时间。每个主页通常有大约 40 行,每行最多 75 个视频。

网飞从收视率、搜索、观看电影/节目的日期、在哪个设备上观看、节目何时暂停、演职员表是否被跳过等方面收集所有数据。

网飞在《纸牌屋》上花费了 1 亿美元,这对它来说是一个福音,因为他们能够通过使用大数据分析吸引许多订户。

网飞试图为观众寻找下一部热门剧集。以个性化的方式为每个会员档案订购整个网飞系列。每个成员的同一流派行有完全不同的视频选择。

然后,网飞从整个目录中挑选出最个性化的推荐,只关注排名靠前的标题。

Sort 的客户最近观看了一些标题,并估计客户是否会继续观看或再次观看,或者他们是否会因为某些内容没有他们想象的有趣而停止观看。

网飞推荐相似的视频,只是因为你看了一个视频,你可能也喜欢相似的视频。即使相似性排名不是个性化的,它也可以根据成员先前观看的内容,很好地估计他们可能喜欢的内容。

尾注

像苹果、LinkedIn 和网飞这样的大公司在各自的领域都是无可争议的王者,现在它们必然会将大数据分析引入自己的组织,这本身就充分说明了大数据在全球范围内获得的地位。我不知道还有什么能比这更好地定义大数据的重要性。

那么,你还在等什么?

用大数据让你的职业身量变大

使用 FB 的 Prophet 预测苹果股票和比特币价格——使用 Python

原文:https://towardsdatascience.com/apple-stock-and-bitcoin-price-predictions-using-fbs-prophet-for-beginners-python-96d5ec404b77?source=collection_archive---------6-----------------------

初学者指南—逐步分析

时间序列分析

这篇文章是关于使用脸书先知预测苹果股票和比特币价格使用 python API。

  1. 先知是什么?
  2. 苹果股价预测
  3. 比特币价格预测
  4. 使用 Matplotlib 和 Seaborn 的基本数据可视化。

关于先知:

P 是一个开源包(Python 和 R 都适用),用于基于加法模型预测时间序列数据,其中非线性趋势符合每年、每周和每天的季节性,加上假日效应。它最适用于具有强烈季节效应的时间序列和几个季节的历史数据。Prophet 对缺失数据和趋势变化非常稳健,通常能够很好地处理异常值。Prophet 是由脸书核心数据科学团队发布的开源软件。它可以在 CRAN 和 PyPI 上下载。

使用 Prophet 的优势

*准确快速

*全自动

*可调预测。

*提供 R 或 Python 版本

F 预测是一项常见的数据科学任务,可帮助组织进行容量规划、目标设定和异常检测。尽管它很重要,但在生成可靠和高质量的预测方面存在严重的挑战,尤其是当存在各种时间序列并且具有时间序列建模专业知识的分析师相对较少时。为了应对这些挑战,我们描述了一种实用的“大规模”预测方法,该方法将可配置模型与分析师在回路中的性能分析相结合。我们提出了一个模块化的回归模型,其可解释的参数可以由具有时间序列领域知识的分析师直观地调整。我们描述了性能分析,以比较和评估预测程序,并自动标记预测以进行人工审查和调整。帮助分析师最有效地利用他们的专业知识的工具可以实现对业务时间序列的可靠、实用的预测。

资料来源:泰勒 SJ,Letham B. 2017 年。大规模预测。 PeerJ 预印本5:e 3190 v2 https://doi . org/10.7287/PeerJ . Preprints . 3190 v2

[## 大规模预测

预测是一项常见的数据科学任务,可帮助组织进行容量规划、目标设定和异常情况预测…

peerj.com](https://peerj.com/preprints/3190/)

Prophet 针对我们在脸书遇到的业务预测任务进行了优化,这些任务通常具有以下特征:

  • 至少有几个月(最好是一年)历史的每小时、每天或每周观察
  • 强烈的多重“人类尺度”季节性:星期几和一年中的时间
  • 提前知道的不定期发生的重要节日(如超级碗)
  • 合理数量的缺失观测值或较大的异常值
  • 历史趋势变化,例如由于产品发布或记录变化
  • 趋势是非线性增长曲线,趋势达到自然极限或饱和

Prophet 程序是一个加法回归模型,有四个主要组成部分:

呈分段线性或逻辑斯蒂增长曲线趋势。Prophet 通过从数据中选择变化点来自动检测趋势的变化。

使用傅立叶级数建模的年度季节性分量。

使用虚拟变量的每周季节性组件。

用户提供的重要节假日列表。

[## 预言家:大规模预测

预测是一项数据科学任务,是组织内许多活动的核心。例如,大…

research.fb.com](https://research.fb.com/blog/2017/02/prophet-forecasting-at-scale/)

先知安装

  • 首先,安装 Pystan
  • 然后安装 Fbprophet

1.安装 Pystan

[## 详细的安装说明- PyStan 2.19.0.0 文档

这是因为 PyStan(和许多 python 工具)需要具有 C 依赖关系的包(即模块)。这些类型的…

pystan.readthedocs.io](https://pystan.readthedocs.io/en/latest/installation_beginner.html)

2.安装 fbprophet

我在 windows 中安装时遇到了问题。请按照文档说明正确安装 pystan,然后安装 fbprophet。

[## Windows 上的 PyStan-PyStan 2 . 19 . 0 . 0 文档

PyStan 在 Windows 下得到部分支持,但有以下警告:Python 2.7:不支持并行采样…

pystan.readthedocs.io](https://pystan.readthedocs.io/en/latest/windows.html)

实现先知

我正在使用

  • Python 3.6
  • Jupyter 笔记本
  • 熊猫
  • 马特普利卜
  • 海生的
  • Plotly

步骤:

  1. 安装所有需要的软件包,包括 prophet 和 alphavantage。
  2. 从 Alphavantage 获取 API 密钥。
  3. 使用 API 获取苹果股票= AAPL 数据。
  4. 使用 API 获取比特硬币= BTC 数据。
  5. 如果需要,将其保存为 CSV 文件。
  6. 数据在熊猫数据框中提供。
  7. 确保将数据框转换为 prophet 要求的格式-ds 和 y 两列。
  8. ds 是日期,它应该是日期时间数据类型。
  9. y 是收盘价,应该是浮点数。
  10. 选择预测周期,如您希望进行预测的时间范围,如 3 个月或 1 年等。
  11. 符合模型。
  12. 预测模型的预测期,如 3 个月或 1 年等。
  13. 预测模型—为您提供预测收盘价、收盘价的上限和下限。
  14. 调用先知绘图方法并进行一些绘图。

苹果股价预测

  1. 首先导入所有的库

2.获取苹果股票价格

我们可以使用免费的 API

alpha vantage API

Quandl API

熊猫 _datareader

我使用的是 Alphavantage API

获取 API 密钥

Alphavantage 文档

[## Alpha Vantage API 文档

Alpha Vantage 的 API 文档。Alpha Vantage 为实时和历史股票和权益提供免费的 JSON APIs

www.alphavantage.co](https://www.alphavantage.co/documentation/)

您可以将数据输出到

  • CSV
  • Json
  • 熊猫数据框

此外,您可以指定输出大小

  • 压缩 —返回最近 100 天
  • 完整 —返回最近 20 年的数据

数据框如下所示

3.把它写到一个文件里,以防你将来需要它。

4.做一些基本的绘图

收盘价柱状图

技术分析:

SMA:简单移动平均线

简单移动平均线(SMA)是一种算术移动平均线,其计算方法是将最近的收盘价相加,然后除以计算平均值中的时间段数。

相对强度指数

J. Welles Wilder 开发的相对强弱指数(RSI)是一种动量振荡器,用于衡量价格运动的速度和变化。RSI 在 0 到 100 之间震荡。传统上,RSI 在 70 以上被认为超买,在 30 以下被认为超卖。信号可以通过寻找分歧和失败摆动来产生。RSI 也可以用来识别大趋势。

5.现在将数据帧转换成 fbprophet 期望的格式。Prophet 的输入总是一个包含两列的 data frame:dsyds(日期戳)列应该是熊猫所期望的格式,理想情况下,日期应该是 YYYY-MM-DD,时间戳应该是 YYYY-MM-DD HH:MM:SS。y栏必须是数字,代表我们希望预测的测量值。

6.先知遵循sklearn模型 API。我们创建了一个Prophet类的实例,然后调用它的fitpredict方法。我们通过实例化一个新的Prophet对象来适应这个模型。预测过程的任何设置都被传递到构造函数中。然后调用它的fit方法并传入历史数据帧。安装需要 1-5 秒钟。

7.未来一年的预测。然后在数据帧上进行预测,数据帧中有一列ds包含要进行预测的日期。您可以使用 helper 方法Prophet.make_future_dataframe获得一个合适的数据帧,该数据帧延伸到未来指定的天数。默认情况下,它还将包括历史中的日期,因此我们将看到模型也是合适的。

预测 df 将包含未来一年的日期。最后 10 条记录如下所示

8.predict方法将为future中的每一行分配一个预测值,并将其命名为yhat。如果您传入历史日期,它将提供样本内拟合。这里的forecast对象是一个新的 dataframe,它包括一个包含预测的列yhat,以及组件和不确定性区间的列。

9.您可以通过调用Prophet.plot方法并传入您的预测数据帧来绘制预测。

10.如果您想查看预测组件,您可以使用Prophet.plot_components方法。默认情况下,您将看到时间序列的趋势、年季节性和周季节性。如果你包括假期,你也会在这里看到。

11.可以用 plotly 创建预测的交互式图形。您需要单独安装 plotly,因为默认情况下它不会与 fbprophet 一起安装。

12.创建比特币数据集

记录数量

13.一些基本的数据可视化

14.现在拟合模型,做预测。代码是

剧情是

理解情节:

首先标出日期和价格

情节看起来像

预测图看起来像

绘图功能是

有个博客在剧情上解释的很清楚。链接在下面

[## 先知情节解释

第一次看 Prophet 生成的一个剧情的时候,我很失落。我开始在…中寻找解释

www.mikulskibartosz.name](https://www.mikulskibartosz.name/prophet-plot-explained/)

验证

使用cross_validation功能,可以对一系列历史临界值自动进行交叉验证程序。我们指定预测范围(horizon),然后可选地指定初始训练期的大小(initial)和截止日期之间的间隔(period)。默认情况下,初始训练周期设置为三倍范围,每半个范围进行一次截止。

在每个模拟预测日期和每个截止日期,cross_validation的输出是具有真实值y和样本外预测值yhat的数据帧。特别是对cutoffcutoff + horizon之间的每个观测点进行预测。然后,该数据帧可用于计算yhaty的误差度量。

在这里,我们进行交叉验证以评估 365 天范围内的预测性能,从第一个截止日期的 730 天训练数据开始,然后每隔 180 天进行预测。在这 8 年的时间序列中,这相当于 11 次总预测。

df 看起来像

您可以看到实际值 y 和预测值 yhat。

绩效指标

performance_metrics实用程序可用于计算预测性能的一些有用的统计数据(yhatyhat_loweryhat_uppery的比较),作为离截止点的距离的函数(预测距离未来有多远)。计算的统计数据包括均方误差(MSE)、均方根误差(RMSE)、平均绝对误差(MAE)、平均绝对百分比误差(MAPE)以及yhat_loweryhat_upper估计值的覆盖范围。

  • RMSE(均方根误差)
  • 平均绝对误差
  • MAPE(平均绝对百分比误差)

结论:

这篇文章的主要目的是安装 prophet,提取历史股票价格数据和加密货币数据,做一些基本的可视化和使用 prophet 做预测。请参考 fbprophet 文档

[## 快速启动

Prophet 遵循 sklearn 模型 API。我们创建一个 Prophet 类的实例,然后调用它的 fit 和 predict…

facebook.github.io](https://facebook.github.io/prophet/docs/quick_start.html#python-api)

你可以通过改变参数来玩它

  • 假期建模
  • 使用自定义季节性
  • 使用逻辑增长趋势模型等

参考资料:

[1] Sean J. Taylor 和 Benjamin Letham 按比例预测,脸书,美国加利福尼亚州门洛帕克

链接:

[## 先知

Prophet 是一个用 R 和 Python 实现的预测程序。它速度很快,并提供完全自动化的预测…

facebook.github.io](https://facebook.github.io/prophet/)

深度学习在道路裂缝识别中的应用

原文:https://towardsdatascience.com/application-of-deep-learning-in-identifying-road-cracks-8153e50ce9e2?source=collection_archive---------23-----------------------

最近,作为我研究的一部分,我有机会使用一个非常酷的道路裂缝检测数据集。一家公司(姑且称之为道路裂缝和其他重要事物部,简称 MRCOIS)😑)正在寻求一种自主系统来定位道路裂缝,并根据 3 种裂缝严重程度(低、中、高)对其进行分类。他们非常慷慨地向我们提供了安大略省四条主要公路上的裂缝路面。数据集是使用由 Furgo Inc 设计的 ARAN 9000 (自动道路分析仪 9000)道路勘测系统收集的。 ARAN 9000 是一种基于激光雷达和相机的集成系统,通常用于执行道路勘测。

Illustration of data collection from the ARAN 9000 system. The system uses an integrated LiDAR and camera based sensor to detect road cracks.

数据集被分成 3 个不同严重程度的裂缝(低、中、高)。相机和激光雷达数据共同用于检测道路裂缝。然后根据裂缝的宽度和深度确定裂缝的严重程度(深而宽的裂缝被确定为严重或高严重程度,而浅而窄的裂缝为低-中等严重程度)

Instances of road cracks (Top Image: LiDAR range image, Bottom Image: Detected instances of road cracks) (Red: Hight severity, Green: Medium severity, Blue: Low severity)

MRCOIS 目前使用的系统是基于裂缝定位阈值技术的组合,然后是基于裂缝平均宽度和深度的多标签分类,以识别裂缝的严重程度。阈值方法对噪声非常敏感,因此道路标记经常被错误地提取为图像中的道路裂缝。阈值技术也已知产生不完整的边缘,因此该方法使用边缘连通性来连接不连续的边缘。这种方法经常导致在没有任何裂缝的区域产生假边缘。

为了解决这些问题,我和我的朋友使用了两种流行的深度学习架构(改进的 CNN 和 FCN)来检测和分类道路裂缝。我总共获得了大约 3000 张照片。由于数据集非常小,我广泛使用数据扩充技术将数据集的大小增加到大约 220,000 张图像。大量的数据是通过将原始图像裁剪成较小的小块而生成的,相邻小块之间有 75%的重叠。因为不是每个小块都包含裂纹像素,所以使用进一步的过滤来去除包含少于 0.5%裂纹像素的图像。然后,为了训练和验证的目的,将补丁分成 9:1。

方法 1:具有结构化预测的卷积神经网络

第一种方法基于具有结构化预测的卷积神经网络(CNN)。提出该方法的原始论文进行了二元分类定位裂纹像素(即裂纹或非裂纹)。在我的论文中,改进了架构以检测不同级别的裂缝严重性。利用更深的网络来学习更复杂的特征,并输出对应于不同裂纹严重程度的多个类。该架构如下图所示。

CNN with structured prediction modified to detect multiple instances of crack severity

方法 2:全卷积神经网络

本研究中使用的第二种方法是基于 VGG-16 的 FCN-8(全文)。FC 网络的结构基于编码器-解码器架构,其中网络的最初 7 层是典型 CNN 的层,后续层用于通过解卷积对结果进行上采样来生成分割图。

在这项研究中,我们使用了 FCN-8 结构。该网络包含 7 个回旋和 5 个汇集层。由于我们使用 FCN-8 架构,我们有 3 个反卷积层,跳过了第 3 层和第 4 层的连接。

Fully Convolutional Network for road crack severity detection

结果和验证

该网络在 GTX-1070 GPU 和 16 GB 内存上进行训练。对结果进行定位和严重程度分类评估。

Top row: Original Image, 2nd row: Binary ground truth, 3rd row: Binarized results from FCN, 4th row: Original CNN with structured prediction, 5th row: Morphological detection, 6th row: Ground truth with crack severity, 7th row: Severity detection from FCN, 8th row: Severity detection from improved CNN with structured prediction

计算裂缝定位(即二元分类)和严重性分类结果的精确度、召回率和 F1 分数。验证数据集的准确性指标如下表所示。

Accuracy metrics for binary crack classification

Accuracy metrics for crack severity classification

尽管结果表明了准确的检测结果,但是仍然存在导致错误分割的问题。在训练网络时,我面临的一个关键问题是训练数据集的质量很差。地面真实数据集包含道路标记和虚假边。因此,整体裂纹定位精度较差,进而导致裂纹严重程度分类精度较低。训练数据的数量也不够,因为最初提供了一些图像,并且不是每个图像都包含裂纹像素。

虽然获得了有希望的结果,但仍需要进行一些改进(获得更好的训练数据集将是一个开始😅).如果你们喜欢这项工作或者需要更多信息,可以在这里找到我的完整出版物。

梯度推进在订单建模中的应用

原文:https://towardsdatascience.com/application-of-gradient-boosting-in-order-book-modeling-3cd5f71575a7?source=collection_archive---------2-----------------------

今天,我们将创建一个预测订单簿中价格变动的 ML 模型。本文包含了一个完整的研究周期:获取数据、可视化、特征工程、建模、算法的微调、质量评估等等。

什么是订单簿?

订单簿是一个电子列表,列出了按价格水平组织的特定证券或金融工具的买卖订单。订单簿列出了每个价位或市场深度的出价或出价股票数量。市场深度数据有助于交易者确定特定证券的价格走向。例如,交易者可以使用市场深度数据来了解证券的买卖差价,以及高于这两个数字的交易量。具有强大市场深度的证券通常具有强大的交易量和相当的流动性,允许交易者在不显著影响市场价格的情况下下大量订单。更多信息请点击这里。

Pricing scheme

市场深度看起来像这样,可视化可能是不同的,它取决于软件

BTC market depth on GDAX

另一种可视化订单簿的方式是一个包含出价和报价的列表

Order book list

中间价是介于股票或商品的卖方的最优价格或卖价和买方的最优价格或买价之间的价格。它可以简单地定义为当前报价的平均买价和卖价。

我们的目标是创建一个预测中间价的模型。

获取数据

让我们从龙虾下载数据样本。该服务以谷歌、苹果、亚马逊、英特尔、微软资产为例,提供 3 个级别的市场深度(1、5、10 级)。

首先,我建议将所有可用资产的中间价和买卖差价可视化。我们需要导入必要的库

下一段代码从文件中加载给定资产和级别的数据

之后,我们可以可视化每个资产

Mid-price and ask-bid volume difference

MSFT 和 INTC 有稍微奇怪和不同的分布。中间价图没有单一的钟形曲线,它看起来像两个分布的混合。还有,量差太对称,和其他资产不一样。

特征工程

这一部分非常重要,因为模型的质量直接取决于它。我们应该在这些新特性中反映出价、要价、交易量以及不同深度数据之间的广泛关系。

接下来的公式允许创建这些特征

Features

这些特征是特征工程的第一部分。第二部分是添加滞后组件。这意味着我们在时间上有一些滞后地移动给定的特征,并作为列添加。此示例显示了它在原始数据集(非新要素)上的工作方式。

Lag components example

接下来的代码提供了特征工程的这两个部分,并添加了目标列 log_return_mid_price

通常,特征看起来像这样

Features example

通过梯度增强和微调进行建模

我们的目标是表明训练 GBM 是在我们的真实目标, y,和我们的近似之间的一些损失函数上执行梯度下降最小化,

这意味着增加弱模型,

我们的 GBM 添加剂模型:

正在以某种方式进行梯度下降。这是有意义的,推动我们的逼近,越来越接近真正的目标 y 将执行梯度下降。例如,在每一步,残差变小。我们必须最小化一些与真实目标和我们的近似值之间的距离相关的函数。让我们重温一下高尔夫球员的类比,想象一下近似值和真实值之间的平方误差

更多信息你可以在这里找到。

我们将使用 Yandex 的梯度增强实现,它调用 CatBoost 。在大多数情况下,这个库在速度和质量上都优于其他库

Libraries performance

该算法有几个对质量有巨大影响的参数:

  • n_estimators —解决机器学习问题时可以建立的最大树数;
  • 深度 —树木的最大深度
  • learning_rate —该设置用于减少梯度步长。它影响训练的整体时间:值越小,训练需要的迭代次数越多;
  • l2_leaf_reg —成本函数的 l2 正则项的系数。允许任何正值。

此外,我们还有特性的参数:

  • 水平 —市场深度;
  • 时间步数 —建立多少个滞后。

理论上,我们的每个资产都有唯一的一组参数。对于这项任务,我们应该定义评估模型质量的目标函数

定义最佳参数的最佳方法之一是贝叶斯优化。我在[上一篇文章](http://One of the best ways to define the optimal parameters is Bayesian optimization. I described this approach in the previous article.)中描述了这种方法。

损失函数是这样的 RMSE

训练集从一开始就包含 50%的数据。验证数据用于模型的微调。测试最终结果所需的最后 25%的数据,这是保留数据。

在微调步骤之后,我们在两个部分(训练集和验证集)上训练最终模型,并使用最后一个部分测试模型。让我们编码这个

do_experiment 函数是本次研究的主要函数之一。该函数另外建立最佳模型的特征重要性,并估计模型的质量。

通常,重要性提供了一个分数,该分数指示每个特征在模型内的增强决策树的构造中有多有用或有价值。在决策树中,一个属性被用来做关键决策的次数越多,它的相对重要性就越高。

这种重要性是为数据集中的每个属性显式计算的,允许对属性进行排序和相互比较。

对于单个决策树,重要性通过每个属性分割点改进性能度量的量来计算,通过节点负责的观察的数量来加权。性能测量可以是用于选择分裂点的纯度(基尼指数)或另一个更具体的误差函数。

然后,对模型中所有决策树的特征重要性进行平均。来源这里。

结果分析

成功的基本衡量标准是使误差小于基线。意味着最终的模型质量很好。

第一个问题是如何衡量质量。可能是平方误差。之后就可以用 bootstrapping 法估计区间了。bootstrap 采样、计算统计和区间估计在上面的 bs_interval 函数中实现。

Bootstrapping

第二个问题是应该使用什么值作为基线预测。许多研究声称市场是不可预测的。通常,预测的下一个价格与上一个价格相同,加上一些噪声,如下所示

Bad stock prediction result

这意味着,如果我们想要预测回报,它将是 0 加上噪声左右。你可以在 Rafael Schultze-Kraft 的这篇文章中找到这个结果。

我们的基线是相似的。这种方法在 do_experiment 函数中实现。让我们运行这个实验do _ experiment(asset _ name),其中 asset_name 来自列表(AAPL、AMZN、GOOG、INTC、MSFT)。

将重要的参数和指标收集到此表中

Final result table

AMZN 和 GOOG 具有相同的最佳参数。通常,水平和深度具有最大值或接近最大值。

正如我们所记得的,在开始的探索阶段,前三个资产(AAPL、AMZN、GOOG)具有良好的买卖价格和交易量分布。最后两个资产(INTC,MSFT)有奇怪的分布。

该表显示,我们在 AAPL、AMZN、GOOG 和的误差方面获得了统计上的显著差异。 基线被击败(绿色)。建模间隔的上限低于基线的下限。

对于 INTC,我们没有显著的结果,区间是交叉的(灰色)。在 MSFT 的情况下,给定的结果比基线差(红色)。可能,其原因是检测到的分布模式(可能是做市商的一些活动或其他事情)。

让我们看看这些模型最重要的特征

Top features for AAPL

Top features for AMZN

Top features for GOOG

Top features for INTC

Top features for MSFT

正如我们所看到的,对于成功的模型,最重要的特征与最近的值相关联 log_return_asklog_return_bidlog_ask_div_bid 等等。

结论

  1. 提出了基于梯度推进的订单簿建模方法。你可以在 GitHub 上找到的代码。
  2. 描述和形式化的特征工程方法。显示了特征的重要性。
  3. 演示质量评估。对于一些资产,获得了良好的结果。

如何提高成绩:

  1. 在优化中更改 max_evals 的数量。
  2. 在拟合中改变最大 _ 深度n _ 估计量
  3. 添加比当前功能更好的新功能,或给定功能的组合。
  4. 使用更多数据进行实验,以获得更好的模型。
  5. 在订单簿中查找具有更多的历史。
  6. 使用专门为时间序列开发的模型(如 LSTM、GRU 等)。

最诚挚的问候,

谢尔盖

激光雷达在林业中的应用。

原文:https://towardsdatascience.com/applications-of-lidar-in-forestry-13686e1b15a7?source=collection_archive---------10-----------------------

Llight Detection and Ranging(激光雷达)是一种主动遥感传感器,它发射激光信号,根据返回的激光脉冲的时间延迟来计算距离。他们能够记录密集的距离回波值阵列(例如,在 50 米范围内每平方厘米几个激光回波的数量级),这些数据被组合成表面的高度详细的 3D 重建。这些在林业中有多种应用,例如:

  1. 为森林规划和管理生成高分辨率数字高程产品(DSM,DTM)的详细表面建模。
  2. 激光雷达技术为精确的生态和土地利用分类提供了更准确的信息。
  3. 激光雷达可以通过测量树冠的垂直结构和密度来绘制森林地图。这些模型有助于我们了解复杂的森林结构,并生成准确的森林清单。
  4. 激光雷达可以用来监测森林中的火灾模式,使消防部门意识到下一次可能的森林火灾。
  5. 针对特定森林区域的精准林业可以帮助我们提高树木质量和总产量。
  6. 这样的例子不胜枚举……

用于精确森林调查的地面激光雷达

在这里,我想给你们概述一下我在希腊西部地中海针叶林的研究,该林位于希腊 Aetolia-Acarnania 村 Gouria 附近,使用地面激光扫描仪(TLS)进行研究。我们只对白皮松进行了研究,因为它是我们项目区最主要的物种(90%)。这项研究中使用的地面激光扫描仪是 Faro Focus 3D 330,它具有 300°和 360°的垂直和水平视场。它的范围从 0.6 米到 330 米,距离精度达到 2 毫米,噪音降低 50 %。下图展示了研究区域和 TLS 的视觉信息。

Study Area in Aetolia-Acarnania village of Greece

Terrestrial Laser Scanner ( Faro Focus 3D 330 )

此外,使用照片级真实感漫游从 TLS 进行密集 3D 重建的示例如下所示:

TLS based 3D point cloud dataset of a small section of the study area.

使用密集 3D 重建,我们应用聚类、过滤和圆柱拟合算法来自动计算距离树基部 1.3 米处的胸径(DBH)。对于树高的测量,首先,从 TLS 导出的点云中分割出单棵树。然后,使用点云两端之间的差异来测量个体树。DBH 和树高结果的直观演示可使用下图进行评估:

Automatic Detection of DBH (white color), tree trunk (red color)

Tree Height Computation from TLS point cloud data

我们使用 DBH 和树高的实地测量来验证结果,使用的树测径器与树干成直角,距离树基部 1.3 米。同样,使用激光测距仪测量树高的实地估计值。下图展示了这两种情况。

Field measurements of DBH and Tree Height to validate the findings.

当将从现场数据测量的 DBH 与从 TLS 导出的 DBH 进行比较时,R 平方值的范围为 0.75 至 0.96。同样,当比较 TLS 和田间数据之间的树高时,获得 0.80 和 1.07 的平均 R 平方和 RMSE 值。

最后,本研究得出结论,TLS 在更精确地获得森林资源调查变量(DBH 和树高)和结构特征(如蓄积量)方面具有很大的潜力。结果证实,TLS 可以提供一个非破坏性的,高分辨率和精确的森林调查参数的确定。这项研究的结果将有助于研究人员更好地理解由于所提供的处理参数的变化而导致的森林清查变量检索准确性的偏差,并进一步促进森林管理的决策。

这项研究的结果已经发表在 SpringerLink 的《摄影测量、遥感和地理信息科学杂志(PFG)》上。日记账可以使用:【https://link.springer.com/article/10.1007/s41064-017-0024-1】进行评估

干杯!

苏曼·吉米尔

地理空间现场数据分析员

国际山区综合发展中心

尼泊尔加德满都邮政总局信箱 3226 号

电话+977–1–5275222 转 214 传真+977–1–5275238网页www.icimod.org

MCMC 在密码学和最优化中的应用

原文:https://towardsdatascience.com/applications-of-mcmc-for-cryptography-and-optimization-1f99222b7132?source=collection_archive---------3-----------------------

增进理解的例子

Photo by Balázs Kétyi on Unsplash

MCMC 是一个很难理解的话题,但是例子确实很有帮助。

上次我写了一篇文章,直观地解释了 MCMC 方法。在那篇文章中,我展示了如何使用 MCMC 链来模拟分布部分已知的随机变量,即我们不知道归一化常数。

我还讲述了如何使用 MCMC 的 来解决大型状态空间的问题。 但没有给出例子。

在这篇文章中,我将提供一些真实的用例。

如果你到目前为止还没有真正欣赏 MCMC,我希望我能在这篇博文结束时激起你的兴趣。

这个帖子是关于借助一些计算机科学问题来理解 MCMC 方法的。

1.密码学——你是一个密码迷吗?

我喜欢密码学。

解谜一直是我的一个爱好,这个例子帮助我更好地理解了许多关于 MCMC 的想法。

这个问题也有很大的渊源,因为这个方法是由数学魔术师佩尔西·戴康尼斯提出的。

所以问题是:

有人带着下面的文字来找你。这条短信看起来像是胡言乱语,但实际上,这是一条可以拯救数百万人生命的秘密短信。他还告诉我们,它是用替代密码解密的。

XZ STAVRK HXVR MYAZ oak zm JKSSO SO MYR OKRR XDP JKSJRK XB masd SO YAZ tw dhz MYR JXMBYNSKF BSVRKTRM nya by NXZ BXKRTRZZTQ OTWDH SVRK MYR AKSD ERPZMRXP KWZMTRP MYR JXTR OXBR SO X QSWDH NSI xd NXZ kx azzrp or retq OKSI MYR jat tsn XDP X OXA DM vs ABR aijkorb mtq xkmabwttxmrp MYR NSKPZ TRM XDP MYR 女士

你能解密它吗?

让我们运用我们新发现的 MCMC 的力量。

关于替代密码的一个注意事项:替代密码就是我们用一个字母替代另一个字母。比如 A 变成 I,B 变成 C 等等。在原文中。

为了创造这个例子,这些数据实际上取自《雾都孤儿》。我们使用随机加密密钥对数据进行加密,加密后我们忘记了密钥,我们希望使用 MCMC 链对加密文本进行解密。真正的解密密钥实际上是

" ICZNBKXGMPRQTWFDYEOLJVUAHS "

所以让我们稍微思考一下这个问题。

解密密钥可以是任何 26 个字母的字符串,所有字母只出现一次。像这样的字符串排列有多少种?这个数字将会是 26!大约 10 个⁶排列。

这是一个相当大的数字,因此这个问题有一个 大的状态空间 (本质上是我们可能需要解析的大量排列)。

如果我们使用暴力的方法,也许我们的孙子或者他们的孙子会得到解决方案。那么我们能做什么呢?

谁是 MCMC?

我们将设计一个链,其状态理论上可以是这些排列中的任何一种。然后我们将:

  1. 从选择一个随机的当前状态开始。
  2. 通过交换当前状态中的两个随机字母来创建新状态的提议。
  3. 使用 评分函数 计算当前状态Score_C和建议状态Score_P的得分。
  4. 如果建议状态的分数大于当前状态,则移动到建议状态。
  5. 否则抛硬币决定哪个有正面的可能性Score_P/Score_C。如果它来了,头移动到提议的状态。
  6. 从第二步开始重复。

如果我们幸运的话,我们可能会达到一个稳定的状态,在这个状态下,这个链具有所需状态的稳定分布,这个链所处的状态可以作为一个解。

什么是评分函数?

这里我们需要担心的主要是评分函数。我们如何计算一个提议是否是一个好的提议?

还记得我上一篇文章中的 hill 例子吗?

我们想搬到最高的山上,并在那里呆很长时间。我们应该为每个状态(解密密钥)使用一个评分函数,该函数为每个解密密钥分配一个正的分数。

如果使用这个解密密钥解密的加密文本看起来更像真实的英语,这个分数直观上应该更高。

那么我们如何量化这样一个函数呢?

英语有一种特殊的结构。我们假设某一对字母一起出现的次数可能遵循某种特定的模式。因此“TH”比“ZF”更有可能出现。

我们将检查一个长文本并计算这些统计数据。

我们将会看到在像《战争与和平》这样合法的长文本中,一个字母一个接一个出现了多少次。这里文本的选择并不重要。

例如,我们希望找出“BA”在文本中出现了多少次,或者“TH”在文本中出现了多少次。

对于每对字符β₁和β₂(例如β₁ = T 和β₂ =H),我们让 R( β₁,β₂)记录该特定对(例如“TH”)在参考文本中连续出现的次数。

类似地,对于解密密钥 x,我们让 Fₓ(β₁,β₂)记录当使用解密密钥 x 解密密文时该对出现的次数

然后,我们使用以下公式对特定的解密密钥 x 进行评分:

这个函数可以被认为是对解密文本中的每个连续字母对乘以该对在参考文本中出现的次数。

直观上,当解密文本中的配对频率最接近地匹配参考文本中的配对频率时,得分函数较高,因此解密密钥最有可能是正确的。

为了使我们的计算生活更容易,我们将计算 log(Score(x))

让我们开始逐步解决这个问题。

首先,让我们加密一些文本来创建我们的例子。在这个残酷的世界上,我们必须自己做所有的事情。

我们可能希望首先为我们的评分函数和评分函数本身创建一些统计数据。

我们还想有一个功能来创建提案国和随机硬币投掷。

最后,这是我们使用 Metropolis-Hastings 算法运行的 MCMC 函数。

现在让我们使用上面的所有函数运行整个代码。

输出:

这个链大约在第 2000 次迭代时收敛,我们能够解读代码。

太棒了。

现在,正如您看到的,找到的 MCMC 密钥并不完全是加密密钥。因此,该解决方案不是确定性的,但我们可以看到,它实际上并没有减少 MCMC 方法提供的任何值。

现在让我们帮助比尔博。

2。背包问题

所以比尔博·巴金斯去了史矛革的巢穴。

他发现了 M 宝藏。

每个宝藏都有一定的重量和黄金价值。

但问题是比尔博真的承受不了这些。

他只能承受一定的最大重量。

但是作为一个聪明的霍比特人,他想最大化他拿走的财宝的价值。

考虑到重量和宝藏的价值以及比尔博能携带的最大重量,你能找到一个好的解决方案吗?

这就是计算机科学中的背包问题。

所以在这个问题中,我们有一个 1xM 数组的重量值 W,黄金值 G,以及一个比尔博可以携带的最大重量 w_MAX 的值。

我们想找出一个由 1 和 0 组成的 1xM 数组 X,它保存着比尔博是否携带了某个特定的宝藏。

该数组需要遵循以下约束:

WX < w_MAX

i.e. the total weight Bilbo Carries is less than Max Weight.

and we want to maximize

GX

i.e. the total Gold value for a particular state X.

Now as earlier this problem also has a 大境界空间。如果我们尝试用蛮力来做,我们需要的排列数是 2^M.,我们可以看到它会变得很大。

如前所述,这是我们可以使用 MCMC 方法的地方。

因此,让我们首先讨论如何从先前的状态创建一个提案。

  1. 从状态中选择一个随机索引并切换索引值。
  2. 检查我们是否满足约束。如果是,则该状态是建议状态。
  3. 否则选择另一个随机索引并重复。

我们还需要考虑评分函数。

我们需要给黄金价值高的州以高价值。我们将使用:

分数越高,我们给予的价值就越大。这里的β是一个+ve 常数。(T 代表转置)

但是β怎么选呢?

如果β很大,我们会给好的解决方案一个很高的分数,链将不能尝试新的解决方案,因为它会陷入局部最优。

如果我们给一个小的值,这个链不会收敛到非常好的解。

因此,我们使用一种称为 模拟退火 的优化技术,即我们将从一个较小的β值开始,随着迭代次数的增加而增加。

这样,链将在开始阶段探索,并在后期阶段停留在最佳解决方案。

现在,我们已经有了开始行动所需的一切。

让我们从创建一个建议函数和得分函数开始。

以及 MCMC 项目。

运行主程序:

OUTPUT
________________________________________________________________MCMC Solution is : [0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0] with Gold Value: 2435

现在我不会说这是最好的解决方案。

使用 DP 的确定性解决方案对于这种用例来说是最好的,但是有时当问题变大时,拥有这样的技术变得非常有价值。

结论

在这篇文章中,我试图用 MCMC 解决计算机科学中的两个问题。

密码学本身是一个庞大的课题,有很多应用。背包问题出现在各种领域的现实世界决策过程中,例如寻找最少浪费的方法来切割原材料,选择投资和投资组合,选择互联网下载管理器中的数据块以及其他优化。

这两个问题都有一个很大的状态空间,不可能用蛮力来解决。

你对 MCMC 方法有什么看法?

此外,如果您发现任何好的应用程序,或者想将这些技术应用到某个领域,我真的很乐意了解它们,并在可能的情况下提供帮助。

你可以在 GitHub 或者 Google Colab 上找到全部代码。

你可以关注的最新和最好的资源之一是 高级机器学习专业化 中的 贝叶斯机器学习方法 课程

我以后也会写更多这样的帖子。让我知道你对这个系列的看法。在 媒体 关注我,或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系。

参考

  1. 概率导论约瑟夫·K·布利茨泰因、杰西卡·黄
  2. 百科

零起点学习的应用

原文:https://towardsdatascience.com/applications-of-zero-shot-learning-f65bb232963f?source=collection_archive---------5-----------------------

作为计算机视觉研究小组的成员,我想写这篇短文来简要介绍我们所谓的“零射击学习”(ZSL),一种迁移学习的有趣变体,以及当前与之相关的研究。

今天,许多机器学习方法专注于分类实例,这些实例的类已经在训练中出现过。具体地说,许多应用程序需要对其类以前从未见过的实例进行分类。零炮学习是一种很有前途的学习方法,其中训练实例覆盖的类与我们要分类的类是不相交的。换句话说,零射击学习就是在没有额外训练数据的情况下利用监督学习。

零镜头学习指的是机器学习的一个具体用例(,因此深度学习),其中你希望模型基于很少甚至没有标记的例子对数据进行分类,这意味着动态分类。

让我们想想卷积神经网络(CNN)是如何工作的——它们将例如图像识别的一般任务分解为一系列由连续层执行的较小任务,其中每一层处理越来越复杂的特征。

当我们训练一个网络来识别一张给定的图片时,例如一个人,我们已经训练它来识别手臂、腿、脸等等。由于这一点,我们可以重复使用这些特征检测器,并重新排列它们来执行一些其他任务,而无需额外的培训。

换句话说,零射击学习是关于利用已经由监督学习以其他方式训练的深度学习网络,而不需要额外的监督学习。

零射击学习可以产生非常有趣的应用,尤其是在我们缺乏适当数据集的情况下。你可能知道,在几乎所有的计算机视觉项目中,缺乏数据是一个巨大的问题。如果要我用几句话来总结 ZSL,我会说是:

  • 无训练样本的模式识别
  • 基于语义转移

数据的自然稀缺

零射学习是人类已经具备的能力。事实上,我们可以用“最小数据集”学习很多东西。例如,你倾向于用每种水果的一些图片来区分同一种水果的不同品种(细粒度分类)和其他水果或外观相似的水果(常规分类)。机器的情况不同...他们需要大量的图像来学习适应自然发生的变化。

这种天生的能力来自于我们现有的语言知识库,它提供了对一个新的或未见过的类的高层次描述,并在它和见过的类和视觉概念之间建立了联系。

为什么我们需要零拍学习?

如你所知,在许多领域中有大量且不断增长的类别。因此,很难为每个类别收集大量带注释的数据。

在一些项目中,类的数量可以达到数千个,并且为每个类获取足够的训练数据是复杂的。零炮学习旨在仅使用来自一小组类的标记数据和关于类关系的外部知识来预测大量未看见的类。此外,类别的数量不断增加,为每个新类别收集新数据的难度也在增加。在需要大量数据的深度学习中尤其如此…

同一物体的不同种类可能很快变成一场噩梦,在这种情况下,无监督学习无法提供帮助。

此外,在正常的对象识别过程中,我们必须确定一定数量的对象类别以提高我们的准确性,并为选定的对象类别收集尽可能多的样本图像。此外,这些样本图像应该包含在各种环境中从不同角度拍摄的元素,以便丰富数据集。

在某些情况下,标签只能由专家来完成。像特定物种的识别这样的细粒度对象识别任务可以被认为是在专家的监督下进行标记的例子。

人们对用于扩大视觉识别的机器 ZSL 越来越感兴趣。

它是如何工作的

不需要太多的细节,零射击学习依赖于一个有标签的训练集的存在,这个训练集包括看得见的类和看不见的类。可见类和不可见类在一个叫做语义空间的高维向量空间中是相关的,可见类的知识可以转移到不可见类中。

零触发学习方法被设计成学习中间语义层及其属性,并在推理时应用它们来预测新的数据类别。

通常情况下,零炮学习算法首先将实例映射到中间属性,中间属性可以是可见的类(带标签数据的类),人类指定的或数据依赖的属性。然后通过知识库将预测的属性映射到大量的未知类别。通过这种方式,对未知类别的预测成为可能,并且这些类别不需要训练数据。

零投学习是一个两阶段的过程:训练和推理。在训练阶段,获取关于属性的知识,在推理阶段,这些知识用于在一组新的类别中对实例进行分类。人们似乎已经做了很多努力来改善训练阶段,而推理阶段却很少受到关注。例如,许多方法不能充分利用属性的辨别能力,并且不能利用在第一阶段获得的属性预测的不确定性。

研究

从研究的角度来看,我已经看到一些团队在研究更精确的 ZSL 模型,该模型使用称为生成对抗网络(GANs)的神经网络架构来读取和分析来自网络的文本,然后在视觉上识别它们描述的对象。这种新方法使系统能够根据类别对对象进行分类,然后使用该信息来识别其他类似的对象。

受益于这项研究的另一个重要因素是偏见。事实上,训练数据的收集和标记可能非常耗时,并且因为仍然难以收集足够多的统计上不同的训练图像,所以未标记的目标类(即,之前未见过的图像或对象)通常被归类为标记的类,这导致了一般化设置中的不良准确性。

当可用的训练图像很少时,现有的对象识别模型很难做出正确的预测,而 ZSL 主要是作为解决这个问题的手段而开发的。

由于我们的研究,我们设法建立了一个原型,可以通过分析相关的网络文章来识别物种。只看那些文字描述(没有看到物种的图像),系统提取关键特征,如动物的头部形状。然后,该系统可以以某种方式想象物种的样子,生成一个合成的视觉模型。

很重要的一点是,图像和文本理解的结果并没有消除训练的需要,但这是一个 ZSL 如何减少训练并帮助系统在面对意外数据时保持准确的例子。

随着 ZSL 的继续发展,我希望看到更多的应用程序,如更好的推荐和更先进的解决方案,自动标记社交媒体类别中的不良内容。我还预见了 ZSL 在机器人领域的强劲发展。

零镜头学习方法在许多方面与人类视觉相似,因此可以用于机器人视觉。不是在有限的一组对象上执行识别,而是使用零射击学习来识别每个对象是可能的。

我毫不怀疑 ZSL 能帮助人工智能从今天有限的应用领域过渡到对人类来说如此自然的多功能领域。

更多信息,我推荐这个视频:【https://www.youtube.com/watch?v=jBnCcr-3bXc】-t = 626s

应用人工智能:从概念到 ML 组件

原文:https://towardsdatascience.com/applied-ai-going-from-concept-to-ml-components-7ae9c5d823d3?source=collection_archive---------17-----------------------

敞开你的心扉,接受将机器学习应用于现实世界的不同方式。作者 Abraham Kang 特别感谢 Kunal Patel 和 Jae Duk Seo 为本文提供意见和建议。

Photo by Franck V. on Unsplash

行动纲要

候选问题

许多人对使用人工智能自动化组织内的冗余流程感兴趣。让我们从一个具体的问题开始,我注意到的是,当不好的事情发生时,律师通常会从客户那里收集事实。这些事实构成了个人可以起诉的诉因(疏忽、殴打、攻击、故意施加精神痛苦)的基础。一旦根据法律依据和事实确定了诉讼原因,就要写好诉状并提交给法院,以便开始法律诉讼。诉状是一份法律文件,列出了导致对另一方采取行动的法律依据的事实。手动创建此文档可能非常耗时,并且类似的事实会导致类似的行动原因。例如,如果有人打了另一个人,通常会有一个“电池”。如果有人不小心伤害了其他人,或者有人在商店里滑倒,可能会受到疏忽的起诉。基于这个问题,我们有一个客户想使用人工智能来学习如何根据描述所发生事情的事实段落写一份投诉。

理解问题

试图让人工智能/人工智能阅读事实,并找出一种方法让人工智能/人工智能撰写完整的投诉可能会超出模型的能力范围,可能需要数年才能解决。然而,如果你花时间去理解和思考潜在的问题,你可以找到现有的技术(稍加修改)来解决这个难题的不同部分。例如,当你看一份诉状时,它以对双方及其立场(原告对被告)以及代表他们的律师的描述开始。可能有集体诉讼部分、管辖权证明(法院是否有权管辖各方)、各方描述、地点证明(我们是否在适当的法院地点)、诉讼原因列表和事实描述。当你看这些部分的时候,你必须考虑构建各个部分的数据来自哪里。在某些情况下,你不会有答案,但如果你仔细观察,你会发现投诉的不同部分之间的模式和相关性。这将允许你考虑你对神经网络的输入和候选输出。

获取神经网络的输入

我们本身没有任何数据,但可能有一种方法可以从所有现有的投诉中解析出事实,并将它们用作我们神经网络的输入。提交给法院的每一份投诉都成为公共信息,因此会有大量的数据。这种解决方案将要求律师写下他们的事实,就像他们直接将它们插入到投诉中一样,但这对于能够让机器学习提供生成的投诉来说是一个小小的不便。提出完整的投诉可能很困难。所以我们把问题分解一下。

分解问题

从逻辑上讲,如何将文档的生成分解成更小的部分?你需要看一个例子:https://www . heise . de/downloads/18/1/8/9/1/3/4/6/NP-v-Standard-Innovation-complaint . pdf。为了让它变得有趣,我挑选了一家成人玩具制造商,这样可能会激发你的好奇心。基本上,我们希望最终从律师提供的事实中生成一份诉状(pdf 以上)。因此,如果你看看这份文件和其他投诉,你会发现类似的结构模式。

所以,你认为什么是分解事物的最好方法…在你有时间思考之前,不要向下滚动。

….真的好好想想…..

好吧,如果你说使用模板按部分分解,那么这可能是最好的方法。

当你分解投诉时,投诉中会列出行动的原因。每个诉因(违反联邦窃听法案、伊利诺伊州窃听法规、侵扰隔离、不当得利、欺诈和欺骗性商业行为法案等)。)有基于事实的支持规则和理由。所以现在有两个问题。如何从事实文本中得出行动的原因,如何在每个行动原因下生成支持文本?

寻找行动的原因

当我们看案件的事实时,我们需要找到我们可以起诉的所有诉讼原因(违反的法律)。从文本中寻找行动的原因没有直接的解决方法,所以我们必须从根本上思考。

你认为我们可以用什么样的现有技术来观察文本并推断文本的意思或描述。如果你说的是多标签文本分类或者多标签情感分析,那么你就领先了(https://paperswithcode.com/task/text-classification,https://papers with code . com/task/perspective-analysis)。.)分析文本以确定其相关的行动原因的过程类似于对文本进行分类或寻找相关文本的情感。还有一些相关的问题,例如,随着法律的出台,诉讼原因需要更新。可能有另一种方法来创建事实的嵌入,然后基于三元组(https://arxiv.org/pdf/1503.03832.pdf)或四元组损失(https://arxiv.org/pdf/1704.01719.pdf)将诉因与事实联系起来,以在嵌入空间中将共享相似词的诉因推到一起,并将不相关的诉因推得更远。然后,使用聚类技术,找出与决定性词语嵌入相近的诉因,这些词语嵌入用于支持与诉状的个别诉因部分中的词语相关的论点。

在单个诉讼原因的支持论据部分生成文本

既然您已经知道如何从文本中获得高层次的诉因,那么您如何为每个单独的诉因部分(违反联邦窃听法案、伊利诺伊州窃听法规、侵扰隔离、不当得利、欺诈和欺骗性商业行为法案等)生成支持性的论据文本。)?

这一个不那么直截了当。想一想什么样的神经网络架构可以生成文本(不要向下滚动,直到你有了一些想法)…

….打开你的心扉…使用原力…

文本生成算法(https://paperswithcode.com/task/data-to-text-generation,https://paperswithcode.com/area/nlp/text-generation)可能是一种选择,但即使是最好的算法也会经常产生乱码。更好的选择可能是使用类似神经网络的架构参与翻译(https://paperswithcode.com/task/machine-translation,https://papers with code . com/task/unsupervised-machine-translation,https://papers with code . com/paper/unsupervised-clinical-language-translation)。此外,为每个行动原因建立一个单独的“翻译”神经网络可能是一个好主意,它可以帮助每个神经网络专注于识别用于为每个行动原因生成支持论据的关键事实。

打扫

通过语法检查器/修正器(https://papers with code . com/task/grammatic-error-correction)运行每个诉讼原因的支持参数文本的候选文本可能是个好主意。这样,任何明显的混乱都会得到解决。

结论

我希望你学会了如何更广泛地应用机器学习解决方案。如果你遇到困难,请告诉我,因为我绝对有兴趣听到人们试图用机器学习来解决的问题。

将拓扑数据分析应用于深度学习?动手心律失常分类!

原文:https://towardsdatascience.com/applied-topological-data-analysis-to-deep-learning-hands-on-arrhythmia-classification-48993d78f9e6?source=collection_archive---------19-----------------------

医疗保健是一个令人兴奋的工作领域。每一次受控的性能增强都多少意味着拯救或改善生命。因此,足够好的概括不是你可以沾沾自喜的。

现在的问题是如何去做。有些人通过扩大数据集的规模来增强他们的推断,有些人提高了质量,有些人使用全新的模型,还有一些人发明了自己的技术。不用引用,深度学习的兴起大概就是最好的例子。今天,我将着眼于最后一个选项:在数据描述方面进行创新。我给你介绍一个:拓扑数据分析。也被缩写为 TDA ,这是从应用拓扑学和计算几何的各种研究中出现的一个新领域。它的目的是提供良好的数学,统计和算法的方法来利用数据中的拓扑和潜在的几何结构。TDA 通常在三维数据上可视化,在其他情况下也很有用,例如时间序列。感兴趣吗?😄

[## 从拓扑数据分析到深度学习:不劳无获

今天,我将尝试给出一些关于 TDA(用于拓扑数据分析)的见解,这是一个快速发展的数学领域…

towardsdatascience.com](/from-tda-to-dl-d06f234f51d)

因为我希望这篇文章实用,所以我将向您推荐我以前写的一篇文章,它揭示了一些理论概念。请随意花几分钟时间沉浸在 TDA 为您提供的多个主题中。这篇文章摘自我在东京富士通人工智能实验室与 INRIA(法国研究所)的 Datashape 团队合作时所做的工作。很不幸,当我不能分享整个工作时,泪水顺着我的脸颊流下,但是你应该有你需要的一切,用那个 Github 和那个论文。

什么是心律失常?

这并不奇怪,但是你应该知道心脏病和中风是美国五大死亡原因之一。因为它关系到外面的每个人,难怪像苹果这样的公司正在通过开发他们自己的智能显示器来瞄准这个领域。事实证明,你的心脏可能是你全身最牛的肌肉:它 24/24 7/7 不间断地工作,并且以非常有节奏的方式工作。然而,它有时会跟不上节奏,这可能是因为酒精、闪电式恋爱、剧烈运动或恐怖电影。其中一些失败可能会致命。心律失常是一种衰竭,是一组描述心律不齐状况的总称,在形状或频率方面。检测这些事件并监测它们的频率可能对监督你的健康有巨大的帮助,并确保你在需要时获得正确的健康干预。然而,这需要智能监控。

弄脏你的手!

M 机器学习!这听起来像是智能监控的方式!但这需要的不仅仅是一个漂亮的模特。这是一件好事,人们一直在努力通过提供一系列开源数据集来促进研究。这些可在 Physionet 平台上获得,并以它们描述的条件命名:麻省理工学院-BIH 正常窦性心律数据库、麻省理工学院-BIH 心律失常数据库、麻省理工学院-BIH 室上性心律失常数据库、麻省理工学院-BIH 恶性室性心律失常数据库和麻省理工学院-BIH 长期数据库。这些数据库由单通道心电图组成,每一个都以 360 Hz 采样。两个或更多的心脏病专家独立地注释每个记录,他们的分歧被解决以获得每个搏动的参考注释。我们可能已经心存感激了!

注释还有一个好处,就是让我们从心跳检测的问题中解脱出来,这并不是一个很大的障碍:基线漂移小波变换1D-CNN 作为一个解决方案,它们都工作得很好。

如何描述心跳?

在我们的例子中,CGs 是一维时间序列,如何描述它们的形状和时间关系?这是一个非常普遍的问题,可以转移到许多领域。这就是拓扑将会有所帮助的地方!

Credits

让我们从我们想要从这些心跳中得到的时间信息开始。在单个事件的范围内,检索到的间隔是左侧描述的间隔( PQRST 事件)。该信息已经与形状高度关联。在 ECG 本身的范围内,我们还需要检索 RR 间隔,这是连续 R 峰之间的延迟,从而量化总体节律(及其异常)。

从那以后,你可能已经在考虑使用上面展示的特性来构建你的模型了(在等式中添加一些 FFT /小波/混沌理论/ …)。从这些特征(结合 SVM、增强树或神经网络)获得的结果是好的,但还不够令人满意。时间信息不是问题所在:问题在于心跳的形状。它们表明心脏本身有一个非常复杂的机制,而个体差异从一开始就意味着巨大的可变性。因此,我们需要一个模型,能够捕捉模式,而不会过度拟合由我们拥有的单个个体池产生的平均模式。这无疑是拓扑数据分析的魅力达到顶峰的地方,至少在时间序列方面。

在心律失常分类一般化所面临的主要挑战中,我们发现了个体差异,特别是心动过缓心动过速。TDA,更准确地说是持续同源理论,以简洁的方式有力地描述了 ECG 信号的形状,避免了复杂的几何特征工程。由于持久同源性的基本稳定性,TDA 特征对于 ECG 信号中感兴趣模式的变形,尤其是时间轴方向上的扩展和收缩,显得非常稳健。这使得它们对于克服个体差异和由心动过缓和心动过速引起的潜在问题特别有用。

Process Visualization: From ECG to Barcode Diagram to Betti Curve

持续同源理论来了(在这篇文章中提出)。它允许我们用一个持久性 条形码唯一地表示一个过滤的单纯复合(在我们的例子中,ECG 信号被转换成一个图形)的持久性同源性。条形码图用一条水平线表示每个持久性生成器,该水平线从它出现的第一个过滤级别开始,到它消失的过滤级别结束。现在,就过滤而言,我们有两种可能的图表:从上到下或从下到上。上图直观地分解了自上而下的策略,显示了使用 1D ECG 信号构建的条形码。不幸的是,条形码图表不能被机器学习直接利用,因为它们的尺寸不一致。为了使它们成为有用的形式,我们将图表转换成贝蒂曲线

贝蒂曲线 :让我们考虑一个 持久性条形码 ,为此我们对半径空间进行矢量化。条形码图的每个组成部分都被称为一个函数,在定义它的半径上取值为 1,在其他任何地方取值为 0。矢量化空间上的这些函数之和定义了贝蒂曲线。

对于每个心跳,我们现在有两条 Betti 曲线,它们的大小是一致的,并且是可控的。我个人倾向于 100 点矢量化,这样我可以将之前训练的模型重新应用到类似的问题中,这些问题将类似的分布曲线作为输入。

将深度学习带入等式

现在的问题是如何利用贝蒂曲线。除了作为一种奇特的数据表示,曲线在一维信号中包含了关于形状的复杂信息。寻找开发这些资源的最佳模式已经开始!

利用一维信号并不令人头痛。唯一不同的是,在这里,维度不是时间,而是空间。在您所拥有的选择中,您可以选择具有欧几里德或动态时间弯曲度量的 kNN,直接使用提升的树或使用 CNN 网络,这可能是在这些情况下最好的网络(可以通过 CNN 可以访问的多个尺度进行解释,这对于空间信息来说可能比时间更方便)。

我当时设计的模型可能更像是我想说的火箭筒,但它明确强调了我构想大多数深度学习问题应该基于的所需模块化的方式。你可以选择像斯坦福大学的论文 (34 层)那样走向堆叠策略,或者走向更水平的多模块方法,混合人类直觉(特征工程)和不可及的统计考虑(深度学习)。这正是下面描述的模型的全部内容:扩大你处理信息的范围

TDA 对归纳有多大影响?

您现在可能想知道 TDA 是否真的带来了我在本文开始时提到的性能提升。对于这一部分,我们花了大量时间进行实验:)

我们采取的第一步是试图评估 TDA 对我们深度学习架构的影响。突出了两个问题:二元分类** (~心律失常检测),包括从正常心跳中识别心律失常心跳,以及多类分类,包括将正确的标签归属于每个异常心跳。我们在交叉验证框架的基础上运行,让患者接受训练,一些进行验证,另一些进行测试。每个 ID 代表一个三重分裂(基于 240 名可用患者,训练 60%,验证 10%,测试 30%)和一个从头开始训练的模型。**

第一个结论很有趣:尽管添加 TDA 确实有助于泛化,但最受影响的问题是实际的分类。解释这一结果的一种方式是将 TDA 视为拓扑和形状的高度专业化的度量。第一个问题主要是关于检测异常心跳,这又回到异常检测,而第二个问题更多地依赖于拓扑信息,因为形状是区分异常心跳的巨大组成部分。

当然,撇开这一步不谈,我们实际上陷入了比较。我在下面附上我们的总体架构的结果,但不会在这里讨论所有的细节。[实际上,我不喜欢在论文之间设计评分系统的方式,基于围绕泛化稳健性的度量和考虑的快速发展,将我们的评估限制在这些方面甚至不再有意义。]

结论被高估了

我希望这篇应用拓扑数据分析的介绍引发了你对潜在理论的兴趣,以及它实际上可以用于的无限问题集。当形状直观地涉及到问题时,使用 TDA 最有意义。会不会通过持久性图条形码图持久性景观持久性轮廓贝蒂曲线,TDA 可以被用来作为机器学习管道的一部分。不幸的是,无论你的创新水平如何,最大的限制因素是数据。让我们开始考虑集中的高质量数据源,然后我们肯定会改变赌注!

参考

  • GitHub 资源库
  • Scikit-为 TDA 学
  • 从拓扑数据分析到深度学习:不劳无获
  • 持续理论:从颤动表象到数据分析
  • 孤质项目
  • 同调与拓扑持续
  • 几何和拓扑推理

有兴趣保持联系?😄Twitter|LinkedIn|Github|Medium

熊猫的应用和λ的使用

原文:https://towardsdatascience.com/apply-and-lambda-usage-in-pandas-b13a1ea037f7?source=collection_archive---------0-----------------------

Photo by chuttersnap on Unsplash

学习这些来掌握熊猫

熊猫是你可以随意使用的一个很好的工具。

我已经和熊猫一起工作了很多年,它的新功能、快捷方式和做一件特定事情的多种方式一直让我感到惊讶。

但我意识到,坚持我学到的一些惯例多年来对我很有帮助。

applylambda是我在熊猫身上学到的一些最好的东西。

每当我为一个新的列或过滤器构建复杂的逻辑时遇到困难,我就会使用applylambda

当企业向您提出定制请求时,这种情况经常发生。

这个帖子是向你展示 ***apply*** ***lambda*** 的威力。

我将使用 IMDB 上过去 10 年中 1000 部流行电影的数据集。你也可以跟随在 Kaggle 内核中。

创建列

Complex columns

您可以通过多种方式创建新列。

如果你想要一个列是列的和或差,你可以使用简单的基本算法。在这里,我得到了基于 IMDB 和标准化 Metascore 的平均评级。

df['AvgRating'] = (df['Rating'] + df['Metascore']/10)/2

但是有时我们可能需要围绕新列的创建构建复杂的逻辑。

举一个复杂的例子,假设我们想要基于各种因素构建一个自定义的电影评分。

比如说,如果电影是惊悚片,我想在 IMDB 评分保持小于等于 10 的条件下,在 IMDB 评分上加 1。如果一部电影是喜剧,我想从评分中减去 1。

我们怎么做呢?

每当我掌握了如此复杂的问题,我就使用apply/lambda。让我首先向您展示我将如何做这件事。

def custom_rating(genre,rating):
    if 'Thriller' in genre:
        return min(10,rating+1)
    elif 'Comedy' in genre:
        return max(0,rating-1)
    else:
        return rating

df['CustomRating'] = df.apply(lambda x: custom_rating(x['Genre'],x['Rating']),axis=1)

一般结构是:

  • 您定义了一个函数,该函数将接受您想要处理的列值,以得出您的逻辑。在这里,我们最终使用的两列是流派和评级。
  • 沿着 axis=1 的行使用带有 lambda 的应用函数。一般语法是:
df.apply(lambda x: func(x['col1'],x['col2']),axis=1)

您应该能够使用 apply/lambda 创建几乎任何逻辑,因为您只需担心自定义函数。

过滤数据帧

Filtering….

熊猫使过滤和子集化数据框架变得相当容易。您可以使用普通运算符和&,|,~运算符对数据帧进行过滤和子集化。

# Single condition: dataframe with all movies rated greater than 8df_gt_8 = df[df['Rating']>8]# Multiple conditions: AND - dataframe with all movies rated greater than 8 and having more than 100000 votesAnd_df = df[(df['Rating']>8) & (df['Votes']>100000)]# Multiple conditions: OR - dataframe with all movies rated greater than 8 or having a metascore more than 90Or_df = df[(df['Rating']>8) | (df['Metascore']>80)]# Multiple conditions: NOT - dataframe with all emovies rated greater than 8 or having a metascore more than 90 have to be excludedNot_df = df[~((df['Rating']>8) | (df['Metascore']>80))]

很简单的东西。

但有时我们可能需要进行复杂的过滤操作。

有时我们需要做一些操作,而仅仅使用上面的格式是做不到的。

例如:我们假设 我们想要过滤电影标题中字数大于或等于 4 的那些行。

你会怎么做?

尝试下面的会给你一个错误。显然,你不能做任何简单的事情,比如用一个系列分割。

new_df = df[len(df['Title'].split(" "))>=4]
-------------------------------------------
AttributeError: 'Series' object has no attribute 'split'

一种方法是首先使用 apply 创建一个标题中包含字数的列,然后对该列进行过滤。

#create a new column
df['num_words_title'] = df.apply(lambda x : len(x['Title'].split(" ")),axis=1)#simple filter on new column
new_df = df[df['num_words_title']>=4]

这是一个非常好的方法,只要你不需要创建很多列。但是,我更喜欢这个:

new_df = df[df.apply(lambda x : len(x['Title'].split(" "))>=4,axis=1)]

我在这里做的是 我的 apply 函数返回一个可以用来过滤的布尔值。

现在,一旦你理解了你只需要创建一个布尔列来过滤,你就可以在你的apply语句中使用任何函数/逻辑来得到你想要构建的复杂逻辑。

让我们看另一个例子。我会试着做一些稍微复杂的事情来展示它的结构。

我们想找到收入低于该年平均收入的电影?

year_revenue_dict = df.groupby(['Year']).agg({'Rev_M':np.mean}).to_dict()['Rev_M']def bool_provider(revenue, year):
    return revenue<year_revenue_dict[year]

new_df = df[df.apply(lambda x : bool_provider(x['Rev_M'],x['Year']),axis=1)]

这里有一个函数,可以用来写任何逻辑。只要我们能够处理简单的变量,这就为高级过滤提供了强大的功能。

更改列类型

我甚至使用 apply 来更改列类型,因为我不想记住更改列类型的语法,也因为它让我可以做更复杂的事情。

在 Pandas 中,改变列类型的正常语法是astype。因此,如果我的数据中有一个名为 price 的列,格式为str。我可以这样做:

df['Price'] = newDf['Price'].astype('int')

但有时并不会如预期般奏效。

你可能会得到错误:ValueError: invalid literal for long() with base 10: ‘13,000’.也就是说你不能把一个带有“,”的字符串转换成一个整型。要做到这一点,我们首先要去掉逗号。

在一次又一次地面对这个问题之后,我现在已经完全停止使用astype了,只使用 apply 来改变列类型。

df['Price'] = df.apply(lambda x: int(x['Price'].replace(',', '')),axis=1)

最后还有progress_apply

progress_applytqdm包附带的单一功能。

这为我节省了很多时间。

有时,当您的数据中有很多行,或者您最终编写了一个非常复杂的 apply 函数时,您会发现 apply 可能需要很长时间。

我见过应用程序在使用 Spacy 时花费数小时。在这种情况下,您可能希望看到带有应用的进度条。

你可以使用tqdm来实现。

在笔记本顶部的初始导入之后,只需将apply替换为progress_apply,一切都保持不变。

from tqdm import tqdm, tqdm_notebook
tqdm_notebook().pandas()df.progress_apply(lambda x: custom_rating_function(x['Genre'],x['Rating']),axis=1)

你会看到进度条。

结论

applylambda功能让你在操作数据的同时处理很多复杂的事情。

我觉得用熊猫不用担心很多事情,因为我可以很好地使用apply

在这篇文章中,我试图解释它是如何工作的。可能还有其他方法来做我上面做的事情。

但是我喜欢用apply / lambda来代替map / applymap,因为我觉得它可读性更强,也更适合我的工作流程。

如果你想了解更多关于 Python 3 的知识,我想从密歇根大学调出一门关于学习 中级 Python 的优秀课程。一定要去看看。

我以后也会写更多这样的帖子。让我知道你对这个系列的看法。在 媒体 关注我或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter @mlwhiz 联系。

应用数据挖掘更好地诊断自闭症谱系障碍

原文:https://towardsdatascience.com/apply-data-mining-to-better-diagnose-autism-spectrum-disorder-f7c8be226341?source=collection_archive---------25-----------------------

精神病学的数据科学方法

Photo by Anna Kolosyuk on Unsplash

简介

自闭症谱系障碍(ASD)是一种神经发育障碍,包括自闭症、阿斯伯格综合症和未特别指明的广泛性发育障碍(PDD-NOS)。根据 DSM-IV-TR 的定义,ASD 有三个特征。

  • 社会赤字
  • 沟通困难
  • 重复的行为。

在 DSM-V 中,标准被重组为两个领域。此外,所有以前定义的不同子类型都被合并到 ASD 中。

  • 社会交流和社会互动
  • 受限制的、重复的行为、兴趣或活动模式

根据疾病控制和预防中心(CDC)(2014),在美国,每 68 名儿童中就有 1 名(每 42 名男孩中有 1 名,每 189 名女孩中有 1 名)被确定患有自闭症。特别是,未特别指明的广泛性发育障碍(PDD-NOS)占 ASD 的 90%。尽管发病率如此之高,但没有具体的医学诊断方法。

传统方法

目前,ASD 通常是通过使用由专业训练有素的医生和心理学家评估的自闭症特定行为测量来诊断的。此外,父母,主要的照顾者,在发现他们孩子患自闭症的可能性上扮演着重要的角色。因此,我将数据挖掘应用于本提案的目的是为未来的 ASD 诊断找到最佳的数据驱动模型。

数据集正在使用

自闭症脑成像数据交换(ABIDE)是一个数据集,包括 7 个用于自闭症临床诊断的流行行为测量,它们是自闭症诊断访谈修订版(ADI-R)、自闭症诊断观察计划模块(ADOS)、社会反应量表(SRS)、社会沟通问题(SCQ)、自闭症商(AQ)、Vineland 适应行为量表(VABS)和韦克斯勒儿童智力量表-IV (WISC-IV)。在这个数据集中,有 539 个 ASD 和 573 个对照,总共包括 1112 个参与者。此外,有 16 个国际医疗站点对该数据集做出了贡献,每个医疗站点对 ASD 诊断应用了不同的测量。ABIDE 提供了多维视角来处理 ASD。

方法

了解哪种行为测量对 ASD 预测更好,进而确定哪种测量的子测试对预测 ASD 更好或更有代表性。我不仅应用了探索性分析来获得描述性统计数据,还应用了监督学习、决策树和回归模型的数据挖掘方法来分析 ASD 的这些数据。

决策树

决策树是一种预测模型,它使用决策及其可能结果的树状模型。此外,这是很容易理解的形象和明确的表示。在这个分析中,我提取了变量作为预测 ASD 的不同测量子测试,包括自闭症、阿斯伯格综合症和 PDD-NOS。所有子测试都是连续值,因此,决策树模型也可以称为回归树。

回归

回归是一个线性模型,它应用测量结果作为自变量来预测 DSM-IV-TR 诊断,因变量。通过交叉验证对所有模型的准确性进行了检验。

调查结果

总的来说,这项数据分析中显示的结果,SRS,对 4-18 岁儿童和青少年的相互社会互动的测量,预测 ASD 最好。互惠社会互动的特征被定义为所有发育障碍的核心特征。这意味着社会互动和交流的特点,具有更高的准确性,是一个更好的预测 ASD。因此,我的结论是,在 ABIDE 数据集中,SRS 是未来 ASD 诊断的最佳测量方法。

该提案被 2019 年美国心理学协会大会第 33 分部智力和发育残疾/自闭症谱系障碍所接受。

致挣扎的灵魂和未言明的心。

将人工智能应用于企业集成:我们准备好了吗?

原文:https://towardsdatascience.com/applying-ai-to-enterprise-integration-how-ready-are-we-912b2a954e60?source=collection_archive---------29-----------------------

介绍

最近,我们似乎每天都听到人工智能(AI),并看到它几乎在任何地方出现。人工智能可以做许多人类可以做的事情,而且速度比人类快几千到几百万倍。这使我们能够将人类从一些工作流中解脱出来,转而依靠人工智能在许多用例中驱动自动化。

因为人工智能有可能重新定义多种技术格局,所以值得仔细关注。在这种情况下,我们从整合的角度研究了人工智能,探索它如何以及在哪里改变整合的格局。在我们的研究背景下,我们将集成定义为"使用技术,使组织内部或组织之间通常不同的系统协同工作,以实现共同的业务目标。这篇文章总结了我们的发现。

人工智能相关的集成用例

首先,作为我们研究的一部分,我们确定了集成领域中 11 类人工智能相关的用例。

  1. 实现人工智能所需的集成——收集人工智能所需的数据并执行人工智能建议的操作,这产生了许多用例
  2. 数据集成——使用人工智能将来自许多不同格式和语义的数据源的数据协调成有意义的记录
  3. 从人类输入中提取有用的信息——使用人工智能提取有意义的输入数据,如音频、视频和自然语言
  4. 提高可用性——使用人工智能来提高系统的可用性
  5. 现有数据存储中的人工智能支持—支持人工智能作为现有数据存储中的交钥匙解决方案
  6. 算法经济——结合来自算法市场的算法来构建系统
  7. 自动驾驶操作(DevOps 和法规遵从性)—使用人工智能来减少或消除管理系统时对人工干预的需求
  8. 自动化和自助式集成—使用人工智能来简化创建集成的过程
  9. 安全性—使用人工智能来检测潜在的攻击和欺诈
  10. 业务自动化——使用人工智能实现业务运营自动化
  11. API 市场——使用人工智能在 API 市场中提供建议和评级

主要观察结果

在评估集成用例环境中的人工智能时,我们得出了一些观察结果。

值得注意的是,人工智能间接创造了整合需求。这是因为在企业中启用人工智能涉及收集、清理和创建数据的单一表示,以及执行决策和向外公开数据,每一项都会导致许多集成用例。

其次,人工智能决策中的弱点可能比人类决策中的弱点更加有害,原因有三:

  • 人工智能正在融入我们生活的大多数方面。
  • 由于每次重复的成本很小,AI 的使用频率高于人类。
  • 不同的人有不同的意见,这提供了监督和平衡错误的影响,而人工智能广泛应用相同的偏见。例如,人类面试官会有广泛的偏见,而人工智能会有一种偏见。

因此,实施人工智能用例的团队——无论它们是否涉及集成——都应该仔细考虑这些挑战的后果,例如偏见和隐私问题。

第三,挑战,如缺乏熟练的专业人员和数据以及模型可解释性,正在限制人工智能采用的有效性。例如,当应用于竞争性领域,如证券或股票市场时,基于人工智能的系统可能会相互竞争,这可能会导致比以前更糟糕的情况。一个例子是股票市场的闪电崩盘。

第四,多种力量正在推动未来将作为云 API 提供的人工智能应用。

  • 由于人工智能需要数据,在某些情况下拥有对数据的独家访问权会带来显著的竞争优势。这被称为“数据网络效应”云中的人工智能应用程序让供应商能够完全访问数据。
  • 由于缺乏专业知识和数据,定制人工智能模型的建立将仅限于大型组织。中小型组织很难构建和维护定制模型。许多人工智能用例将作为云 API 解决,让供应商集中数据和专业知识。
  • 人工智能的部署和管理是复杂的,当能够处理这些复杂问题的专业人员短缺时,它使部署变得复杂。使用云 API 将让人工智能消费者避开这些复杂性。

在我们的研究中,我们探索了每一类用例是如何受到上述机会、挑战和风险的影响的。在用例中,我们发现有四个已经有了可用的系统,并且可能会被更多的人采用。这些是“安全性”、“数据集成”、“从人类中提取有用的信息”和“现有数据存储中的人工智能支持”。

另一方面,我们已经确定了三个用例,它们不会面临关键的挑战,但在广泛采用之前需要 5 到 10 年的开发。其中包括,“提高可用性”、“自动驾驶操作(DevOps 和法规遵从性)”和“自动和自助服务集成”

最后,我们发现“业务自动化”用例虽然对大公司来说是可行的,但如果没有云 API 的支持,对中小型企业(SME)来说往往是遥不可及的。

结论

在我们的研究中,在严格评估人工智能如何影响集成领域的同时,我们确定了 11 类可以显著影响集成结果的用例。AI 有一个重要的开发者社区和丰富的工具集。许多现实生活中的人工智能用例已经证明了它们的有效性。尽管有希望,但仍有障碍。偏见和隐私问题等风险,以及模型可解释性和熟练专业人员短缺等挑战,正在限制人工智能的采用。我们的报告,人工智能将如何塑造未来的整合?详细讨论机会、风险和挑战;评估每个用例的可行性;并确定了四类准备开发的用例。

将数据科学应用于网络安全网络攻击和事件

原文:https://towardsdatascience.com/applying-data-science-to-cybersecurity-network-attacks-events-219fb6312f54?source=collection_archive---------11-----------------------

网络世界是一个需要理解的巨大概念。当时,我决定在大学期间进入网络安全领域。让我感兴趣的是理解恶意软件、网络安全、渗透测试的概念&在网络安全中真正发挥作用的加密方面。

能够保护基础设施很重要,但也很有趣。当然有编码,但我从来没有真正学会如何将代码应用到网络安全原则中。这是我接下来真正想知道的,可以扩展我在信息技术和计算机科学方面的知识。我学到了更多关于编码的知识,尤其是 Python。我涉猎了一点 Scala &我在大学期间已经有了 Sequel 和 Java 应用程序的良好基础,在新兵训练营期间学习它让我对它感觉更舒服一些。

数据科学沉浸式项目教会我如何通过 Sequel、JSON、HTML 或 web-screwing 应用程序收集数据,我在这些应用程序中清理数据&然后应用 Python 相关代码进行统计分析。然后,我能够对数据进行建模,以发现趋势、做出预测或提供建议/推荐。我想把这一点应用到我在思科 NetaCad、网络安全原则和软件开发的背景中

然后我想把这和我的网络安全背景联系起来。我决定从 Data.org 收集大量关于联邦通信委员会(FCC)的网络攻击的数据。在这篇博文中,我决定写一写我是如何将我的数据科学知识与我在现实行业中的网络安全背景联系起来的。我将提供这个项目的一些背景,一段代码&一些关于 FCC 如何像我一样更好地理解这些数据的见解。这可能对未来的情况或其他政府相关的网络安全项目有用。

据我所知,FCC 使用 CSRIC 最佳实践搜索工具,该工具允许您使用各种标准搜索 CSRIC 的最佳实践,包括网络类型、行业角色、关键字、优先级和 BP 编号。

通信安全、可靠性和互操作性委员会(CSRIC)的任务是向 FCC 提供建议,以确保通信系统的最佳安全性和可靠性,包括电信、媒体和公共安全。

CSRIC 的成员专注于一系列公共安全和国土安全相关的通信事务,包括:(1)通信系统和基础设施的可靠性和安全性,特别是移动系统;(2) 911、增强型 911 (E911)、下一代 911(ng 911);& (3)紧急警报。

CSRIC 的建议将解决有害网络事件的预防和补救、提高整体通信可靠性的最佳实践的开发、通信服务的可用性和性能以及在自然灾害、恐怖袭击、网络安全攻击或其他导致通信基础设施异常紧张的事件期间的紧急警报、在出现大范围或重大中断时通信服务的快速恢复以及通信提供商可以采取的帮助保护最终用户和服务器的步骤。

对我来说,处理这个项目的第一步是理解我需要完成什么&这个项目让我走什么样的方向。我记得我需要向 FCC 提供建议,以确保电信、媒体和公共安全领域通信系统的最佳安全性和可靠性。

在尝试这个项目时,我考虑了不同的方法。第一步是直接进入,以便更好地理解数据本身,我只关注事件的优先级&对其应用大量的机器学习分类模型。第二种方法是能够将自然语言处理技术应用于事件的描述&看看这与事件的优先级有什么关系。

有了这个,我们就可以做出预测&然后,提出更好地预防、理解或控制事件的建议。我的想法是,如果我们可以通过修复不太复杂的事件来关注更关键的事件,我们就可以节省足够的资产来进一步改善系统,以应对更复杂的事件。

需要什么:

  • Python IDE
  • 机器学习和统计软件包
  • 精通数据科学概念
  • 一些网络安全和网络相关概念的知识

我们开始吧!让我们首先从导入我们打算使用的任何包开始,我通常复制并粘贴对我以前的数据科学项目有帮助的有用模块的列表。

import pandas as pd 
import numpy as np  
import scipy as sp  
import seaborn as sns
sns.set_style('darkgrid') 
import pickle       
import regex as re  
import gensimfrom nltk.stem import WordNetLemmatizer
from nltk.tokenize import RegexpTokenizer
from nltk.stem.porter import PorterStemmer
from nltk.stem.snowball import SnowballStemmer
from nltk.corpus import stopwords
from sklearn.feature_extraction import stop_words
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizerimport matplotlib.pyplot as plt 
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler 
from sklearn.naive_bayes import MultinomialNB  
from sklearn.linear_model import LinearRegression,LogisticRegression
from sklearn import metrics
from sklearn.ensemble import RandomForestClassifier, BaggingClassifier, AdaBoostClassifier, GradientBoostingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.pipeline import Pipeline
from keras import regularizers
from keras.models import Sequential
from keras.layers import Dense, Dropoutimport warnings
warnings.filterwarnings('ignore')%matplotlib inline

然后,我们需要加载数据,并通过以下方式查看数据:

# Loads in the data into a Pandas data frame
fcc_csv = pd.read_csv('./data/CSRIC_Best_Practices.csv')
fcc_csv.head()

现在我们有了数据,我们可以探索、清理和理解这些数据。下面,我提供了一个基础数据探索性分析的功能。我们希望这样做是为了充分理解我们正在处理的数据&需要达到什么样的总体目标。

以下函数将允许我们查看任何空值、用下划线替换任何空格、重新格式化数据框索引、查看每列的数据类型、显示任何重复的数据、描述数据的统计分析并检查形状。

# Here is a function for basic exploratory data analysis:def eda(dataframe):
    # Replace any blank spaces w/ a underscore.
    dataframe.columns = dataframe.columns.str.replace(" ", "_")
    # Checks for the null values.
    print("missing values{}".format(dataframe.isnull().sum().sum()))
    # Checks the data frame range size.
    print("dataframe index: {}".format(dataframe.index))
    # Checks for data types of the columns within the data frame.
    print("dataframe types: {}".format(dataframe.dtypes))
    # Checks the shape of the data frame.
    print("dataframe shape: {}".format(dataframe.shape))
    # Gives us any statistical information of the data frame.
    print("dataframe describe: {}".format(dataframe.describe()))
    # Gives us the duplicated data of the data frame. print("duplicates{}".format(dataframe[dataframe.duplicated()].sum()))
    # A for loop that does this for every single column & their 
    # values within our data frame giving us all unique values.
    for item in dataframe:
        print(item)
        print(dataframe[item].nunique())# Let's apply this function to our entire data frame.
eda(fcc_csv)

根据这些数据,我们认为这是一个不平衡的分类问题!我们接下来需要做的是消除任何“NaN”或空值&在某种程度上平衡我们的类。根据我们的探索性数据分析,我们可以看到大多数数据在对象类型列中都有“NaN”值。我们可以用下面的函数来解决这个问题!

# Here's a function to convert NaN's in the data set to 'None' for 
# string objects.
# Just pass in the entire data frame.
def convert_str_nan(data):
    return data.astype(object).replace(np.nan, 'None', inplace = True)convert_str_nan(fcc_csv)

Checking the amount of values in the Priorities column

查看优先级列,我们有一个与对象相关的列,它将事件的严重性分为重要、非常重要和关键。对应于该优先级列的另一列将它们排序为 1-3,1 表示重要,2 表示非常重要,3 表示关键。根据优先级的不同,我们看到数据是不平衡的。我们通过重命名我们的专栏来解决这个问题,以便更好地理解,然后在我们关注高度重要和关键事件的地方进行平衡。

# Let's rename the 'Priority_(1,2,3)' column so we can utilize it.
fcc_csv.rename(columns = {
    'Priority_(1,2,3)': 'Priorities'
},
inplace = True)# Let's view the values & how the correspond to the 'Priority' 
# column.
fcc_csv['Priorities'].value_counts()# We notice that we have an unbalanced classification problem.
# Let's group the "Highly Important" (2) & "Critical" (3) aspects 
# because that's where we can make recommendations.
# Let's double check that it worked.
fcc_csv['Priorities'] = [0 if i == 1 else 1 for i in fcc_csv['Priorities']]
fcc_csv['Priorities'].value_counts()

Result of the above code after we’ve balanced the class

第一种方法(理解数据)

在下一节中,我将讨论我理解优先级列的最初方法。我很快了解到,这种方法并不是最好的,但在提出建议时,当我查看攻击的优先级时,这种方法非常有用。

我的下一步是了解哪些列与我的优先级列最符合模式和趋势。似乎所有运行良好的列都是二进制的!描述列是文本相关的&机器不喜欢处理文本对象。使用下面的代码,我们可以看到哪些列与我们的预测列最正相关&最负相关。

# Let's view the largest negative correlated columns to our 
# "Priorities" column.
largest_neg_corr_list = fcc_csv.corr()[['Priorities']].sort_values('Priorities').head(5).T.columns
largest_neg_corr_list# Let's view the largest positive correlated columns to our 
# "Priorities" column.
largest_pos_corr_list = fcc_csv.corr()[['Priorities']].sort_values('Priorities').tail(5).T.columns.drop('Priorities')
largest_pos_corr_list

Most Negatively Correlated

Most Positively Correlated

现在,我们可以开始制作我们的模型,看看我们所做的会给我们准确的预测或足够的建议信息。让我们首先从训练测试分割开始,这些相关的列作为我们的特征&我们的优先级列作为我们的预测变量。

# Let's pass in every column that is categorical into our X.
# These are the strongest & weakest correlated columns to our 
# "Priorities" variable. 
X = fcc_csv[['Network_Operator', 'Equipment_Supplier', 'Property_Manager', 'Service_Provider', 'wireline', 'wireless', 'satellite', 'Public_Safety']]
y = fcc_csv['Priorities'] # Our y is what we want to predict.# We have to train/test split the data so we can model the data on 
# our training set & test it.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 42)# We need to transpose the trains so they contain the same amount of # rows.
X = X.transpose()

既然我们已经训练测试分割了我们的特征,让我们应用网格搜索在朴素贝叶斯分类器、随机森林分类器、Adaboost/梯度增强分类器 & a Keras 神经网络上找到完全准确的最佳参数或特征!但是这些分类器模型到底意味着什么呢?

简单来说,朴素贝叶斯分类器假设一个类中特定特征的存在与任何其他特征的存在无关。让我们看看我们的数据吧!

# Instantiates the Naive Bayes classifier.
mnb = MultinomialNB()
params = {'min_samples_split':[12, 25, 40]}# Grid searches our Naive Bayes.
mnb_grid = {}
gs_mnb = GridSearchCV(mnb, param_grid = mnb_grid, cv = 3)
gs_mnb.fit(X_train, y_train)
gs_mnb.score(X_train, y_train)# Scores the Naive Bayes.
gs_mnb.score(X_test, y_test)

随机森林分类器从随机选择的训练集子集创建一组决策树,然后汇总来自不同决策树的投票,以决定测试对象的最终类别。随机森林中的每棵树都给出一个类别预测,拥有最多票数的类别成为我们模型的预测。我们来建模吧!

# Instantiates the random forest classifier.
rf = RandomForestClassifier(n_estimators = 10)# Grid searches our random forest classifier.
gs_rf = GridSearchCV(rf, param_grid = params, return_train_score = True, cv = 5)
gs_rf.fit(X_train, y_train)
gs_rf.score(X_train, y_train)# Our random forest test score.
gs_rf.score(X_test, y_test)

Graph of our Adaboost Model, it’s overfit!

AdaBoost 是自适应增强的简称。它基本上是一种用作分类器的机器学习算法。每当你有大量的数据,你想把它分成不同的类别,我们需要一个好的分类算法来做到这一点。因此有了“boosting”这个词,因为它可以提升其他算法!

scores_test = []
scores_train = []
n_estimators = []for n_est in range(30):
    ada = AdaBoostClassifier(n_estimators = n_est + 1, random_state = 42)
    ada.fit(X_train, y_train)
    n_estimators.append(n_est + 1)
    scores_test.append(ada.score(X_test, y_test))
    scores_train.append(ada.score(X_train, y_train))# Our Ada Boost score on our train set.
ada.score(X_train, y_train)# Our Ada Boost score on our test set.
ada.score(X_test, y_test)

神经网络是一组算法,大致模仿人脑,设计用于识别模式。他们通过一种机器感知、标记或聚类原始输入来解释感官数据。我们甚至可以应用正则化来解决过度拟合的问题!

Our regularized Neural Network, it’s overfit!

model_dropout = Sequential()n_input = X_train.shape[1]
n_hidden = n_inputmodel_dropout.add(Dense(n_hidden, input_dim = n_input, activation = 'relu'))
model_dropout.add(Dropout(0.5)) # refers to nodes in the first hidden layer
model_dropout.add(Dense(1, activation = 'sigmoid'))model_dropout.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics = ['acc'])history_dropout = model_dropout.fit(X_train, y_train, validation_data = (X_test, y_test), epochs = 100, batch_size = None)

The Accuracy of Our Models

这告诉我们什么?!根据训练分数和测试分数,我们可以看到我们的模型过度拟合 &不擅长预测或分析趋势。我们的模型过适合是什么意思?我们有高方差 & 低偏差高方差会导致算法对训练数据中的随机噪声建模,而不是对预期输出建模。我们仍然不能对此提出建议,因为它并没有给我们提供太多的信息!

第二种方法(自然语言处理)—最佳途径

我的第二个方法是关注描述栏。在我第一次尝试后,我想看看攻击的优先级与描述中给出的内容是如何关联的。描述栏给了我们一个简短的解释,说明发生了什么&一个建议的 FCC 兼容的解决方案,他们可以做些什么来阻止类似的事件。

为了更好地理解描述栏,我需要应用自然语言处理(NLP ),因为计算机和统计模型不喜欢处理文本和单词。但是我们可以解决这个问题!在清理数据和平衡优先级列时,我的方法是类似的,但是我应用了一些 NLP 概念来更好地理解描述、分析它、提出建议&甚至根据特定于事件的单词的出现来预测下一个事件是什么。

一些概念包括:

  • 预处理是将原始数据转换成干净数据集的技术。
  • Regex,正则表达式是一个文本字符串,允许您创建模式来帮助匹配、定位&管理文本。另一种清理文本的方法。
  • T21 是将一个单词的词形变化组合在一起的过程,这样它们就可以作为一个术语来分析。
  • 词干化是将屈折词缩减为词干、词根或词根形式的过程。
  • 计数矢量化统计词频。
  • TFIDFVectorizer 是一个词的值随着计数成比例增加,但被该词在语料库中的出现频率所抵消。

让我们从将正则表达式概念应用到已经清理过的数据开始。我们还想剥离或清除有用但在每一个描述中零星出现的常用词。

# Let's clean the data using Regex.
# Let's use regex to remove the words: service providers, equipment # suppliers, network operators, property managers, public safety
# Let's also remove any mention of any URLs.fcc_csv['Description'] = fcc_csv.Description.map(lambda x: re.sub('\s[\/]?r\/[^s]+', ' ', x))
fcc_csv['Description'] = fcc_csv.Description.map(lambda x: re.sub('http[s]?:\/\/[^\s]*', ' ', x))
fcc_csv['Description'] = fcc_csv.Description.map(lambda x: re.sub('(service providers|equipment suppliers|network operators|property managers|public safety)[s]?', ' ', x,  flags = re.I))

现在我们已经清理了我们的数据,我们应该应用一些预处理技术来更好地理解在事件的每个描述中使用的单词。

# This is a text preprocessing function that gets our data ready for # modeling & creates new columns for the 
# description text in their tokenized, lemmatized & stemmed forms. 
# This allows for easy selection of 
# different forms of the text for use in vectorization & modeling.def preprocessed_columns(dataframe = fcc_csv, 
                        column = 'Description', 
                        new_lemma_column = 'lemmatized', 
                        new_stem_column = 'stemmed',
                        new_token_column = 'tokenized',
                        regular_expression = r'\w+'): 

    tokenizer = RegexpTokenizer(regular_expression)     
    lemmatizer = WordNetLemmatizer()                     
    stemmer = PorterStemmer()                            

    lemmatized = []                                      
    stemmed = []                                         
    tokenized = []

    for i in dataframe[column]:                        
        tokens = tokenizer.tokenize(i.lower())           
        tokenized.append(tokens) lemma = [lemmatizer.lemmatize(token) for token in tokens]     
        lemmatized.append(lemma)        stems = [stemmer.stem(token) for token in tokens]            
        stemmed.append(stems)                                         

    dataframe[new_token_column] = [' '.join(i) for i in tokenized]    
    dataframe[new_lemma_column] = [' '.join(i) for i in lemmatized]   
    dataframe[new_stem_column] = [' '.join(i) for i in stemmed]   

    return dataframe

然后,我们希望对词干化、词汇化和标记化的描述词应用 countvectorize,以便控制英语中常见的停用词,我们可以使用下面的代码来实现这一点。然后我们可以看到整个数据集中最常见的单词是什么。

# Instantiate a CountVectorizer removing english stopwords, ngram 
# range of unigrams & bigrams.cv = CountVectorizer(stop_words = 'english', ngram_range = (1,2), min_df = 25, max_df = .95)# Create a dataframe of our CV transformed tokenized words
cv_df_token = pd.SparseDataFrame(cv.fit_transform(processed['tokenized']), columns = cv.get_feature_names())
cv_df_token.fillna(0, inplace = True)cv_df_token.head()

Top Word Count in the Entire Data Set

我们可以看到,弹出来的词大部分都是网络或安全相关的。我们可以利用这些信息更好地了解这些事件的范围!是网络攻击吗?它们与网络仓库有关吗?等等。

但是如果我们想要更多的信息呢?我们可以根据事件重要性的紧急程度或严重性对描述进行分组。也许这没什么严重的,所以它被列为 0(不重要)或非常糟糕被列为 1(非常重要)。我们可以使用下面基于预处理列的代码来实现这一点。然后我们可以想象最常见的真正重要的单词是什么。

# Split our data frame into really "important" & "not important" 
# columns.
# We will use the "really_important" descriptions to determine 
# severity & to give recommendations/analysis.
fcc_really_important = processed[processed['Priorities'] == 1]
fcc_not_important = processed[processed['Priorities'] == 0]print(fcc_really_important.shape)
print(fcc_not_important.shape)

Top Word Count of the Really IMPORTANT words

最后,我们可以开始对标记化的数据建模回归和分类度量。让我们从通过管道应用逻辑回归模型开始,在管道中可以应用网格搜索工具来调整我们的最佳特性或最佳参数。让我们建立我们的 X 变量,我们的特征!我们将在上面创建的经过处理的数据框的标记化列中使用单词或要素。经过处理的数据帧是一个全新的数据帧,它包含了我们的标记化、词干化和词汇化的列。

在这里,我决定将重点放在标记化的列上,因为这个特定的列在参数调优和准确性方面表现最好。为了缩短这篇博文的时间长度,我决定把重点放在符号化上,也就是效果最好的地方!让我们也对它进行测试分割。

X_1 = processed['tokenized']# We're train test splitting 3 different columns.
# These columns are the tokenized, lemmatized & stemmed from the 
# processed dataframe.
X_1_train, X_1_test, y_train, y_test = train_test_split(X_1, y, test_size = 0.3, stratify = y, random_state = 42)

现在让我们创建我们的管道,它使用网格搜索概念来寻找最佳超参数。一旦网格搜索适合(这可能需要一段时间!)我们可以从网格搜索对象中拉出各种信息和有用的对象。通常,我们会希望将几个转换器应用于一个数据集&,然后最终构建一个模型。如果您独立地完成所有这些步骤,那么在预测测试数据时,您的代码可能会很混乱。它也容易出错。幸运的是,我们将有管道

在这里,我们将应用一个逻辑模型,该模型可以考虑拉索和山脊惩罚。

你应该:

  1. 拟合并验证数据的默认逻辑回归的准确性。
  2. 对不同的正则化强度、套索和山脊惩罚进行网格研究。
  3. 将优化的逻辑回归测试集的准确性与基线准确性&默认模型进行比较。
  4. 看看找到的最佳参数。选了什么?关于我们的数据,这说明了什么?
  5. 查看优化模型的(非零,如果 Lasso 被选为最佳)系数和相关预测值。最重要的预测因素是什么?
pipe_cv = Pipeline([
    ('cv', CountVectorizer()),
    ('lr', LogisticRegression())
])params = {
    'lr__C':[0.6, 1, 1.2],
    'lr__penalty':["l1", "l2"],
    'cv__max_features':[None, 750, 1000, 1250],
    'cv__stop_words':['english', None],
    'cv__ngram_range':[(1,1), (1,4)]
}

现在,我们可以在网格搜索对象中的逻辑回归模型上应用管道。请注意正在实例化的 countvectorize 模型。我们这样做是因为我们想看看这是如何影响我们的准确性和我们与网络攻击相关的词的重要性的因素。

# Our Logistic Regression Model.
gs_lr_tokenized_cv = GridSearchCV(pipe_cv, param_grid = params, cv = 5)
gs_lr_tokenized_cv.fit(X_1_train, y_train)
gs_lr_tokenized_cv.score(X_1_train, y_train)gs_lr_tokenized_cv.score(X_1_test, y_test)

Our Improved Accuracy of our Logistic Model

那么由此可以推断出什么呢?看起来我们已经看到训练数据的模型精度大幅提高,测试数据的精度也提高了 10%。但是,车型还是过合身!但仍然做得很好!我们的最佳参数是什么?如果我们想调整未来的物流模型,我们可以使用这些信息!下面的代码将告诉我们这一点!

gs_lr_tokenized_cv.best_params_

Our BEST Hyper Parameters from our Logistic Gridsearch within the Pipeline

使用 L1 正则化技术的回归模型称为 Lasso 回归,使用 L2 的模型称为 Ridge 回归。从我们的最佳超参数,我们的模型有利于岭回归技术。现在我们想根据我们的逻辑回归做出预测&能够提出建议。我们如何继续做那件事?让我们看看与我们的特征相关联的系数,这些系数将预测最佳 y 变量的结果。

coefs = gs_lr_tokenized_cv.best_estimator_.steps[1][1].coef_
words = pd.DataFrame(zip(cv.get_feature_names(), np.exp(coefs[0])))
words = words.sort_values(1)

Predictions for Suggestions Based off Occurrence & Importance of Words

建议和结论

既然我已经完成了数据建模和分析,我现在可以向 FCC 以及任何其他计划进行类似项目的数据科学家或数据分析师提出建议。

未来的数据科学家做一个类似的项目。获取更多数据,更好的数据样本,增加/降低模型的复杂性& 正则化。这有助于解决我在这个项目中经历过的过度拟合你的数据的问题。了解不平衡分类问题。这样可以引出你解决问题的主要方向。

对于 FCC 的 CSRIC 的最佳实践,我的最佳建议是先解决简单的问题,这样它们就不会经常发生&耗尽您的资源。这可以让他们专注于更重要和复杂的事件或攻击。基于我的预测和对给定数据的分析。

简单的问题:

  • 不同的电缆
  • 彩色编码电缆
  • 仓库通风更好
  • 增加功率容量
  • 更好的硬件
  • 天线间距

中度问题:

  • 利用网络监控
  • 在可行的情况下提供安全的电气软件
  • 寻找新硬件和软件的门槛
  • 病毒防护

复杂:

  • 最大限度减少单点故障和软件故障
  • 设备管理架构
  • 安全网络/加密系统

将人工智能应用于电子竞技(PUBG)

原文:https://towardsdatascience.com/applying-data-science-to-esports-pubg-b7950330423a?source=collection_archive---------21-----------------------

我们都是玩电子游戏长大的,对吗?那么,我们如何将数据科学和数据分析应用于视频游戏呢?PlayerUnknown's Battleground 也被称为 PUBG,可以说已经彻底改变了皇室战争电子游戏领域!关于 PUBG 如何开启《皇室战争》竞技游戏模式有一个争论,其他视频游戏设计者、创造者&制造商,如&【Apex 传奇】,仅举几个例子,都复制了重新设计的&,使自己更加独特!我决定从 Kaggle 举办比赛的网站上获取数据,看看我们能否根据单个玩家的特征统计数据,找出一个人在比赛中的排名。

在 PUBG 游戏中,每场比赛最多有 100 名玩家开始(matchId)。玩家可以加入在游戏结束时(winPlacePerc)排名的队伍(groupId ),排名是基于当他们被淘汰时有多少其他队伍还活着。在游戏中,玩家可以捡起不同的弹药,救活倒下但没有被击倒的队友,驾驶车辆,游泳,跑步,射击&体验所有的后果——例如摔得太远或撞倒自己&消灭自己。

我们得到了大量匿名的 PUBG 游戏统计数据,格式化后每行包含一个玩家的赛后统计数据。数据来自各种类型的比赛:单人赛、双人赛、团队赛和定制赛;不能保证每场比赛有 100 名球员,也不能保证每组最多有 4 名球员。我们必须创建一个模型,根据球员的最终统计数据预测他们的最终排名,范围从 1(第一名)到 0(最后一名)。我创建了一个数据字典来获取更多关于数据的信息&让我们的生活更简单。

在整篇文章中,我打算提供允许我创建这样一个模型的代码——其他模型可能对其他人来说表现得更好。我的下一个目标是创造视觉效果&提供任何进一步的见解!这个项目和文章类似于我的关于爱荷华州房价的项目和文章!感兴趣的话,点击这里!

理解这篇文章需要什么:

  • 丰富的 Python 经验和知识
  • Python 统计数据包的中级知识
  • IDE
  • 熟悉数据科学、分析和统计

让我们从进口开始吧!

*import pandas as pd 
import numpy as np  
import seaborn as sns 
import matplotlib.pyplot as plt 
from sklearn.model_selection import train_test_split, GridSearchCV 
from sklearn.preprocessing import PolynomialFeatures, StandardScaler, LabelEncoderfrom sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression, LogisticRegression, LassoCV, RidgeCVfrom sklearn.ensemble import RandomForestClassifier, BaggingClassifier, AdaBoostClassifier, GradientBoostingClassifier%matplotlib inline*

接下来,我们需要导入我们的文件。在这个项目中,我们使用了两个文件。一组训练数据和一组测试数据。训练集和测试集非常相似,除了我们在训练集中缺少了一列,球员的最后落点!请记住,无论我们对训练数据集做什么,我们都必须对测试数据做什么,以保持我们的数据无偏、精确和相似。

*# Imports the csv files from Kaggle
# Files are stored locally
pubg_train = pd.read_csv('./data/pubg_train.csv')
pubg_train.head()pubg_test = pd.read_csv('./data/pubg_test.csv')
pubg_test.head()*

接下来,我们希望对数据显示的任何内容应用一些数据清理、探索性数据分析和常识。下面我写了一个简单的数据清理和探索性数据分析的函数,我将它应用于两个 csv 文件。

*# Here is a function for basic exploratory data analysis:
def eda(dataframe):
    # Replace any blank spaces w/ a underscore.
    dataframe.columns = dataframe.columns.str.replace(" ", "_")
    # Checks for the null values.
    print("missing values: {}".format(dataframe.isnull().sum().sum()))
    # Checks the data frame range size.
    print("dataframe index: {}".format(dataframe.index))
    # Checks for data types of the columns within the data frame.
    print("dataframe types: {}".format(dataframe.dtypes))
    # Checks the shape of the data frame.
    print("dataframe shape: {}".format(dataframe.shape))
    # Gives us any statistical information of the data frame.
    print("dataframe describe: {}".format(dataframe.describe()))
    # Gives us the duplicated data of the data frame. 
    print("dataframe duplicates: {}".format(dataframe[dataframe.duplicated()].sum()))

    # A for loop that does this for every single column & their values within our data frame giving us all 
        # unique values.
    for item in dataframe:
        print(item)
        print(dataframe[item].nunique())# Let's apply this function to our entire data frame.
eda(pubg_train)
eda(pubg_test)*

经过一些探索性分析,我们意识到我们有一些“NaN”或空值,由于不准确的数据、创建者的错误输入或不适用于训练数据集中的某个球员而留空。记住,我们必须对训练集和测试集做同样的事情。我们的数据非常“脏”

下面,我创建了一个函数来解决这个问题。我们可以通过删除行来删除这些值,看看这些值是否扭曲了数据,这些值是否是某种异常值,或者我们可以手动编辑和替换它们。我决定将“NaN”值转换为 0.0 浮点类型。

*# Here's a function to convert NaN's in a specific column in the data # set to 0.0 for floats.
# Just pass in the entire data frame & specify a specific column w/ a # float NaN.
def convert_float_nan(data):
    return data.replace(np.nan, 0.0, inplace = True)
convert_float_nan(pubg_train["winPlacePerc"])*

清理完数据后,我们已经清除了训练集的所有空值数据,因此它将与测试数据集相似!两者都没有空值&都有八行,但是记住训练数据集有 24 列,而测试数据集有 25 列。但是,我们还没有定下来!让我们改变位于两个数据集中的列的类型!转换类型使分析更容易,有效和正确!

*pubg_train['damageDealt'] = pubg_train['damageDealt'].astype(int)
pubg_train['longestKill'] = pubg_train['longestKill'].astype(int)
pubg_train['rideDistance'] = pubg_train['rideDistance'].astype(int)
pubg_train['swimDistance'] = pubg_train['swimDistance'].astype(int)
pubg_train['walkDistance'] = pubg_train['walkDistance'].astype(int)
pubg_train['winPlacePerc'] = pubg_train['winPlacePerc'].astype(int)pubg_test['damageDealt'] = pubg_test['damageDealt'].astype(int)
pubg_test['longestKill'] = pubg_test['longestKill'].astype(int)
pubg_test['rideDistance'] = pubg_test['rideDistance'].astype(int)
pubg_test['swimDistance'] = pubg_test['swimDistance'].astype(int)
pubg_test['walkDistance'] = pubg_test['walkDistance'].astype(int)*

既然两个集合的数据都是干净的& set,我们是否可以可视化所有列与“winPlacePerc”列的关系?这是我们希望预测的仅位于定型数据集中而不在测试数据集中的列。以下代码将完成这项工作:

*# Let's make a simple heat map on what column we're trying to 
# predict to see correlations.
plt.figure(figsize = (5,5))
sns.heatmap(np.round(pubg_train.corr()[['winPlacePerc']].sort_values('winPlacePerc'), 30), annot = True, cmap = 'viridis')*

上图显示了我们想要预测的内容&每列如何与该列正相关和负相关。某一列的接近程度&该列中的数据量如何准确地与排名第一或最后相关?这是我们的目标!让我们看看哪些列为我们提供了最强的相关性:

*# Let's view the largest negative correlated columns to our 
# "winPlacePerc" column.
largest_neg_corr_list = pubg_train.corr()[['winPlacePerc']].sort_values('winPlacePerc').head(5).T.columns
largest_neg_corr_list*

Largest Negatively Correlated Columns

*# Let's view the largest positive correlated columns to our 
# "winPlacePerc" column.
largest_pos_corr_list = pubg_train.corr()[['winPlacePerc']].sort_values('winPlacePerc').tail(5).T.columns.drop('winPlacePerc')
largest_pos_corr_list*

Largest Positively Correlated Columns

出于特征工程的目的,我们需要这样做!特征工程是机器学习算法中使用的特征(变量)的创建和操作。(集思广益或测试特征,决定要创建的特征,检查特征如何与模型配合工作,改进特征(如果需要)。我们的特征,我们指定的相关列&它们的数据有助于预测和显示关系,在这种情况下是我们试图预测的关系!

现在我们已经得到了我们的特性,让我们从训练/测试分割数据开始&然后扩展它。我们可以通过将样本数据分割成子集来执行模型验证,这也称为训练/测试分割。这是我们可以用来训练模型和测试模型的代表性数据。这可以帮助表示未来的数据,避免某些调整的过度拟合,并提高我们预测的质量。

当我们缩放数据时,我们实质上是将我们的列转换成 Z 分数。这意味着您正在转换我们的数据,使其符合特定的范围,如 0-100 或 0-1。当您使用基于测量数据点之间距离的方法时,您希望缩放数据。

*# Here we can feature load our best correlated variables.
# Our y-variable is what we want to predict.
X = pubg_train[['killPlace', 'matchDuration', 'winPoints', 'killPoints', 'rankPoints', 'damageDealt', 'weaponsAcquired', 'boosts', 'walkDistance']]
y = pubg_train['winPlacePerc'] # What's being predicted# Let's train test split our data.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 42)# Scales our data.
# Feature scaling is a method used to normalize the range of 
# independent variables or features of data. 
# In data processing, it is also known as data normalization.
ss = StandardScaler()
ss.fit(X_train)
X_train = ss.transform(X_train)
X_test = ss.transform(X_test)*

现在,我们已经完成了所有的预处理步骤,让我们开始创建我们的模型,该模型将帮助我们根据我们已经训练/测试的特性来预测胜率。对于这个项目,我决定使用逻辑回归函数,也称为 Logit 函数,因为我们能够处理带有分类标签数据的数字数据。分类标签数据是我选择的特征!

为什么是 Logit 模型?除了简单的线性回归,逻辑回归是一种替代方法。逻辑回归使用比值比的概念来计算概率。这被定义为一个事件发生的几率与它不发生的几率之比。我决定通过网格搜索来运行我的 Logit 模型,以找到最佳参数&在这个范围内,有一条优化的管道!

*# A pipeline that instantiates a tuned Logistic Regression model.
pipe_cv = Pipeline([
    ('lr', LogisticRegression())
])
# Here are our parameters we've tuned.
params = {
    'lr__C':[1.0],
    'lr__penalty':["l1"]
}# Our Logistic Regression Model ran through a Grid Search Object.
gs_lr = GridSearchCV(pipe_cv, param_grid = params, cv = 3)
gs_lr.fit(X_train, y_train)
gs_lr.score(X_train, y_train)*

这是我们基于跑步或 Logit 模型对训练/测试分割功能中的训练数据得出的分数。请记住,分割允许我们使用部分训练数据集作为测试数据集,因为整个训练数据集代表整个测试数据集!

Pipeline Gridsearch Training Score

注意我们的训练分数有多高!那太好了,如果我们的测试分数相似,那么我们就不是过度健康或不健康!更多了解过度拟合和欠拟合模型,查看我的数据科学家指南这里!这将展示如何避免过度装配&装配不足。

现在让我们给测试数据打分吧!

*# Let's run our model on the test data.
gs_lr.score(X_test, y_test)*

Pipeline Gridsearch Testing Score

我们的模型既不是过合身也不是欠合身!干得好!现在,我们对管道的最佳调整参数是什么?

*# Give's us our best parameters.
gs_lr.best_params_*

Best Parameters Based off of a Logit Model Pipeline

我们的 Logit 模型像一个套索逻辑回归特征,在调整参数中用“l1”表示!现在我们已经有了模型集,清理了数据,并发现基于这些特征预测成功率的可能性很大,我们的下一步是将它们可视化!这将在本文后面出现,所以请继续关注!

应用深度学习优化服装电子商务流程

原文:https://towardsdatascience.com/applying-deep-learning-for-fashion-e-commerce-7e9e28692172?source=collection_archive---------24-----------------------

自动选择鞋类的缩略图。

Image courtesy : https://www.myntra.com/

当我学习无监督学习方法时,我遇到了不同的聚类方法,如 KMeans,层次聚类。在学习阶段,我想在现实世界的问题上实现这种方法。此外,电子商务系统已经占据了我的心灵一段时间,了解这个系统是如何工作的非常有吸引力。所以我决定解决一个我将在本文中描述的问题。

在这篇博客中,我将分享我在为时尚电子商务(鞋类)选择缩略图的自动化过程中的经验和收获。它将涵盖以下内容:

  • 如何使用用于聚类过程的深度学习从图像生成特征
  • 如何找到 KMeans 的最佳聚类数(肘方法)
  • 选择哪种架构进行特征提取

问题陈述:

想象一下,为一家时尚电子商务公司工作,每天都能从供应商那里获得成千上万张鞋类图片。为缩略图选择正确的图像很重要,这样才能吸引用户进一步查看或购买产品。

Lace-Up shoes .

任务是从一堆鞋的图像中识别将被用作缩略图的最佳视图图像,并且还对鞋的类型进行分类。在上面的图像中,右侧图像是最好的图像,它将被用作缩略图。

W 为什么这是必要的?

  • 每个产品都有多个视图(前视图、后视图、左视图、右视图),只有少数视图有产品的信息,因此选择产品的最佳视图将是缩略图。它将自动完成某些手动完成的过程。
  • 当训练分类器来识别鞋的类型时,选择最佳视图也是有益的。通过这样做,分类器将仅从具有最多信息的视图(如前视图或侧视图)中学习特征。如果你给分类器提供描述鞋的鞋底的视图,那么它将不会学习对分类鞋的类型更重要的特征。像系带鞋一样,具有系带信息的视图将是对分类器最有用的特征,而不是鞋底信息。

数据

数据由Fynd-时尚电子商务公司提供。 CSV 文件,列名为“类”,图像 URL 指向不同的视图(5 个不同的视图)。从网址下载图片,并保存为以下格式: footweartype_id_viewid.jpg。此外,通过查看图像,view_1 将始终是鞋类的前视图也是不必要的。

数据集中总共有 6 类鞋。

Image Courtesy : Fynd . Types of Footwear

方法

在数据中,我们没有给出任何关于缩略图选择哪个视图的信息。我们只能从不同的角度来看特定的鞋子和它的类型。那么,如果数据没有用最佳视图标记,如何训练分类器呢?这类问题属于无监督学习。对于无监督学习,我们可以使用聚类等方法来标记数据。

在跳到任何非监督方法之前,有必要将问题一般化,以便方法变得简单。在观察数据集之后,我遇到了某些事情:

  • 对于系带鞋、便鞋、带扣鞋、钩环鞋、后带鞋,视图将是最重要的视图。

  • 对于 zip 类型,包含 zip 信息的视图将是最重要的视图。

现在我们已经决定了某些事情,这将概括我们的问题。现在转向无监督的方法来识别上述鞋的类型。

如何使用聚类?

现在的任务是将具有相同视图的图像聚集在一起。我决定使用 KMeans 进行聚类。要使用像 KMeans 这样的聚类算法,我们必须传递图像的某些特征。诸如形状上下文、要点、HOG、启发式等特征,并将这些特征提供给聚类算法。在可视化每种鞋类的聚类后,有一些不属于这些聚类的坏图像。

在这一切之后,我决定使用深度学习方法进行聚类。什么?怎么会?

基本思想是将图像传递给预训练的网络,然后移除模型的顶层,并将最后一层的输出传递给聚类算法。

使用预先训练的深度学习网络的好处是,在层中学习的抽象将捕捉一切,形状,模式等。所以我们不必手动从图像中提取特征。就像魔法一样。

有不同的预训练模型,如 VGG16、VGG19、ResNet50 等。为了决定选择哪种架构,我们可以使用 剪影得分 来找到最佳集群。

剪影得分是一种衡量一个聚类中的每个点与其相邻聚类中的点的接近程度的方法。这是在 k-means 聚类过程中找出 k 的最佳值的一种简洁的方法。轮廓值在[-1,1]范围内。值+1 表示样本远离其相邻聚类,而非常接近其所分配的聚类。同样,值为-1 表示该点与其相邻的簇的距离比其所分配的簇的距离更近。并且,值为 0 意味着其在两个集群之间的距离的边界处。值+1 是理想值,-1 是最不理想的值。因此,该值越高,集群配置越好。

在上图中,随着聚类数的增加,可以观察到 ResNet 的性能优于 VGG16。因为 ResNet50 更深入,它捕捉到更多的信息。

集群的可视化

从 ResNet 传递特征,并找到具有相同视图的集群。

Same Views of Hook Type Closure

Same views of Laceup Closure

Same views of Backstrap closures

model = ResNet50(weights='imagenet', include_top=**False**)# function to load a particular type of footwear . And pass the return the features from last layer**def** get_vec_footwear(footwear_dir):

    resnet50_feature_list = []
    filenames = listdir(footwear_dir)
    **for** i,fname **in** enumerate(filenames):
        **try** :
            img = image.load_img(footwear_dir+'/'+fname,target_size= (224,224))
            img_data = image.img_to_array(img)
            img_data = np.expand_dims(img_data,axis=0)
            img_data = preprocess_input(img_data)
            resnet50_feature = model.predict(img_data)
            resnet50_feature_np = np.array(resnet50_feature)
            resnet50_feature_list.append(resnet50_feature_np.flatten())

        **except** **IOError** :
            **continue**

    resnet50_feature_list_np = np.array(resnet50_feature_list)
    **return** resnet50_feature_list_np#Feature vectors from above function is passed into this function to get clusters**def** get_clusters(a,b,resnet50_feature_list_np):
    silloute_score = []
    objects = []
    cluster_errors = []
    **for** i **in** range(a,b):
        objects.append(i) 
        print(i)
        kmeans = KMeans(n_clusters=i, random_state=0, n_jobs=-1).fit(resnet50_feature_list_np)
        silloute_score.append(metrics.silhouette_score(resnet50_feature_list_np , kmeans.labels_,metric='euclidean'))
        cluster_errors.append( kmeans.inertia_ )

    **return** silloute_score , objects , cluster_errorsresnet50_feature_list_np = get_vec_footwear('lace_data_rgb')

silloute_score , objects , cluster_errors = get_clusters(2,20,resnet50_feature_list_np)

在上面的代码中,我们将目录名传递给 get_vec_footwear 函数。它返回图像的特征向量。在获得特征向量之后,它们被传递给 get_clusters 函数,该函数将特征向量传递给聚类算法。

您可以在这里找到进一步的实现:

[## amitpeshwani/鞋类-最佳视角-分类

在 GitHub 上创建一个帐户,为 amitpeshwani/鞋类最佳视角分类的发展做出贡献。

github.com](https://github.com/amitpeshwani/footwear-best-view-classification)

对于每种类型的鞋,基于轮廓得分的 肘分析 来决定最佳的聚类数。

肘方法的思想是对数据集的一系列值k(k-聚类数)运行 k 均值聚类,并对每个值 k 计算误差平方和(SSE)。然后,为每一个 k 值绘制一个上证指数的折线图。如果折线图看起来像一只手臂,那么手臂上的“肘”就是最好的 k 的值。

https://bl.ocks.org/rpgove/0060ff3b656618e9136b

在上图中,K 的最佳值是 5。在 k=5 的值之后,随着我们增加 k . ,SSE 趋向于向 0 下降,因此的目标是选择一个较小的值 k ,该值仍然具有较低的 SSE,并且肘部通常代表我们通过增加 k 开始具有递减收益的地方。

在聚类的基础上,图像被分成

  • Typeoffootwear _ bestview
  • Typeoffootwear _ nobestview

Laceup-best-views

按照上面的方法,我把每种鞋的相同视图的图片分开,保存到名为typeofootware _ best/nobestviews(上图中的 lace up _ best)的文件夹中。因此,我们为每种鞋类标注了最佳和非最佳视角的数据。现在,我们可以训练一个分类器,它不仅可以识别最佳视图,还可以对鞋的类型进行分类。将无监督学习问题转化为有监督学习问题。

在上面的图片上训练 VGG19。以下是模型的输出示例:

Laceup

Hook & Loop

最后的话

我在剪影评分的基础上使用了预先训练好的 ResNet50。resnet 的输出直接馈入聚类算法。使用肘分析找到了最佳聚类数。然后,在聚类的基础上分离图像,并用特定的视图标记每个聚类。现在有了带有鞋的类型的视图的标记信息,使用正常的 VGG 体系结构进行分类任务。进一步的 改进:我们可以使用在时尚 MNIST 数据集上训练的模型,而不是使用在 imagenet 数据集上训练的预训练 resnet,因为它将捕获鞋类的形状和纹理的更多信息,并使用该模型进行聚类。

希望本文概述了我解决这个特殊问题的实现。请随意纠正我的实现。

感谢阅读,

艾米特。

想聊天?在Linkedin上找我。

我的一些有趣的作品:

[## amitpeshwani/电影推荐案例研究

在 GitHub 上创建一个帐户,为 amitpeshwani/电影推荐案例研究的发展做出贡献。

github.com](https://github.com/amitpeshwani/Movie-Recommendation-Casestudy) [## amitpeshwani/NLP-亚马逊-食品-评论

在 GitHub 上创建一个帐户,为 amitpeshwani/NLP-Amazon-Food-Reviews 的发展做出贡献。

github.com](https://github.com/amitpeshwani/NLP-Amazon-Food-Reviews)

在 Java 中应用 NLP,全部来自命令行

原文:https://towardsdatascience.com/applying-nlp-in-java-all-from-the-command-line-1225dd591e80?source=collection_archive---------27-----------------------

Image source by Hannah Wright

介绍

我们都知道通过浏览器工作的机器学习工具和云服务,它们为我们提供了一个界面,我们可以使用它来执行日常数据分析、模型训练和评估以及其他不同程度的效率任务。

但是,如果您想在本地机器或组织中可用的基础设施上完成这些任务,您会怎么做呢?而且,如果这些可用的资源不能满足完成体面的端到端数据科学或机器学习任务的先决条件。这时,访问云提供商不可知的深度学习管理环境,如 Valohai 会有所帮助。此外,我们将使用所有人都可以使用的 自由层

Create a free account

我们将执行构建 Java 应用程序的任务,然后使用它训练和评估 NLP 模型,我们将从命令行界面完成所有这些工作,减少与可用 web 界面的交互,基本上这将是一个端到端的过程,一直到训练、保存和评估 NLP 模型。我们不需要太担心设置、配置或管理任何环境。

目的或目标

在这篇文章中,我们将学习做一系列的事情,涵盖不同层次的抽象(没有特定的顺序):

  • 如何在本地机器上构建和运行 NLP 模型?
  • 如何在云上构建和运行 NLP 模型?
  • 如何构建运行在 CPU 或 GPU 上的 NLP Java 应用?
  • 大多数例子都不是基于 Java 的,更不用说基于 Java 的了
  • 大多数例子都是基于 CPU 的,很少是基于 GPU 的
  • 如何根据资源(即 GPU)的存在与否来执行上述操作?
  • 如何为 Java 搭建一个 CUDA docker 容器?
  • 如何从命令行完成以上所有工作?
  • 通过单独的命令
  • 通过 shell 脚本

我们需要什么,如何需要?

以下是我们开始行动所需要的:

  • 可以在任何操作系统上构建和运行的 Java 应用程序
  • 允许连接到远程云服务的 CLI 工具
  • 管理上述所有内容的 shell 脚本和代码配置

一旦我们明确了我们的目标和需求,这个任务的如何部分就不难了,我们将在接下来的章节中展开。

面向 Java、DL4J 和 Valohai 的 NLP

面向 Java 的 NLP:DL4J

我们在 GitHub 上为你捕获了这篇文章所需的所有代码和说明。以下是您熟悉该项目的步骤:

快速启动

为了快速开始,我们只需要做这些事情:

  • 在https://valohai.com开户,见https://app.valohai.com/accounts/signup/
  • 在你的本地机器上安装 Valohai CLI
  • 克隆回购https://github.com/valohai/dl4j-nlp-cuda-example/
$ git clone https://github.com/valohai/dl4j-nlp-cuda-example/
$ cd dl4j-nlp-cuda-example
  • 使用 Valohai CLI 工具创建一个 Valohai 项目,并为其命名
$ vh project create
  • 在设置页面(https://app . valo hai . com/p/[your-user-id]/dl4j-NLP-cuda-example/Settings/Repository/)的存储库选项卡上,将您的 Valohai 项目与 GitHub repohttps://github.com/valohai/dl4j-nlp-cuda-example/链接起来
$ vh project open### Go to the Settings page > Repository tab and update the git repo address with https://github.com/valohai/dl4j-nlp-cuda-example/
  • 用来自 git repo 的最新提交更新 Valohai 项目
$ vh project fetch

现在,您已经准备好开始使用从命令行执行机器学习任务的能力了。

参见自述文件 中的 高级安装和设置部分,了解我们需要在您的系统上安装和配置什么,以便在您的本地机器上或 Docker 容器中运行应用程序和实验——目前这不是这篇文章所必需的,但您可以在以后尝试。

关于 valohai.yaml

您可能已经注意到,我们在 git repo 中有一个 valohai.yaml 文件,我们的 valohai.yaml 文件包含几个您可以使用的步骤,我们已经按它们的名称登记了它们,我们将在运行我们的步骤时使用它们:

  • build-cpu-gpu-uberjar :在 Valohai 上构建我们的 Uber jar(CPU 和 gpu 两个版本)
  • train-cpu-linux :在 Valohai 上使用 uber jar 的 cpu 版本运行 NLP 训练
  • train-gpu-linux :在 Valohai 上使用 gpu 版本的 uber jar 运行 NLP 训练
  • evaluate-model-linux :从上述 train-* 执行步骤之一评估经过训练的 NLP 模型
  • 了解您的 GPU:在任何实例上运行为了收集该实例上与 GPU/Nvidia 相关的详细信息,我们对上面的其他步骤(构建和运行步骤)运行相同的脚本

从命令行构建 Java 应用程序

假设您已经设置好了,我们将从在命令提示符下在 Valohai 平台上构建 Java 应用程序开始,这就像运行两个命令之一一样简单:

$ vh exec run build-cpu-gpu-uberjar [--adhoc]

### Run `vh exec run --help` to find out more about this command

您将会看到一个执行计数器的提示,它不是一个数字:

<--snipped-->
😼  Success! Execution #1 created. See https://app.valohai.com/p/valohai/dl4j-nlp-cuda-example/execution/016dfef8-3a72-22d4-3d9b-7f992e6ac94d/

注意:仅当您没有使用 git repo 设置您的valo hai项目或者有未保存的提交并且想要在确定配置之前进行试验时,才使用 *--adhoc*

您可以通过以下方式观看处决过程:

$ vh watch 1

### the parameter 1 is the counter returned by the `vh exec run build-cpu-gpu-uberjar` operation above, it is the index to refer to that execution run

您可以看到,当执行开始时,我们或者在等待分配实例,或者控制台消息在屏幕上移动。你也可以通过网络界面看到同样的内容。

注意:实例的可用性取决于它们的受欢迎程度以及您对它们的剩余配额,如果它们最近被使用过,则它们更有可能是下一个可用的。

一旦该步骤完成,您可以看到它产生了一些工件,在 Valohai 术语中称为输出,我们可以通过以下方式看到它们:

$ vh outputs 1

### Run `vh outputs --help` to find out more about this command

在接下来的步骤中,我们需要类似于datum://[....some sha like notation...]的 URL。您可以看到,我们有一个日志文件,其中捕获了关于正在运行的实例的 GPU 相关信息,您可以通过以下方式下载该文件:

$ vh outputs --download . --filter *.logs 1

### Run `vh outputs --help` to find out more about this command

从命令行运行 CPU/GPU 的 NLP 训练过程

我们将使用构建的工件,即用于 CPU 和 GPU 后端的 uber jars 来运行我们的培训流程:

### Running the CPU uberjar
$ vh exec run train-cpu-linux --cpu-linux-uberjar=datum://016dff00-43b7-b599-0e85-23a16749146e [--adhoc]

### Running the GPU uberjar
$ vh exec run train-gpu-linux --gpu-linux-uberjar=datum://016dff00-2095-4df7-5d9e-02cb7cd009bb [--adhoc]

### Note these datum:// link will vary in your case
### Run `vh exec run train-cpu-linux --help` to get more details on its usage

注:看看 Valohai CLI docs 的 输入,看看如何编写如上的命令。

如果我们喜欢,我们可以观看这个过程,但它可能会很长,所以我们可以切换到另一个任务。

上面的执行运行结束时,将模型保存到${VH_OUTPUTS}文件夹中,使其能够被 Valohai 归档。型号名称后面有后缀,以记录它们是如何生产的。

在我们构建、训练或评估步骤的任何时候,我们都可以通过这样做来停止正在进行的执行(排队或运行):

$ vh stop 3
(Resolved stop to execution stop.)
⌛   Stopping #3...
=>   {"message":"Stop signal sent"}
😁  Success! Done.

成功训练后下载保存的模型

我们可以通过计数器号查询执行的outputs,并使用以下命令下载:

$ vh outputs 2
$ vh outputs --download . --filter Cnn*.pb  2

看你 如何在你的本地机器 上评估下载的模型,既有由CPUGPU创建的模型基于进程(各自的妖孽 jars)。只需将下载模型的名称作为参数传递给 提供的 runner shell 脚本

评估来自先前训练执行的保存的 NLP 模型

### Running the CPU uberjar and evaluating the CPU-verion of the model
$ vh exec run evaluate-model-linux --uber-jar=datum://016dff00-43b7-b599-0e85-23a16749146e --model=datum://016dff2a-a0d4-3e63-d8da-6a61a96a7ba6 [--adhoc]

### Running the GPU uberjar and evaluating the GPU-verion of the model
$ vh exec run evaluate-model-linux --uber-jar=datum://016dff00-2095-4df7-5d9e-02cb7cd009bb --model=datum://016dff2a-a0d4-3e63-d8da-6a61a96a7ba6 [--adhoc]

### Note these datum:// link will vary in your case
### Run `vh exec run train-cpu-linux --help` to get more details on its usage

在模型评估结束时,我们得到了下面的模型评估指标和在模型上运行测试集后的混淆矩阵:

注: 源代码 以行内注释的形式包含了各阶段 ML 和 NLP 相关的解释。

捕获关于 Nvidia 的 GPU 和 CUDA 驱动程序的环境信息

此步骤与在云上构建和运行 Java 应用程序以及使用客户端工具远程控制和查看它的整个过程无关,尽管能够了解我们在何种系统上运行培训是有用的,特别是对于培训的 GPU 方面:

$ vh exec run know-your-gpus [--adhoc]

### Run `vh exec run --help` to get more details on its usage

记录你的实验

  • 在写这篇文章的时候,我做了几个实验,并以一种有效的方式跟踪成功和失败的实验,我能够使用 Valohai 的版本控制工具
  • 过滤执行
  • 通过“令牌”搜索具体执行
  • 重新运行成功和失败的执行
  • 确认执行是成功的,失败的原因是正确的
  • 另外,在下面的 Valohai 平台上检查数据目录和数据来源是我的项目的一个例子(寻找跟踪按钮):

比较基于 CPU 和 GPU 的进程

我们可以从以下方面讨论基于 CPU 和 GPU 的进程之间的比较:

  • 应用程序构建性能
  • 模型训练速度
  • 模型评估准确性

但是我们不会在这篇文章中讨论这些话题,尽管你可以获得你需要的指标,如果你想进一步研究的话。

必要的配置文件和 shells 脚本

所有必要的脚本都可以在 GitHub repo 上找到,它们可以在:

  • 项目的根文件夹
  • docker 文件夹
  • 资源-存档文件夹

也请看看 README.md 文件,了解更多关于它们的用法和其他我们在这篇文章中没有提到的信息。

瓦罗海——编排

如果我们注意到上述所有任务都是通过一些不同抽象层次的工具来编排的:

  • docker 管理基础设施和平台级配置以及版本控制管理
  • java 能够在任何选择的平台上运行我们的应用
  • shell 脚本能够以平台无关的方式再次运行构建和执行命令,并且能够在 MacOSX 上的 GPU 等资源缺失时进行例外处理
  • 客户端工具,用于连接远程云服务,即 Valohai CLI ,并查看、控制执行和下载最终结果

您正在利用可用于完成各种数据和机器学习任务的工具和技术,从一个点协调您的任务。

Image source by Mark Rasmuson

结论

我们已经看到 NLP 是一项消耗资源的任务,拥有正确的方法和工具肯定会有所帮助。来自 Skymind 的 DeepLearning4J 库和 Valohai 平台再次为我们服务。感谢两个平台的创造者。此外,我们可以看到这篇文章强调的以下好处(以及更多)。

利益

我们通过做上述事情获得了很多东西:

  • 不必担心硬件和/或软件配置和版本控制管理— docker 容器 FTW
  • 能够运行手动一次性构建、培训和评估任务— Valohai CLI 工具 FTW
  • 让您的团队定期自动执行任务,以便能够在远程云基础架构上运行任务— 基础架构即代码 FTW
  • 克服旧的或缓慢的机器或无法访问板载 GPU 的 Mac 的限制— 支持 CUDA 的 docker 映像脚本 FTW
  • 克服本地或服务器基础设施上没有足够资源的情况,并且仍然能够运行需要高吞吐量和高性能环境的实验——与云提供商无关的平台,即valo hai environmentsFTW
  • 运行任务,而不必等待任务完成,并且能够以经济高效的方式在远程资源上同时并行运行多个任务,这是一个与云提供商无关的平台,即valo hai CLItool FTW
  • 远程查看、控制配置和执行,甚至在成功执行后下载最终结果——一个与云提供商无关的平台,即 Valohai CLI 工具 FTW
  • 和许多其他你会发现自己

建议

  • 使用提供的支持 CUDA 的 docker 容器:强烈建议不要在本地机器(基于 Linux 或 Windows)上安装 Nvidia 驱动程序或 CUDA 或 cuDNN 暂时搁置,留待以后试验
  • 使用提供的 shell 脚本和配置文件:尽量不要执行手动 CLI 命令,而是使用 shell 脚本来自动执行重复的任务,前提是示例是一个很好的起点,并在此基础上更进一步
  • 尝试从提供的资源中学习尽可能多的:关于 GPU、CUDA、cuDNN,并寻找更多(参见帖子底部的资源部分)
  • 使用版本控制和基础设施即代码系统:git 和 valohai.yaml 就是很好的例子

在做上述所有事情时,我感到非常高效,我的时间和资源得到了有效利用,最重要的是,我可以与他人分享,每个人都可以直接重用所有这些工作——只需克隆回购和就可以了

我们没有提到的,也可能是一个很好的话题,就是在未来的帖子中提到的瓦罗海管道!

资源

  • dl4j-NLP-cuda-GitHub 上的示例项目
  • 在 docker Hub 上启用 CUDA 的 Docker 容器(使用最新标签: v0.5 )
  • GPU,Nvidia,CUDA 和 cuDNN
  • 牛逼的 AI/ML/DL 资源
  • Java AI/ML/DL 资源
  • 深度学习和 DL4J 资源
  • 厉害了 AI/ML/DL: NLP 资源
  • DL4J NLP 资源
  • 语言处理
  • 用于 GPU 和 CPU 的 ND4J 后端
  • Vocab 缓存如何工作
  • Word2Vec,Doc2vec & GloVe:用于自然语言处理的神经单词嵌入
  • 深度学习中的 Doc2Vec 或段落向量 4j
  • 句子迭代器
  • 什么是标记化?
  • 例子
  • https://github . com/eclipse/deep learning 4j-examples/tree/master/dl4j-examples
  • https://github . com/eclipse/deep learning 4j/tree/master/deep learning 4j/deep learning 4j-NLP-parent

瓦罗海资源

  • 瓦罗海 | 文档 | 博客 | GitHub | 视频 | 展柜 | 关于瓦罗海 | 懈怠|@瓦罗海
  • 在文档中搜索任何主题
  • 关于如何使用 Valohai CLI 工具的博文:【1】|【2】
  • 自定义 Docker 图像

其他资源

  • 牛逼的 Graal|graalvm.org

其他相关岗位

  • 如何在 Valohai 平台上做 Java 的深度学习?
  • 关于如何使用 Valohai CLI 工具的博文:【1】|【2】

最初发表于【https://blog.valohai.com】

在数据科学中应用产品方法

原文:https://towardsdatascience.com/applying-product-methodologies-in-data-science-a13aac70de0e?source=collection_archive---------17-----------------------

Photo by Stefan C. Asafti on Unsplash

什么是伟大的数据驱动产品?花式模特?开创性的想法?事实是,秘方通常在于成功实施产品方法论。

在这篇文章中,我回顾了最近的一次黑客马拉松经历,使用了最小可行产品、风险假设和峰值的精益和敏捷方法概念。我探索了这些方法如何帮助团队快速识别用例,映射所设想的解决方案的风险和复杂性,并快速迭代到可发布的产品。

GitHub 代码可用此处

黑客马拉松式的戏弄

"世界上哪些地方发生了侵犯人权的行为,发生了哪些类型的侵犯人权行为?"

这是在最近与微软的 AI for Good 倡议联合举办的黑客马拉松中,发给洞察数据科学研究员的一份不那么谦虚的简报。我是西雅图团队的一员,最初是由一屋子的博士组成的,他们摇着头,嘀咕着资源、范围,以及这份简报甚至是一个有效的研究问题的前提。我们勇往直前,走了很远,最终成为向微软展示的两个决赛团队之一。

我们的工作分析了美国国务院关于各国人权状况的年度报告,该报告每年为全球约 160 个国家发布。我们使用了一种量化评分方法,旨在总结每个人权领域的国家表现(使用来自 Cingranelli-Richards (CIRI)人权数据项目的数据和方法)。然后,我们制作了一个仪表板,显示(1)侵犯人权的类型如何在各国聚集,(2)它们与宏观经济和发展指标的关系,(3)国务院报告中通常与这些聚集相关的关键词。

Final output of the Seattle hackathon team: credit to Kyle Chezic for data vis code

这是我们的第一次黑客马拉松。我为我们的团队和我们所做的工作感到非常自豪。然而,评委的反馈给我的印象是,虽然我们使用的方法和模型显示了强大的技术能力,但我们有时很难清楚地讲述我们做了什么以及为什么做。从那以后,我开始思考如何将产品思维应用到数据科学项目中,说实话,这往往会在展示技术实力的热潮中迷失。

医生和数据科学

Insight 是一项博士后培训奖学金,旨在弥合学术界和数据科学之间的差距。该项目的职权范围确保其组织者特别乐于将博士们置于他们过去的学术应对策略痛苦地死去的境地。作为一个物种,我们生来就不具备快速切入问题核心,理解解决方案的受益者,并在两者之间画出最短路线的能力。更好的做法是,在接下来的一年里仔细提炼研究问题……在接下来的四年左右时间里,在埋在付费墙后面的期刊上发表大量警告性的答案。

需要澄清的是,我不想加入数据科学博客的活跃交易,这些博客胜利地痛斥学术界。博士成为优秀的数据科学家是因为他们受过科学训练,而不是尽管如此。然而,从学术界向科技行业的转变包括决定在旅途中带什么工具,以及哪些工具应该亲切地存放在阁楼上“以备后用”,与面包机、攀岩用具和其他过去雄心的遗物放在一起。

学术研究思维必须进入阁楼,特别是通过对知识主体的潜在贡献来评估研究问题价值的本能,以及相应的信念,即只有在同行评议的火焰中锻造的深入方法才能通过检验。要保留的,是理解领域知识是必不可少的;不管你的代码和数学有多好,如果你不理解你正在建模的系统,以及你自己的偏见的影响,你仍然在黑暗中徘徊。

从研究项目到产品开发

那么,从微软的反馈中我们能学到什么呢?嗯,一个评论指出用例不清楚。谁在使用这个产品,我们为他们解决了什么问题?第二是我们的产品方法不够清晰。我们需要讲述一个更好的关于特性优先级的故事,以及我们如何分配时间来开发它们。

定义用例

回想起来,我们心中的用例是建立在微软已经与联合国人权事务高级专员办事处(人权高专办)完成的一些工作的基础上的。总之,微软和人权高专办举行了一次联合构思会议,以确定人权高专办工作人员真正需要的是什么。其成果是 RightsView,实质上是一个关于世界各地新出现和正在发生的侵犯人权行为的实时信息仪表板。研讨会引用的一段话表明,人权高专办想要仪表板;

“对潜在的、新出现的或正在发生的危机提出明确的人权观点,并通过联合国其他部门和国际社会的更广泛参与,对这些危机作出适当的反应。”

会议还制作了仪表板模型的草图,这是决定产品开发方向的有用起点。

Product Vision: ‘The Right(s)View’, a dashboard for human rights monitoring. Source:https://news.microsoft.com/features/technology-helps-un-advance-protection-human-rights-new-ways/

MVP 方法

给定一个经过充分研究的用户和用例,任务就变成了描述该产品的功能,并确定开发的当务之急。这样做的主要方法是开发最小可行产品(MVP)。这种方法规定识别满足早期用户的最小功能集,尽快发布这些功能,并通过建立成功和整合用户反馈来迭代产品。

看看 RightsView 仪表板的例子,首先映入我眼帘的是,这本质上是一个“从消防水管喝水”的问题;我们试图提供一种服务,它吸收大量具有高度可变性和噪声的非结构化数据,并向用户返回结构化、相关、简洁和可预测的信息,从而引导或支持他们采取行动。这种服务中潜在功能的深度是令人生畏的,我们可以将它描述为一种多阶段的方法,在这种方法中,我们越来越接近“结构化、相关、简洁和可预测”的最终目标(见下图)。)

When drinking from the firehose, use a funnel.

从 MVP 的角度来看,我们可能会问,帮助用户消化所有这些数据的最小功能是什么?我认为这是摄取所有非结构化数据并以某种方式将其转换为分类和地理定位事件的第一步,并结合结构化数据的表示层(最有可能是地图仪表盘)。)

Prioritized MVP functionality

应该注意的是,MVP 方法经常被指责为落入了削减产品的陷阱,以至于最初的发布有些琐碎,用途有限。因此,作为一个独立的产品,这种功能的例子值得在市场上寻找。

在公共非结构化数据的事件映射的情况下,实际上有一个相当健康的市场。例如,武装冲突地点&事件数据项目 ( ACLED )就非常接近这第一步。然而,其数据依赖于研究人员手动编码提交给网站的非结构化报告。虽然这使它成为一个更值得信赖的数据来源和记者的最爱(例如卫报经常使用其数据),但其手动方式使其成为一个耗时和昂贵的产品。

The ACLED uses a mostly manual approach to codifying events data

另一个很好的例子是关于事件、语言和语气的全球数据库(GDELT),它代表了将公共媒体源解析为事件数据的过程完全自动化的尝试。该项目的创始人 Philip Schrodt 在 2011 年的一篇论文中概述了生成该数据集的必要步骤,该数据集现在可供任何人在这里使用。虽然 GDELT 几乎过于庞大,无法适用于正在发生何种类型的侵犯人权行为以及发生在何处的问题,但它确实表明,事件数据生产确实是它自己的研究领域,在政策分析和社会学方面拥有广泛的用户基础。

GDELT is an example of fully automated event detection

确定了一个 MVP,并从 Schrodt 的 2011 年的论文中概述的步骤开始,我选择进行一些我自己的进一步工作,看看工作的 MVP 迭代会是什么样子。有很多中型文章发布了文本分类程序的一步一步的过程,所以如果你感兴趣的话,我将只提供一个简短的概要和一个到 github 项目的链接。

MVP 从国务院 2015 年至 2018 年的年度人权国家中摘抄了文本。每年涵盖约 160 个国家,每份报告约 10,000 字,分为以下几节:

  • 政府腐败和缺乏透明度
  • 歧视、社会虐待和人口贩运
  • 尊重公民自由
  • 尊重人的完整性
  • 工人权利
  • 参与政治进程的自由

每个句子都由它出现的部分标记,然后形成标记的训练数据。在进行一些引导重采样以解决类别不平衡之后,数据被清理、矢量化并用于训练支持向量机。然后,这被用作从各种 RSS 提要中解析的新闻提要的分类算法。

同时,我使用自然语言工具包(NLTK)对每个新闻故事进行实体检测,特别是搜索地名。在找到一个名字的地方,这个名字被传递给谷歌地图的 API,以便对这个故事进行地理定位。结果存储在 pandas 数据框中,并使用 Tableau 可视化。

Outline of the process for event coding RSS newsfeeds

其结果是我刚刚调查的现有方法的基本版本,但特别关注新闻报道中报道的侵犯人权行为。在训练中,该模型在 6 个类别中实现了 76%的准确率,当应用于 RSS 提要时,这一准确率下降到 67%。

Demo of MVP for human rights events in RSS feeds

显然,这是一个比我们团队采用的方法简单得多的结果。但是有没有好一点呢?我们的时间是否应该更好地花在改进产品的“第一步”上,或者我们探索更大范围的功能是否正确?要回答这个问题,调动第二种产品开发方法是有帮助的…

最危险的假设方法

一个 MVP 用一个清晰的、线性的路径来诱惑一个优化的解决方案。最危险的假设测试把重点放在学习上…

从这个角度来看,MVP 部分中概述的漏斗现在可以被认为是关于什么可以做什么不可以做的风险越来越大的假设,特别是在分配的时间框架内。

Taking a Risky Assumption perspective means explicitly acknowledging the scale and risk of the challenge

再说一次,在评估什么是可能的,什么是不可能的时候,做一些市场调查是值得的。事实证明,预测国家支持的犯罪,特别是暴力的爆发的领域已经被几个团体尝试过了。例如,早期预警项目宣称自己是第一个此类公共系统,旨在“关注那些尚未发生大规模暴行,但这种暴力风险很高的国家。”

The Early Warning Project attempts to highlight countries ‘at risk’ of mass killings

我首先注意到的是该项目的发言人强调它是而不是预测模型的谨慎。吉尔·萨维特是主持这个项目的美国大屠杀纪念馆的馆长;

“我们没有精确预测。这不是这个工具的目的,”Savitt 说。“我们正在做的是试图提醒政策制定者,这是一种恐怖发生的时机已经成熟的情况,并给他们一个警告,即可以采取行动来避免这种情况。”

类似的模型似乎在私营国防和安全部门略显模糊的水域中运行,它们的设计师显然不羞于预测它们的性能。例如,洛克希德·马丁公司宣传其综合危机预警系统(ICEWS)有 80%的准确率可以预测全球危机。这些“危机”实际上是什么的细节,或者如何测量准确性的任何意义都没有给出…

因此,看来我们的产品中确实存在一些有风险的假设,最值得注意的是,我们可以发现侵犯人权行为和社会经济指标之间的任何相关性,甚至可以预测人权表现随时间的变化。

探索有风险的假设和代码峰值的概念

我们的团队花了大量的时间来探索不同的方法,从描述到预测我们的数据,并在这个过程中消除了相当多的方法不起作用。这就是风险假设方法的本质:直接测试项目的核心假设,而不是从最简单/最少的元素开始,然后碰壁。正如一个描述所说,风险假设方法的关键是:

…快速、小型测试。为了检验你最大的假设,你能做的最小实验是什么?

当这些测试是以编写一些框架代码的形式来测试一个想法是否“有腿”,就像我们的情况一样,那么这个测试也可以被描述为一个尖峰。简而言之,尖峰是一个从极限编程(XP)产品开发学派中出现的术语。它被描述为一个开放式的,但理想情况下简短而集中的编码练习,旨在测试一个假设。换个说法;

“我们能编写的最简单的程序是什么,能让我们相信我们是在正确的轨道上?”⁴

回顾我们团队应对这一挑战的方式,识别风险假设的模型,结合使用尖峰来测试它们,是我们使用的直观方法。我们的团队分为四大任务,每个任务侧重于不同的假设和尖峰任务:

Risky Assumptions can be tested using Spikes

结果喜忧参半。我们找到了一个很好的方法来将结构化的文本转化为每个人权类别的“分数”,我们还找到了一个方法来将国家分组为不同类型的人权概况,我们至少开始探索社会经济变量在形成这些分组中的作用。预测,多少可以预见,是不可能的。

并列比较

在使用了 MVP 和最危险假设方法来描绘出产品是如何开发的之后,我们现在可以看看每种方法的结果,并反思其优缺点。

短期与长期风险

对我来说,一个收获是 MVP 方法似乎可以减轻短期风险,而处理风险最大的假设需要长远眼光。有了 MVP,你也许更有可能得到满足最少用户需求的东西。然而,你的路线图可能会掉下悬崖,因为你实际上试图做的事情——预测人权侵犯——最终可能无法实现。

管理速度

对于黑客马拉松来说,这是一个特别重要的问题,因为产品结果预计在几周之内就会出来。通常情况下,一个 MVP 将由一个复杂性和模糊性较低的用户故事组成,这样你就有更好的机会规划出需要多长时间。在精益方法中处理风险最大的假设本质上更具探索性,因此您需要更加积极地为每个代码峰值分配严格的时间余量。

功能膨胀

MVP 方法可以帮助你专注于一个单一的特性并抓住它。因为黑客马拉松是一场竞赛,所以我们不得不在我们最危险的假设中包含每个代码峰值的结果。因此,我们最终获得了大量的功能,展示了我们做了多少工作,但却淹没了微软的评委,以及潜在的未来用户。

感谢

非常感谢所有为我们的成功做出贡献的队友。请务必查看他们的个人资料:

普里西拉·艾迪森

泰勒·布莱儿

凯尔·切齐克

科林·迪特里希

斯蒂芬妮·李

玛丽·萨尔米

  1. https://news . Microsoft . com/features/technology-helps-un-advance-protection-human-rights-new-ways/
  2. https://hacker noon . com/the-MVP-is-dead-long-live-the-rat-233 D5 d 16 ab 02
  3. https://www . NPR . org/sections/goatsandsoda/2018/12/20/675582639/is-种族灭绝-可预测-研究者-说-绝对
  4. http://agiledictionary.com/209/spike/

通用机器学习工作流

原文:https://towardsdatascience.com/applying-the-universal-machine-learning-workflow-to-the-uci-mushroom-dataset-1939442d44e7?source=collection_archive---------12-----------------------

Photo by Phoenix Han on Unsplash

一个将弗朗索瓦·乔莱的通用机器学习工作流程应用于 UCI 蘑菇数据集

W e 将使用来自 UCI 的机器学习库的蘑菇数据集来执行我们的演示。本书面向至少对 Python 基础有基本了解并有一些机器学习经验的读者。也就是说,我将为门外汉提供大量支持来源的链接,以便任何人都可以利用所提供的信息。

在我们开始之前,我想感谢我的 Lambdonian 同事 Ned H 对这篇文章的所有帮助。

通用机器学习工作流

  1. 定义问题并组装数据集
  2. 选择衡量成功的标准
  3. 决定评估协议
  4. 准备数据
  5. 开发一个比基线做得更好的模型
  6. 开发一个过度拟合的模型
  7. 正则化模型并调整其超参数

1.定义问题并组装数据集

简单地说,我们的问题是把蘑菇分为食用和有毒两类。我们得到了一个包含 23 个特征的数据集,其中包括蘑菇的类别(可食用或有毒)。

根据数据信息文件中列出的特性,我们可以为数据集创建一个列名列表。

column_names = ['class',
                'cap-shape',
                'cap-surface',
                'cap-color',
                'bruises?',
                'odor',
                'gill-attachment',
                'gill-spacing',
                'gill-size',
                'gill-color',
                'stalk-shape',
                'stalk-root',
                'stalk-surface-above-ring',
                'stalk-surface-below-ring',
                'stalk-color-above-ring',
                'stalk-color-below-ring',
                'veil-type',
                'veil-color',
                'ring-number',
                'ring-type',
                'spore-print-color',
                'population',
                'habitat']

让我们导入数据集,并从。数据文件使用[pd.read_csv()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_csv.html)

import pandas as pdurl = '[https://archive.ics.uci.edu/ml/machine-learning-databases/mushroom/agaricus-lepiota.data'](https://archive.ics.uci.edu/ml/machine-learning-databases/mushroom/agaricus-lepiota.data')mushrooms = pd.read_csv(url, header=None, names=column_names)

2.选择衡量成功的标准

鉴于我们问题的性质;分类蘑菇是否有毒,我们将使用精度作为我们成功的衡量标准。精度是分类器不将有毒蘑菇标记为可食用蘑菇的能力。我们宁愿人们丢弃我们的模型归类为有毒的可食用蘑菇,而不是食用我们的分类器标记为可食用的有毒蘑菇。

from sklearn.metrics import precision_score

3.决定评估协议

我们将使用 10 重交叉验证来评估我们的模型。虽然一个简单的拒绝验证集可能就足够了,但我怀疑它的可行性,因为我们有大约 8000 个样本。

from sklearn.model_selection import train_test_split, cross_validate

首先让我们把数据分成一个特征矩阵(X)和一个目标向量(y)。我们将使用[OneHotEncoder](http://contrib.scikit-learn.org/categorical-encoding/onehot.html)来编码我们的分类变量。

import category_encoders as ce#Drop target feature
X = mushrooms.drop(columns='class') #Encode categorical features
X = ce.OneHotEncoder(use_cat_names=True).fit_transform(X)

y = mushrooms['class'].replace({'p':0, 'e':1})print('Feature matrix size:',X.shape)
print('Target vector size:',len(y))____________________________________________________________________Feature matrix size: (8124, 117) Target vector size: 8124

接下来,我们将把数据分成训练集和测试集。

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=.2, stratify=y)print('Training feature matrix size:',X_train.shape)
print('Training target vector size:',y_train.shape)
print('Test feature matrix size:',X_test.shape)
print('Test target vector size:',y_test.shape)____________________________________________________________________Training feature matrix size: (6499, 117) 
Training target vector size: (6499,) 
Test feature matrix size: (1625, 117) 
Test target vector size: (1625,)

4.准备数据

我们几乎准备好开始训练模型,但是首先我们应该探索我们的数据,熟悉它的特征,并格式化它,以便它可以输入到我们的模型中。

我们可以使用.dtypes().columns.shape来检查我们的数据集,但是 Pandas 提供了一个[.info](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.info.html)功能,允许我们在一个地方查看所有这些信息。

print(mushrooms.info())____________________________________________________________________<class 'pandas.core.frame.DataFrame'> 
RangeIndex: 8124 entries, 0 to 8123
Data columns (total 23 columns):
class                       8124 non-null object
cap-shape                   8124 non-null object 
cap-surface                 8124 non-null object 
cap-color                   8124 non-null object 
bruises?                    8124 non-null object 
odor                        8124 non-null object 
gill-attachment             8124 non-null object 
gill-spacing                8124 non-null object 
gill-size                   8124 non-null object 
gill-color                  8124 non-null object 
stalk-shape                 8124 non-null object 
stalk-root                  8124 non-null object 
stalk-surface-above-ring    8124 non-null object 
stalk-surface-below-ring    8124 non-null object 
stalk-color-above-ring      8124 non-null object 
stalk-color-below-ring      8124 non-null object 
veil-type                   8124 non-null object 
veil-color                  8124 non-null object 
ring-number                 8124 non-null object 
ring-type                   8124 non-null object 
spore-print-color           8124 non-null object 
population                  8124 non-null object 
habitat                     8124 non-null object 
dtypes: object(23) memory usage: 1.4+ MB None

另一个有用的步骤是检查空值的数量以及它们在数据帧中的位置

print(mushrooms.isna().sum())____________________________________________________________________class                       0 
cap-shape                   0 
cap-surface                 0 
cap-color                   0 
bruises?                    0 
odor                        0 
gill-attachment             0 
gill-spacing                0 
gill-size                   0 
gill-color                  0 
stalk-shape                 0 
stalk-root                  0 
stalk-surface-above-ring    0 
stalk-surface-below-ring    0 
stalk-color-above-ring      0 
stalk-color-below-ring      0 
veil-type                   0 
veil-color                  0 
ring-number                 0 
ring-type                   0 
spore-print-color           0 
population                  0 
habitat                     0 
dtype: int64

一个也没有……这似乎好得令人难以置信。

由于我们勤奋好学,阅读了数据集信息文件。我们知道所有缺失的值都标有问号。一旦清楚了这一点,我们就可以使用[df.replace()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.replace.html)来转换?敬 NaNs。

import numpy as np
mushrooms = mushrooms.replace({'?':np.NaN})
print(mushrooms.isna().sum())
____________________________________________________________________class                       0 
cap-shape                   0 
cap-surface                 0 
cap-color                   0 
bruises?                    0 
odor                        0 
gill-attachment             0 
gill-spacing                0 
gill-size                   0 
gill-color                  0 
stalk-shape                 0 
stalk-root               2480
stalk-surface-above-ring    0 
stalk-surface-below-ring    0 
stalk-color-above-ring      0 
stalk-color-below-ring      0 
veil-type                   0 
veil-color                  0 
ring-number                 0 
ring-type                   0 
spore-print-color           0 
population                  0 
habitat                     0 
dtype: int64

我们到了,stalk_root有 2480 个空白特征,让我们用m替换它们。

mushrooms['stalk-root'] = mushrooms['stalk-root'].replace(np.NaN,'m')print(mushrooms['stalk-root'].value_counts())____________________________________________________________________b    3776 
m    2480 
e    1120 
c     556 
r     192 
Name: stalk-root, dtype: int64

5.开发一个比基线做得更好的模型

基线模型

使用我们数据集中最常见的标签,我们将创建一个我们希望击败的基线模型。

首先让我们看看如何使用[df.value_counts()](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.value_counts.html)来分配类

mushrooms['class'].value_counts(normalize=True)____________________________________________________________________e    0.517971 
p    0.482029 
Name: class, dtype: float64

我们将使用 class 属性的模式来创建基线预测。

majority_class = y_train.mode()[0]baseline_predictions = [majority_class] * len(y_train)

让我们看看我们的基线模型有多精确。

from sklearn.metrics import accuracy_scoremajority_class_accuracy = accuracy_score(baseline_predictions,
                                         y_train)print(majority_class_accuracy)____________________________________________________________________ 0.5179258347438067

约 52%…这是给定初始数据集中类的分布后我们所期望的。

决策树

我们将尝试用决策树来拟合我们的训练数据,并产生大于 52%的准确率分数。

from sklearn.tree import DecisionTreeClassifier
import graphviz
from sklearn.tree import export_graphviztree = DecisionTreeClassifier(max_depth=1)# Fit the model
tree.fit(X_train, y_train)# Visualize the tree
dot_data = export_graphviz(tree, out_file=None, feature_names=X_train.columns, class_names=['Poisonous', 'Edible'], filled=True, impurity=False, proportion=True)graphviz.Source(dot_data)

现在,我们已经将决策树与我们的数据相匹配,我们可以通过查看分类器的预测概率分布来分析我们的模型。简单来说,预测概率表示模型对其分类标签的确信程度。

除了预测概率,我们还会看我们决策树的精度得分。Sklearn 为我们提供了一个简单的方法,用[classification_report](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.classification_report.html)看到分类模型的很多相关分数。

我们还将使用 sklearn 的[confusion_matrix](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html)生成混淆矩阵。混淆矩阵显示了真假阳性和阴性的数量。

因为我们将再次使用这些工具,所以我们将编写一个函数来运行我们的模型分析。

import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import classification_report, confusion_matrixdef model_analysis(model, train_X, train_y):
  model_probabilities = model.predict_proba(train_X) Model_Prediction_Probability = [] for _ in range(len(train_X)):
      x = max(model_probabilities[_])
      Model_Prediction_Probability.append(x) plt.figure(figsize=(15,10)) 

  sns.distplot(Model_Prediction_Probability) plt.title('Best Model Prediction Probabilities') # Set x and y ticks
  plt.xticks(color='gray') #plt.xlim(.5,1)
  plt.yticks(color='gray') # Create axes object with plt. get current axes
  ax = plt.gca() # Set grid lines
  ax.grid(b=True, which='major', axis='y', color='black', alpha=.2) # Set facecolor
  ax.set_facecolor('white') # Remove box
  ax.spines['top'].set_visible(False)
  ax.spines['right'].set_visible(False)
  ax.spines['bottom'].set_visible(False)
  ax.spines['left'].set_visible(False)
  ax.tick_params(color='white') plt.show();

  model_predictions = model.predict(train_X) # Classification Report
  print('\n\n', classification_report(train_y, model_predictions, target_names=['0-Poisonous', '1-Edible'])) # Confusion Matrix
  con_matrix = pd.DataFrame(confusion_matrix(train_y, model_predictions), columns=['Predicted Poison', 'Predicted Edible'], index=['Actual Poison', 'Actual Edible'])

  plt.figure(figsize=(15,10)) sns.heatmap(data=con_matrix, cmap='cool'); plt.title('Model Confusion Matrix')
  plt.show();

  return con_matrix

现在将这个函数应用到我们的决策树中。

model_analysis(tree, X_train, y_train)

我们将把我们的预测存储为一个tree_predictions变量,用于解释我们模型的准确性。

tree_predictions = tree.predict(X_train)accuracy_score(y_train, tree_predictions)____________________________________________________________________0.8862901984920757

88%的准确率已经不错了,但是让我们进入工作流程的下一步。

6.开发一个过度拟合的模型

我们将使用[RandomForestClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html)作为我们的过度拟合模型。

from sklearn.ensemble import RandomForestClassifierrandom_forest = RandomForestClassifier(n_estimators=100, max_depth=5)cv = cross_validate(estimator = random_forest, X = X_train, y = y_train, scoring='accuracy', n_jobs=-1, cv=10, verbose=10, return_train_score=True)____________________________________________________________________ [Parallel(n_jobs=-1)]: Using backend LokyBackend with 2 concurrent workers.[Parallel(n_jobs=-1)]: Done   1 tasks      | elapsed:    2.6s [Parallel(n_jobs=-1)]: Done   4 tasks      | elapsed:    3.2s [Parallel(n_jobs=-1)]: Done  10 out of  10 | elapsed:    4.7s finished

现在我们可以看到我们的随机森林的准确性得分。

random_forest.fit(X_test, y_test)
test_predictions = random_forest.predict(X_train)accuracy_score(y_train, test_predictions)____________________________________________________________________ 0.9924603785197723

99%的准确率对我来说太过了。

我们可以使用前面的model_analysis函数来分析我们的模型。

model_analysis(random_forest, X_train, y_train)

7.正则化模型并调整其超参数

现在,我们将调整RandomForestClassifier的超参数,并尝试在欠拟合和过拟合之间游走。我们可以使用 sklearn 的[RandmoizedSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.RandomizedSearchCV.html)在我们的param_distributions字典中搜索超参数。

from sklearn.model_selection import RandomizedSearchCVparam_distributions = {
    'max_depth':[1, 2, 3, 4, 5],
    'n_estimators': [10, 25, 50, 100, 150, 200]}search = RandomizedSearchCV(estimator = RandomForestClassifier(), param_distributions = param_distributions, n_iter=100, scoring='precision', n_jobs=-1, cv=10, verbose=10, return_train_score=True)

search.fit(X_train, y_train)

我们可以用search.best_estimator_来看看哪个模型的精度得分最高。

best_model = search.best_estimator_
best_model____________________________________________________________________RandomForestClassifier
(bootstrap=True, class_weight=None, criterion='gini', max_depth=5, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2,             min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=None,             oob_score=False, random_state=None, verbose=0,             warm_start=False)

从模型描述中我们可以看到,具有 5 和 10 个估计量的max_depthRandomForestClassifier是我们的最优模型。现在我们可以运行我们的分析功能。

model_analysis(best_model, X_test, y_test)

3 次误报,不完美,但相当不错。

结论

重申我们的工作流程。

  1. 定义问题并组装数据集
  2. 选择衡量成功的标准
  3. 决定评估协议
  4. 准备数据
  5. 开发一个比基线做得更好的模型
  6. 开发一个过度拟合的模型
  7. 正则化模型并调整其超参数

虽然 Chollet 将其描述为通用的机器学习工作流,但根据我们试图解决的具体问题,存在无限的变化。不过一般来说,你总是从定义你的问题和收集数据开始,(无论是从预先准备好的数据集还是自己收集的数据)。

我希望这篇文章展示了 Chollet 的通用机器学习工作流程的详细介绍。

感谢阅读!

在 T witter 、 GitHub 和 LinkedIn 上关注我

附:这是我在这篇文章中使用的 Colab 笔记本的链接。

应用金融机器学习进展中的两个想法

原文:https://towardsdatascience.com/applying-two-ideas-from-advances-in-financial-machine-learning-433c7950858a?source=collection_archive---------12-----------------------

寻找金融中的结构突变和测量熵

当我不调整我的足球博彩模式时,我会涉足金融。最近,我被这本的书《金融机器学习的进步》(AFML)迷住了——作者将学术严谨与实际执行相结合。这不是一个容易的阅读——我不得不重读几遍章节和参考文献,才能真正理解他在说什么,但这是非常值得的。

与此同时,我偶然发现了这个由 WorldQuant 发起的在线交易挑战。起初,我感到不快,因为你必须用他们的专有语言而不是 Python 来编码,但当我使用这个平台时,我发现它非常容易掌握,并允许我专注于想法的产生和执行,而不用担心 Python 包和环境设置。

我将介绍 AFML 的两个特征提取思想,他讲述了如何使用结构突变和熵来提取特征。

更新:我的团队进入了新加坡的全国总决赛!在此处找到幻灯片中涵盖战略的部分。

1.结构突变

当将机器学习应用于金融时,人们通常首先想到的是预测未来,通常是资产的未来价格。但是我们也可以用它来预测某些策略会更有效的情况。结构性断裂就是这样一个例子。

一个结构性的突变代表了一个制度的改变,意味着观察到的新价格不属于迄今为止价格序列的原始分布。破裂可能表明有气泡形成。在休息期间,会有意想不到的机会——市场参与者争相适应新的规范,因此某些策略可能会更有效。

我通过“累积和”测试计算结构突变,即测量跨越阈值的累积噪声,这意味着一个突变。Chu、Stinchcombe 和 White[1]描述了一种计算对数价格偏离的简单方法;我使用下面的 WorldQuant 平台实现了一个这样的迭代。

snt: Test Statistic; crit: Critical Value

2.使用峰度近似熵

熵最初用于热力学,作为不可逆热损失的量度[2]。信息论之父克劳德·香农(Claude Shannon)将这一概念应用于信息熵[3],信息熵是一种基于概率的信息包含多少价值的量度——概率越低,信息含量越高,反之亦然。

那么这和市场有什么关系呢?一些人将市场效率与熵联系起来[4],例如,当价格序列具有高熵时,它具有低冗余和高信息含量,因此不存在套利机会。在低熵或低效率时期,可能会形成泡沫。如果我们能测量价格序列的信息熵,我们就能创造出在高熵或低熵时期更有效的策略。

在我们测量熵之前,我们必须对我们的返回序列进行编码。我们使用收益序列而不是价格序列,是因为需要平稳性——《AFML》的作者着重强调了一个细微差别的价格序列以保持记忆——我很快就会尝试这种方法。

对 return 序列进行编码后,一个简单的方法是计算表示 price 序列所需的唯一位的数量,本质上是创建一个字典。熵也是压缩的一种度量,如果需要很多比特来解释一个价格序列,价格序列的熵就越高。

如果没有 Python 的灵活性,实际编码和计算熵是相当困难的,所以我在平台上使用峰度间接地实现了它。

峰度是对分布尾部有多厚的一种度量。峰度越高,越多的值以平均值为中心。如果我们对一只股票的价格序列进行编码,峰度较高的序列可能熵值较低。

Source: outsmartingthemarkets.com

请注意,下面的峰度公式测量的是超额峰度,因此如果您正在从头开始计算峰度,您将需要减去 3,这是一个正态分布的峰度。

with 2 lines of code, I can implement a kurtosis check over any time period!

现在你已经学会了从价格序列中提取特征的两种方法,你可以想出在结构突变或高/低熵时期有效的创造性策略。

你也读过《AFML》吗?你有什么想法可以让我的执行变得更好吗?或者你想看看书中的其他章节是如何执行的吗?请在下面的评论中告诉我。

参考

[1]朱家祥(1996),斯廷奇科姆,赫伯特·怀特.监测结构变化。

[2]克劳修斯研究报告(1870 年)第十六卷。适用于热的一个力学定理。伦敦、爱丁堡和都柏林哲学杂志和科学杂志 40:122–127。DOI: 10.1080/147864470 08640370。

[3] Shannon CE (1948)一种数学理论的交流。贝尔系统技术杂志 27:379–423。DOI:10.1002/j . 1538–7305.1948 . TB 00917 . x

[4]古尔科,L. (1999 年)。熵市场假说。国际理论应用金融杂志,2,293–329。

人工智能如何工作:两个主要的直觉

原文:https://towardsdatascience.com/approaches-to-ai-dominant-intuitions-1c5195a7166a?source=collection_archive---------24-----------------------

Photo by Franck V. on Unsplash

人工智能(AI)可能是一个真正理解起来颇具挑战性的话题,尤其是对于缺乏该领域深厚学术背景的企业经理、企业家和投资者来说。他们可能会本能地感觉到人工智能的巨大潜力——好莱坞制作的所有科幻电影和电视节目可能都在这方面发挥了作用——但他们经常会问,我应该如何看待人工智能?AI 实际上是如何工作的?

下面这篇文章通过展示人工智能的两种广泛且相当主流的直觉——认知的和统计的——来解决这个问题。尽管该领域相对分散,人工智能从业者背景各异,但认知和统计直觉似乎反映了当今接近人工智能的方式。如果你能掌握其中一个或两个直觉,那么你将更好地作为商业利益相关者有意义地参与围绕人工智能的讨论,以及建立和投资人工智能机会。

认知直觉

想想你上一次不得不为多项选择题考试而学习的时候。图 1 显示了这种问题的一个非常简单的例子。

Fig. 1: Multiple Choice Question

如果你幸运的话,你可能有机会使用过去考试的题库来练习。如果你像我一样,你可能会反复练习这些问题几次,希望每一次都越来越好。

这本质上也是人工智能如何工作的认知直觉。它强调学习的概念,并把它与人类认知相提并论。类似于学生处理过去测试中的样本问题,人工智能使用过去的数据来建立对现实世界越来越准确的理解(或模型)。特别地,你和 AI 都做以下事情:

  • 用数据训练:你解决的选择题越多,你就能更好地完成任务。当然,通过这样做,你通常只会在手头的特定任务上做得更好。例如,如果你一直在准备生物考试,你不太可能提高历史考试的成绩。AI 也是一样。
  • 通过试错来学习:你想要最大化奖励(通过答对和通过测试)并避免惩罚(减分)。你也可以这样看待 AI 学习;它因正确的预测而受到奖励,因错误的预测而受到惩罚。随着时间的推移,人工智能会调整自己的行为,减少错误,实现回报最大化。
  • 简化现实:为了让学习任务变得简单一点,你可以使用简单的试探法、捷径或其他技巧来提高你的准确性。例如,你可以把相似的概念分成几组,或者使用记忆术来帮助你更好地回忆主题;所有这些都可以帮助你得到正确的答案,而不必仔细考虑问题。同样,人工智能也依赖于现实世界的简化模型来对环境做出快速反应。想象一下自动驾驶汽车在路上绕过障碍物,甚至你的手机使用面部识别解锁屏幕——检测不需要完美,只要足够接近现实就行。

统计直觉

早在高中,后来在大学,我记得通过散点图上绘制的点绘制最佳拟合线。图 2 示出了一个简单的例子,其中目的显然是画一条尽可能靠近图上尽可能多的点的直线。

Fig. 2: Best-Fit Line

有了对最佳拟合线的基本理解,你就已经能够理解人工智能是如何工作的了。这是因为人工智能建立在统计概念的基础上,以开发关于世界的智能思维方式——这也是人工智能的统计直觉的基础。事实上,仅仅从图 2 中的图表,我们就可以开始理解一些对人工智能来说是基础的概念:

  • 揭示关系:人工智能就是要揭示数据中不同变量之间非常复杂的关系。例如,图 2 中的最佳拟合线描述了变量 xy 之间可能的(并且非常简单的)线性关系。关系也可以是非线性的(例如,二次、正弦等。)并且跨越两个以上的维度。如果这种关系可以用数学来表示,那么它可能是人工智能的公平游戏。
  • 内插和外插:这与填充数据中的空白有关,例如预测尚未绘制在图上的 x 的值的 y 的值(反之亦然)。如果缺失数据在我们当前数据样本的范围内,那么我们就谈插值。如果缺失或未知数据超出了我们的数据样本范围,那么我们就要考虑外推
  • 检测异常:人工智能的几个高影响力用例与检测数据中的异常值或异常有关。例如,在制造业,生产过程依赖于设备的稳定性和一致性;人工智能越来越多地用于促进“预测性维护”(例如,通过监控设备的健康状态并采取行动),以预先防止设备性能下降,从而减少生产线上的停机时间。因此,发现异常并思考导致异常的原因(例如,通过根本原因分析)是人工智能的关键问题。
  • 理解欠拟合和过拟合问题:xy 之间的关系应该适合已知的以及未知的/新的数据。例如,图 2 中的线可能适合当前的数据样本,但是如果随着 x 变大, xy 之间的关系发生变化,该怎么办?就我们所知,最佳拟合线的斜率可能与我们当前数据样本中的相同,但斜率也可能降低,甚至可能呈现下降趋势。拟合不足意味着人工智能揭示的统计关系仅粗略地拟合了数据(并且它可能没有足够好地拟合数据),而过度拟合意味着该关系可能太好地拟合了可用的数据样本(并且可能与我们尚未看到的数据相去甚远)。在这里实现正确的平衡是人工智能的一个关键挑战。

包裹

很难理解人工智能。尽管已经存在了近一个世纪,但其固有的复杂性让人工智能感觉像是一个新生领域,仍然更像是科幻小说而不是现实。企业经理、企业家和投资者可以本能地感觉到,人工智能是——或将很快成为——一件大事,但这项技术仍然经常让人感觉像一个黑匣子。

为了打开这个黑匣子,并揭示更多关于人工智能实际上如何工作的信息,根据上面提出的人工智能的两个主要直觉来思考会有所帮助。认知直觉是从人类认知和学习的角度来看待人工智能的;用我们自己的认知做类比,可以更容易把握 AI 是如何工作的。同时,统计直觉通过数学关系的透镜看待人工智能;这种直觉是关于发现、描述和优化感兴趣的结果变量(即 y 变量)和可能的预测变量(即 x 变量)之间复杂且看似隐藏的关系。综合起来,认知和统计直觉为人工智能如何在引擎盖下工作提供了一个相当全面的画面。

最后,理解人工智能的这两个主要直觉也与今天积极招聘数据科学家和其他人工智能专业人员的人高度相关。你会注意到,大多数候选人主要通过认知或统计的观点来理解人工智能。比如有经济学和数学(当然还有统计学)背景的考生,倾向于从统计学的世界过渡到 AI;一个恰当的例子是,我采访的一位担任数据科学职位的前经济学家说,人工智能基本上只是“类固醇统计”。同时,有计算机科学或机械工程背景的候选人,可能有自动化和机器人方面的经验;对于这些候选人来说,向人工智能的跳跃往往是思维的转变,从基于规则的确定性机器转向更“智能”的非确定性机器,这些机器可以以适应的方式与环境互动。可以说,为认知和统计直觉招募人才可以带来更全面、更有效的人工智能团队。

无需深度学习的小规模不平衡数据集情感分析方法

原文:https://towardsdatascience.com/approaches-to-sentimental-analysis-on-a-small-imbalanced-dataset-without-deep-learning-a314817e687?source=collection_archive---------14-----------------------

让我们让 logreg 再次变得伟大!

介绍

现在有很多用于 NLP 的预训练网络,它们是 SOTA,并且击败了所有基准:BERT、XLNet、RoBERTa、ERNIE…它们被成功地应用于各种数据集,即使在数据很少的情况下。

在 7 月底(2019 年 7 月 23 日–2019 年 7 月 28 日),有一个关于分析 Vidhya 的小型在线黑客马拉松,他们让参与者对药物评论进行感性分析。这很复杂,原因有几个:

  • 只有 5279 个样本在训练中,有 3 类(阴性、中性、阳性)不平衡;
  • 一些标签似乎是不正确的,这种情况有时会发生在人工标注文本的时候;
  • 有些课文很短,有些很长。在某些情况下,评论不仅包含评论本身,还包含人们回答的评论的引用;
  • 另一个更有趣的问题是:一般来说,评论可能是积极的,但对一种药物有负面情绪(以及任何其他对情绪);

一方面,如果情况复杂,需要对背景有深刻的理解,深度学习模型应该可以很好地工作;另一方面,我们只有几千个样本,这似乎不足以进行深度学习。

剧透:据我所知,winners 对 BERT 和 XLnet 进行了微调,但没有共享代码,具体的我就说不出来了。

我知道我不能在这个比赛上花太多时间,所以我决定尝试普通的方法(单词袋和逻辑回归),看看他们能走多远。

排行榜可在此处获得(指标为 f1-macro):https://data hack . analyticsvidhya . com/contest/innoplexus-online-hiring-hackathon/PVT _ lb

我以 0.5274 的分数获得了第 21 名(第一名的分数为 0.6634)。我还提交了一份得分为 0.5525 的作品,这将使我获得第 12 名,但我没有选择它😞

数据概述

在任何项目的开始,我总是从 EDA 开始。所以我们来看看数据。我们有一些唯一的 id,评论的文本,药物的名称和情绪(1 是负面的,2 是中性的,0 是正面的)。

人们通常会写下他们的疾病、症状和药物。

训练和测试数据集中的药物有所重叠,但并不完全重叠,有些药物只出现在一个数据集中。

正如我在开始时所写的,大多数文本都很短,但也有一些很长的文本,可能是因为错误而出现在这里。

设置基线

写一个基线通常是一个好主意,它将在以后用作参考,并确保一切正常工作。

主要步骤如下:

  • 处理数据,为建模做准备;
  • 建立模型;
  • 执行验证(可以与训练模型同时进行);

基本的方法是跳过任何文本预处理,使用文本矢量器。我使用 NLTK 的 TweetTokenizer,因为它通常比默认的 sklearn tokenizer 更好。它可以提取表情符号和许多其他有用的令牌。而且使用 n 元单词比单词更好。

我们可以直接使用sentiment特征作为目标,因为它已经是数值,并且从 0 开始。

tokenizer = TweetTokenizer()
vectorizer = TfidfVectorizer(ngram_range=(1, 3), tokenizer=tokenizer.tokenize)
full_text = list(train['text'].values) + list(test['text'].values)
vectorizer.fit(full_text)
train_vectorized = vectorizer.transform(train['text'])
test_vectorized = vectorizer.transform(test['text'])
y = train['sentiment']

我们有一个多类分类问题。有两种主要的方法:为每个类或其他类建立二元分类器,或者为每对类建立二元分类器。我更喜欢第一种方法,并将它与逻辑回归一起使用。

logreg = LogisticRegression(class_weight='balanced')
ovr = OneVsRestClassifier(logreg)

现在有必要建立一种方法来检查我们模型的质量。我们可以简单地分割训练数据,一部分训练模型,另一部分检查质量。但是我更喜欢使用交叉验证。这样我们训练了 N 个模型,验证了 N 次,并且对模型的质量有了更好的度量。因此,我在我们的模型中使用了cross_val_score函数,使用了f1_macro指标,因此它将跟随排行榜分数,并定义简单的 3 倍分割。

scores = cross_val_score(ovr, train_vectorized, y, scoring='f1_macro', n_jobs=-1, cv=3)
print('Cross-validation mean f1_score {0:.2f}%, std {1:.2f}.'.format(np.mean(scores), np.std(scores)))

交叉验证的得分是 0.4580。现在我们可以对测试数据进行预测,生成提交文件并提交。

pred = ovr.predict_proba(test_vectorized)
sub['sentiment'] = pred.argmax(1)
sub.to_csv('sub.csv', index=False)

结果是 0.4499。这是一个好的开始,并且表明我们的验证方案足够好(具有相似的分数)。

改变超参数。第一步。

让我们努力提高分数。第一步是尝试改变预处理步骤。我使用带有 1-3 个 ngrams 和单词的TfidfVectorizer作为标记。有许多可能的方法来处理文本数据:

  • 干净的文本。这可能包括将缩写改为完整的单词,删除数字/标点符号/特殊符号,纠正拼写错误等等;
  • 词汇化或词干化以减少独特单词的数量;
  • 使用字母/符号作为标记(相对于使用单词);
  • 许多其他想法;

作为第一个实验,我将TfidfVectorizer参数改为TfidfVectorizer(ngram_range=(1, 5), analyzer='char'。这使我的交叉验证分数增加到 0.4849,并将公共排行榜上的分数提高到 0.4624。对于改变一行代码来说,这是一个很好的改进,是吗?

下一个想法:我们可以同时使用单词和字符标记!我们简单地连接矩阵:

vectorizer = TfidfVectorizer(ngram_range=(1, 3), tokenizer=tokenizer.tokenize, stop_words='english')
full_text = list(train['text'].values) + list(test['text'].values)
vectorizer.fit(full_text)
train_vectorized = vectorizer.transform(train['text'])
test_vectorized = vectorizer.transform(test['text'])vectorizer1 = TfidfVectorizer(ngram_range=(1, 5), analyzer='char')
full_text = list(train['text'].values) + list(test['text'].values)
vectorizer1.fit(full_text)
train_vectorized1 = vectorizer1.transform(train['text'])
test_vectorized1 = vectorizer1.transform(test['text'])train_matrix = hstack((train_vectorized, train_vectorized1))
test_matrix = hstack((test_vectorized, test_vectorized1))

这给了我 0.4930 的交叉验证分数和 0.4820 的排行榜。

使用文本

正如我在开头所写的——课文包含了大量的信息,但并不是所有的信息都是有用的。人们可以引用其他文本,写长篇故事,比较几种药物等等。

几次尝试之后,我做了以下事情:

train['new_text'] = train.apply(lambda row: ' '.join([i for i in row.text.lower().split('.') if row.drug in i]), axis=1)

现在我们有了新的文本,其中只包含提到相关药物的句子。在此之后,我调整了超参数,并以这个矢量器结束:

TfidfVectorizer(ngram_range=(1, 3),  max_df=0.75, min_df=10, sublinear_tf=True)

这在交叉验证中得到 0.5206 分,在公共排行榜中得到 0.5279 分。是我选择的提交让我在排行榜上获得了第 21 名。

模型口译

了解模型预测的内容和方式通常是一个好主意,这可以带来一些见解,从而改进我们的模型。

ELI5 可以这样解释我们的模型并显示预测:

红色单词意味着这个单词减少了这个类的概率,绿色单词增加了这个类的概率。

一个更好的解决方案

我尝试了很多东西来提高分数:不同的模型(像 SGD),超参数优化,文本清洗,欠采样,半监督学习和其他东西。让我们看看我的最佳解决方案是如何创建的。

  • 更好的文本预处理

清理文本对我不起作用,但我能够改进我缩短文本的方法。现在我不仅用提到药物的那句话,还用下一句话——我觉得人们第一次提到药物后,一般会写点别的。我也只取前 10 个句子:大部分文本都在这个范围内,但也有一些巨大的文本,这会使训练变得更糟。

def get_text(row):
    splitted_text = row.text.lower().split('.')
    indices = [splitted_text.index(j) for j in [i for i in splitted_text if row.drug in i]]
    full_indices = []
    for i in indices:
        full_indices.append(i)
        if i < len(splitted_text) -1:
            full_indices.append(i + 1)
    full_indices = list(set(full_indices))
    full_text = []
    for i in full_indices:
        full_text.append(splitted_text[i])
    return ' '.join(full_text[-10:])
  • 超参数优化

超参数优化总是很重要。Sklearn API 允许使用方便的语法构建管道并优化它们:

combined_features = FeatureUnion([('tfidf', TfidfVectorizer(ngram_range=(1, 3))),
                                  ('tfidf_char', TfidfVectorizer(ngram_range=(1, 3), analyzer='char'))])
pipeline = Pipeline([("features", combined_features),
                     ('clf', OneVsRestClassifier(LogisticRegression(class_weight='balanced')))])parameters = {
    'features__tfidf__max_df': (0.3, 0.75),
    'features__tfidf_char__max_df': (0.3, 0.75),    
    'clf__estimator__C': (1.0, 10.0)
}
grid_search = GridSearchCV(pipeline, parameters, cv=folds,
                               n_jobs=-1, verbose=1, scoring='f1_macro')
grid_search.fit(train['new_text'], train['sentiment'])

这样,我们可以优化两个矢量器和“OneVsRestClassifier”中的逻辑回归模型的参数。

  • 欠采样

我已经决定,可能是阶级不平衡太严重了,应该对此采取一些措施。有许多方法可以处理它:欠采样,过采样,SMOTE,改变类不平衡。你可以注意到我使用了平衡类权重的逻辑回归,但是这还不够。经过几次尝试,我决定做一个简单的欠采样,随机抽取 2000 个中性类样本。

  • 半监督学习

这个想法很简单:在我们训练了我们的模型之后,它应该给出很好的预测(嗯,至少我们希望如此:),大多数有信心的预测应该是正确的,或者至少是大部分正确的。我选取了 1000 个最佳预测,并将它们添加到训练数据集中。在增加的数据集上训练了一个新模型后,我在公开排行榜上得到了 0.5169。这个提交在私人排行榜上的价值是 0.5525,但我没有足够的信任去选择它。

结论

一方面,使用更传统的 ML 方法可能获得高结果,另一方面,现在这些方法不足以击败使用预训练模型的深度学习。这是否意味着更简单的模型没有用武之地?我认为,有时在商业中使用逻辑回归可能是合理的:它建立起来更快,更容易解释,需要的资源更少。然而,从长远来看,使用深度学习是一种成功的方式。

用 Hinton 胶囊网络探讨等方差问题

原文:https://towardsdatascience.com/approaching-the-problem-of-equivariance-with-hintons-capsule-networks-b7f06b2abc57?source=collection_archive---------23-----------------------

看看这个:

现在看这个:

即使你从未去过月球,你也可能认出上面图像的主体是美国宇航局的月球漫游车,或者至少是同一辆车在稍微不同的方向上的两个实例。您可能有一个直观的想法,知道如何操纵一个图像的视点来近似另一个图像的视图。这种认知转换对人类来说是毫不费力的直觉,但对于没有明确训练示例的卷积神经网络来说却非常困难。

卷积和最大池层的限制

标准的卷积神经网络,顾名思义,是由一系列的卷积运算组成的,这些卷积运算分层次地提取图像特征,如边缘、点和角。每个卷积将图像乘以像素权重的滑动窗口,也称为卷积核,每层中可能有几十到几千个核。通常,我们在每个卷积之间执行合并操作,降低图像维度。池化不仅减小了层的大小(节省了内存),而且提供了一些平移不变性,使得给定的网络可以对图像主题进行分类,而不管它位于图像中的什么位置。然而,这与其说是一个功能,不如说是一个缺陷,因为池化操作混淆了关于图像中某个位置的信息(推动了 U-nets 中 skip 连接的开发),并且除了翻译之外,在处理图像转换方面表现不佳。

具有汇集的 conv 网络中的翻译不变性缺乏对象转换等价性,这是一种更一般化的认知能力,似乎更接近于我们自己理解世界的方法。事实上,conv 网在各种各样的计算机视觉任务中表现相当好,这掩盖了这个缺点。考虑 MNIST 手写数字数据集的经典例子。按照今天的标准,LeNet-5 是一个相对较浅和简单的 conv 网络设计,它很快学会正确识别测试数据集中 98%的数字。

Test predicted: seven two one zero four one four nine Test groundTruth: seven two one zero four one four nine Accuracy of the network on the 10000 test images: 98.68 %

然而,对测试图像进行简单的 35 度旋转,测试性能会急剧下降。

Test predicted: four two one zero four one four two Test groundTruth: seven two one zero four one four nine LeNet 5 accuracy on 10000 (rotated) test images: 76.05 %

所谓的“胶囊网络”在处理旋转数据方面做得更好:

Test predicted: nine zero one two three four five six Test groundTruth: seven two one zero four one four nine Accuracy of the network on the 10000 (rotated) test images: 84.09 %

缓解该问题的标准方法是数据扩充,即添加旋转、镜像、扭曲等。综合放大数据集以覆盖可能的示例的更大分布。这提高了给定视觉任务的性能,但它显然是一个杂牌,正如他们所说的“智力上不令人满意”

多年来 Geoffrey Hinton 一直直言不讳地表示他不喜欢汇集操作,并一直试图用一种更普遍的等方差来取代汇集的偶然平移不变性,他称之为“胶囊”,这是一种通过将卷积提取的特征重塑为多维向量来创建的场景内容的表示。胶囊网络的概念随着 conv 网络的兴起而发展,如将自动编码器(2011) 转变为用于训练胶囊的动态路由方法(2017) ,以及最近更新的称为期望最大化(2018) 的训练算法。

胶囊来拯救?

在胶囊网络中,每个向量学习表示图像的某些方面,例如形状图元,向量长度对应于对象在给定点存在的概率,向量的方向描述对象的特征。在 2017 年的实现中,第一层胶囊每个都试图通过动态路由来预测下一层胶囊的正确概率(例如,在人脸检测 CapsNet 中,“眼睛”和“鼻子”胶囊值将各自对下一层中每个点的“人脸”胶囊的预测有贡献)。考虑 2D 胶囊向量检测构成卡通门口的多边形的简化示例。这些胶囊代表两种形状(方块和四分之一圆)的存在和方向,它们将一起尝试预测下一个胶囊层中的正确分类,该胶囊层学习检测正确定向的门口。

而在 conv 网中,仅仅正确特征的存在(在训练数据中表示的方向上)就足以触发分类,而不管它们彼此之间的空间关系,胶囊向量都必须非常一致,以从其部分预测整体。我们还应该注意到胶囊一次只能检测给定对象的一个实例,因此一堆块将无法区分,并且 CapsNet 模型可能会因同一类型的重叠部分而混淆。这个缺点经常被比作人类感知中的拥挤。

教程部分:针对旋转 MNIST 分类,训练和测试 LeNet5 与动态路由 CapsNet

比谈论胶囊更好的是修补它们。为了简单起见,我们将使用流行的 MNIST 手写数字数据集。本节中的代码为在 5 层 LeNet5 conv 网络中熟悉的数据集和机器学习模型的上下文中理解 CapsNets 提供了可破解的基础。在对 CapsNet 在 MNIST 的表现有了一个大致的了解之后,我们建议增加不同的训练数据扩充例程,以了解每个模型在学习各种转换方面的表现。

首先,我们将使用 PyTorch 的转换库定义我们想要处理的数据集和我们需要的预处理。

import torch import torchvision import torchvision.transforms as transforms import numpy as np import matplotlib.pyplot as plt import time import torch.nn as nn import torch.nn.functional as F import torch.optim as optim #Download dataset (if necessary) and define test set transformation batch_size = 8 degrees= 15 transform_normal = transforms.Compose([torchvision.transforms.RandomAffine(0, translate=(0.0714,0.0714)),\ transforms.ToTensor(),\ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) transform_rotate = transforms.Compose([torchvision.transforms.RandomRotation([degrees,degrees+1e-7],\ resample=False,\ expand=False, center=None),\ transforms.ToTensor(),\ transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) train = torchvision.datasets.MNIST(root='./data', train=True,download=True,transform=transform_normal) test = torchvision.datasets.MNIST(root='./data', train=False,download=True,transform=transform_rotate) test_norot = torchvision.datasets.MNIST(root='./data', train=False,download=True,transform=transform_normal) #Data iterator definitions train_loader = torch.utils.data.DataLoader(train, batch_size=batch_size,shuffle=True) test_loader = torch.utils.data.DataLoader(test, batch_size=batch_size,shuffle=False) test_loader_norot = torch.utils.data.DataLoader(test_norot, batch_size=batch_size,shuffle=False) #Define class labels classes = ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")

定义我们的 CNN: LeNet5

我们将从在 PyTorch 中实现一个名为 LeNet5 的小型卷积神经网络开始。该模型仅在几个训练时期后就为我们提供了 90%以上的测试集准确度,并且仅由 2 个卷积层和 3 个全连接层组成。

#define LeNet5 Conv-net architecture class lenet5(nn.Module): def __init__(self): super(lenet5, self).__init__() in_channels = 1 conv0_channels = 6 conv1_channels = 16 kernel_size = 5 pool_size = 2 pool_stride = 2 h_in = 256 h2 = 120 h3 = 84 classes = 10 self.conv0 = nn.Conv2d(in_channels, conv0_channels, kernel_size) self.pool = nn.AvgPool2d(pool_size, pool_stride) self.conv1 = nn.Conv2d(conv0_channels, conv1_channels, kernel_size) self.fc2 = nn.Linear(h_in, h2) self.fc3 = nn.Linear(h2, h3) self.fc4 = nn.Linear(h3, classes) def forward(self, x): h_in = 256 x = self.pool(F.relu(self.conv0(x))) x = self.pool(F.relu(self.conv1(x))) x = x.view(-1, h_in) x = F.relu(self.fc2(x)) x = F.relu(self.fc3(x)) x = self.fc4(x) return x def imshow(img,my_string=None): #Helper function for visualizing digits img = img / 2 + 0.5 # unnormalize npimg = img.numpy() plt.imshow(np.transpose(npimg, (1, 2, 0))) if(my_string is not None): plt.title(my_string) plt.show()

LeNet5 的培训和测试程序

我们将使用 Adam 优化来最小化训练期间的交叉熵误差。同样,可以通过 PyTorch 轻松访问该功能。

def train_lenet5(lenet5,learning_rate=1e-4, epochs=10, try_cuda=True): t0 = time.time() if (try_cuda): if torch.cuda.is_available(): device = torch.device("cuda") else: device = torch.device("cpu") #Define training criterion and optimizer criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(lenet5.parameters(), lr=learning_rate) #Send model to GPU if desired lenet5 = lenet5.to(device) for epoch in range(epochs): # loop over the dataset multiple times running_loss = 0.0 for i, data in enumerate(train_loader, 0): #get inputs inputs, labels = data inputs = inputs.to(device) labels = labels.to(device) #zero the parameter gradients optimizer.zero_grad() #forward pass + back-propagation + update parameters outputs = lenet5(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() #print statistics running_loss += loss.item() if i % 2000 == 1999: # print every 2000 mini-batches print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss = 0.0 print("Finished training for %i epochs on device %s took %.2f seconds"%(epochs,device,time.time()-t0)) def test_lenet5(lenet5): #We'll test on the cpu lenet5.to(torch.device("cpu")) #Get training set performance dataiter = iter(train_loader) images, labels = dataiter.next() #print images imshow(torchvision.utils.make_grid(images),"Training Example") pred_prob = lenet5(images) _, predicted = torch.max(pred_prob, 1) #report labels print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(batch_size))) print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(batch_size))) #calculate accuracy correct = 0 total = 0 with torch.no_grad(): for data in test_loader_norot: images, labels = data outputs = lenet5(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print("LeNet 5 accuracy on (unrotated) training images: %.2f %%" % (100 * correct / total)) dataiter = iter(test_loader_norot) images, labels = dataiter.next() #print images imshow(torchvision.utils.make_grid(images),"Unrotated Test Data") #get probabilities and predictions pred_prob = lenet5(images) _, predicted = torch.max(pred_prob, 1) print('Test predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(batch_size))) print('Test groundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(batch_size))) correct = 0 total = 0 with torch.no_grad(): for data in test_loader_norot: images, labels = data outputs = lenet5(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print("LeNet 5 accuracy on 10000 (unrotated) test images: %.2f %%" % (100 * correct / total)) #test with rotation dataiter = iter(test_loader) images, labels = dataiter.next() #print images imshow(torchvision.utils.make_grid(images),"Rotated Test Data") pred_prob = lenet5(images) _, predicted = torch.max(pred_prob, 1) print("Test predicted: ", " ".join("%5s" % classes[predicted[j]] for j in range(batch_size))) print("Test groundTruth: ", " ".join("%5s" % classes[labels[j]] for j in range(batch_size))) correct = 0 total = 0 with torch.no_grad(): for data in test_loader: images, labels = data outputs = lenet5(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print("LeNet 5 accuracy on 10000 (rotated) test images: %.2f %%" % (100 * correct / total)) lenet5_model = lenet5() pre_trained = True # Change this flag to train from scratch if(pre_trained): lenet5_model.load_state_dict(torch.load("./lenet5_trained.pt")) else: #liy: learn-it-yourself pass print("LeNet5 Parameters: \n",lenet5) train_lenet5(lenet5_model,epochs=1) test_lenet5(lenet5_model) #save the model parameters #torch.save(lenet5_model.state_dict(), "./lenet5_trained.pt")#output [1, 2000] loss: 1.135 [1, 4000] loss: 0.521 ... [14, 6000] loss: 0.051

用于训练胶囊网络的动态路由算法在计算上比 conv 网要求更高。如果我们想在合理的时间内完成,我们肯定会想在 GPU 上训练。我们还为那些目前处于 GPU 之间或只想跳过测试的人预先培训了一个 CapsNet。为了训练和测试一个胶囊网络,我们分叉并修改了岩崎健太在 https://github.com/gram-ai/capsule-networks的实现。通过输入(在命令行中)克隆本教程中使用的版本:

git clone [https://github.com/theScinder/capsule_networks_rotated_MNIST.git](https://github.com/theScinder/capsule_networks_rotated_MNIST.git)

之后,您可能希望启动 PyTorch visdom 服务器以实现可视化,方法是输入(在单独的命令行窗口中):

python -m visdom.server

最后,您可以通过在交互式 python 会话(仍在 capsule_networks_rotated_MNIST 目录中)中输入以下代码来训练和测试 CapsNet,或者将其保存为. py 文件以供使用,并通过命令行运行:

python run_capsnet.py

其中 run_capsnet.py 是新保存的脚本文件的名称。

from capsule_network import * from torch.autograd import Variable #change these parameters to train from scratch num_epochs = 0 load_model = True train_and_test_capsnet()#output #parameters: 8215570 WARNING:root:Setting up a new session... time to train CapsNet for 0 epochs = 0.04 seconds Test predicted: seven two one zero four one four nine Test groundTruth: seven two one zero four one four nine Accuracy of the network on the 10000 (unrotated) test images: 99.37 % Test predicted: nine zero one two three four five six Test groundTruth: seven two one zero four one four nine Accuracy of the network on the 10000 (rotated) test images: 92.12 %

结论

胶囊网络提供了卷积神经网络的通用特征提取属性的扩展。通过训练每个初级胶囊来预测下一层胶囊的输出,可以鼓励模型学习识别部分、整体之间的关系以及它们的实例化特征(例如位置和方向)的重要性。在许多方面,这感觉像是识别场景中的对象的更自然的方式,因为方向和其他属性可以作为由胶囊表示的场景对象的参数来学习,并且修改特征可以给我们视点、比例等方面的真实变化。相比之下,卷积激活开始看起来像一个非常粗糙的特征表示。

然而,用于训练的动态路由算法可能非常慢(一个历元可能需要超过 5 分钟,而在相同硬件上 LeNet5 需要 25 秒),并且在实践中,它可能需要一点选择性表示(也称为挑选),以找到顶点网明显优于可比 conv 网的情况。使用 LeNet5 这样的简单 conv 网,数据扩充可以在训练和(旋转)测试 MNIST 数据集上产生超过 98%的准确性,并且基于所需的训练时间而不是模型大小来比较 CapsNets 和 conv 网可能更公平。总的来说,98%和 99%以上的准确率之间的差别可能看起来不大,但就解决问题而言,最重要的是最后几个百分点的误差,而不是学习一种近似的启发式方法。

培训顶网仍有很大的改进空间,高度的兴趣确保他们将得到大量的开发工作。我们很可能会看到顶网以类似于 conv 网的方式获得效用,首先在玩具问题上展示,如 MNIST,然后应用于更相关的领域。caps net 肯定会产生令人兴奋的结果,这是更快的硬件加速器和更好的训练算法/软件库的结合,使“深度 caps net”成为现实。

获取的公开领域月球漫游车图片(NASA 生成)https://commons . wikimedia . org/wiki/File:Apollo _ 15 _ Lunar _ Rover _ final _ resting _ place . jpghttps://commons . wikimedia . org/wiki/Category:Lunar _ Roving _ Vehicle #/media/File:Apollo _ 17 _ Lunar _ Rover _ near _ station _ 8 _ AS17-146 艾:

原载于 2019 年 5 月 8 日 https://blog.exxactcorp.comT21

使用神经网络逼近 2019 年奥斯卡投票者的想法

原文:https://towardsdatascience.com/approximating-the-minds-of-2019-oscars-voters-using-neural-networks-b922f3d6864c?source=collection_archive---------15-----------------------

Credit: Disney | ABC Television Group

介绍

提名公布后的一个月里,各大娱乐新闻媒体纷纷发表文章,证明预测奥斯卡奖得主是一项强迫性的运动。我从来没有密切关注过任何颁奖仪式,我一直以为每个被提名者都以大致相等的几率进入这场迷人的混战,而客观上最好的那个类别将获得胜利。不是这样的!事实证明,任何数量的因素都可以影响投票者,可以说,其中大多数因素都可以量化,并由神经网络来消耗。这些因素中的一些是工艺协会奖的获得者,但今年的奥斯卡奖之所以如此有趣,是因为有史以来第一次,他们都选择了授予不同的电影。

简单地说,神经网络是一种机器学习技术,旨在通过获取输入并判断它们的相对重要性来估计一条信息(或输出),从而模仿人脑。以这种方式解决问题背后的理念是,每个问题的某些因素更重要。例如,如果你试图评估一个人是否患有糖尿病,那么他的身体质量指数将是一个比他的年薪更重要的因素。通过在已知输出的大数据集上训练网络,可以确定输入的重要性或权重。下面,我提出了一种利用神经网络预测奥斯卡最佳影片的方法。

放弃

截至 2017 年,该学院拥有 6687 名行业专业人士(根据维基百科),他们都对今年的“最佳影片”提名有无数的个人意见。因此,不可能 100%肯定地说今年的 8 位提名者中哪一位会把桂冠带回家…所以请不要在我预测的这部电影上下注!

收集数据

当然,第一个问题是,有什么样的迹象表明一部电影可以赢得奥斯卡最佳影片奖?幸运的是,我在帝国在线找到了一篇名为【如何预测奥斯卡奖】的文章,这篇文章是好心人提供的。它规定,一部电影要赢得“最佳影片”,需要具备以下条件:

  1. 这部电影的导演至少需要获得“最佳导演”提名,奥斯卡奖历史上只有四部电影无视这一规则。
  2. 这部电影需要获得“最佳改编剧本”或“最佳原创剧本”提名。
  3. 美国演员工会(SAG)与奥斯卡投票者有很大的交集。与“最佳影片”相对应的奖项是“演员在电影中的杰出表现”奖(也被称为“演员工会奖”),根据《帝国》的说法,获得提名对于赢得“最佳影片”来说(几乎)是至关重要的。我说差不多……去年的获奖者水的形状没有获得这个奖项的提名。
  4. 无论是动画还是外国电影都没有获得过“最佳影片”。这对今年(以及神经网络)有着有趣的影响!)作为墨西哥电影《T2 罗马》(T3),T4 被广泛认为是领跑者(T5)。
  5. 一部获得 SAG ensemble 奖、美国制片人协会“杰出制片人奖”和美国导演协会“故事片杰出导演奖”的电影可以有把握地获得“最佳影片”(有几个明显的例外)。

这篇文章中另一个有趣的地方是上述每一种预测奥斯卡最佳影片的成功率。影评人选择奖以 60%的准确率领先(然而,他们只是从 1996 年开始运行,所以样本量较低),其次是英国电影电视艺术学院奖的 55%,美国演员工会奖的 50%和金球奖“最佳电影-戏剧”类别的 45%。值得注意的是,金球奖还颁发了一个名为“最佳音乐/喜剧电影”的奖项。《帝国》没有报道这个奖项的成功率。然而,根据维基百科,该奖项(或 1958 年至 1962 年间短暂脱钩的奖项之一)的 12 名获奖者在 72 个奖项中获得了“最佳影片”,命中率为 17%。因此,我打算在预测奥斯卡将颁发“最佳影片”方面胜过广播电影评论家协会的优秀成员——他们颁发了评论家选择奖。

在这篇文章中,我将训练两个神经网络。网络 A 将排除美国制片人协会奖(est。美国演员工会奖(美国东部时间 1989 年)1995)和评论家选择奖(est。1996)并且网络 B 将包括它们。这是因为他们作为一个整体只有 22 年的数据,而奥斯卡、英国电影电视艺术学院、金球奖和美国导演协会(Directors' Guild of America)都是从(至少)1948 年开始颁奖的,这大约会使数据点的数量增加一倍。

训练网络

做出这样的预测似乎是一个分类问题,有两种可能的结果——最佳影片奖,或者不是。然而,这并没有考虑到在一组精选的数据中只选出一个获胜者的限制,或者实际上的“被提名者”。因此,我认为这可以被视为一个回归问题,其中输出是一个连续变量,它转化为电影是“最佳影片”赢家的概率。然后,我们可以在一组被提名者中做出决定性的选择,选出可能性最大的一个。

前馈网络是第一种神经网络,简而言之,它是节点(或神经元)的有向图,首先接受输入,其中之一可能是“一部电影有多少项提名?”。然后,它将这些输入传递给网络隐藏层中的神经元,这些神经元应用一个激活函数,试图确定每个输入的重要性。最后计算输出值,例如这部电影有 0.2 的机会赢得“最佳影片”。我们可以通过计算网络输出和我们知道的输出之间的差异来衡量网络的成功。使用训练函数来执行训练,目的是最小化预测中的误差,并且尽可能快地训练网络。

为具有特定层数、神经元和最佳训练函数的网络选择一种架构并不是一门精确的科学。选择架构有几种不同的方法,这取决于您的问题有多严重。例如,如果您试图使用神经网络(如引言中所述)来诊断糖尿病,那么您可能希望仔细选择(可能使用遗传算法)一种具有高准确性和诊断糖尿病倾向的架构,而不是让潜在的患者在未诊断的情况下漏网。我的问题绝不是关键问题,所以我选择架构的方法将是不同技术组合的基本网格搜索。

网络 A

在选择训练数据方面,我决定从 1951 年开始,这是第一年颁发金球奖最佳音乐或喜剧电影奖。这给了我从那时到 2015 年的 65 个数据点,不包括独立验证的两年数据。注意,我对网络 A 使用了 12 个输入,如下所示:英国电影电视艺术学院奖“最佳影片”;获得金球奖最佳喜剧/音乐剧提名或奖项;金球奖最佳剧情类电影提名或获奖;这部电影获得的奥斯卡提名总数;奥斯卡最佳导演提名;这部电影的电影剧本获得奥斯卡提名;不管是动画还是外国电影;和美国导演协会奖或提名“故事片杰出导演奖”。

我首先尝试分离出这个问题的最佳训练函数,为此,我创建了许多具有不同训练函数的网络,并控制隐藏层数量(1)和神经元数量(10)的常量变量。然后我每个人训练五次,取他们表现的平均值。我选择多次训练网络,每次训练在优化前使用不同的权重和偏差进行初始化,这意味着每次训练网络都可能得到更好或更差的结果。通过取每次训练表现的平均结果,我可以为这个特定的问题建立最佳的训练函数。对于这个数据集,具有动量训练函数的梯度下降是最佳的。

接下来,我尝试了不同的层数和神经元数的组合。杰夫·希顿在他写的《Java 神经网络导论》中规定,一个神经网络只需一个隐层,输入层(12)和输出层(1)神经元的平均值就可以达到很好的性能。我决定对层的集合{1,2}和神经元的集合{1,3,6,10,12}进行采样,总共十个组合。因此,举例来说,对(2,6)将有两个隐藏层,每个层有六个神经元。我再次对每个不同的网络进行了五次训练,以找到最佳的层/神经元组合,令我颇为不安的是,结果是一个隐藏层有十个神经元——这是我建立最佳训练函数的原始控制变量。真是搪塞!

所以我为这个问题建立了最好的神经网络结构:一个隐藏层;十个神经元;和具有动量训练功能的梯度下降。这种架构在测试集上实现了 79.9%的准确率,在验证集上实现了 78.4%的准确率,总体平均准确率为 79.2%…比评论家选择奖好得多!

网络 B

由于这个网络中考虑的三个颁奖仪式的时间都不长,我只能使用 1996 年以来的数据,这给了我 20 个数据点——比以前少得多。要注意的是,我使用了 18 个输入,这些输入与上面列出的输入完全相同,但增加了以下六个:演员工会提名或“电影演员的杰出表现”奖,评论家选择提名或“最佳影片”奖,以及美国制片人工会提名或“杰出制片人”奖。

为了节省时间,并且考虑到训练数据与网络 A 的输入数据共享三分之二的输入数据,我决定仅使用之前的数据集测试我的前三个架构。这实现了以下目标:

  1. 一个隐藏层;十个神经元,GDM——准确率 65.2%
  2. 两个隐藏层;十二个神经元,GDM——49%的准确率
  3. 三个隐藏层;十个神经元,GDM——58.7%的准确率

因此,再一次,具有 10 个神经元的单个隐藏层是最佳架构,尽管对于这样一个 20 点的精简数据集,我相信结果比更大的数据集更不稳定。例如,在训练时,我两次看到验证集只有目标输出为 0 的数据点,换句话说,它没有“最佳图片”获胜者的数据。因此,我将更加怀疑网络 B 产生的结果。

独立验证

我为自己保留了两年的数据,以独立验证这些网络是否达到了上述精度。对 2016 年和 2017 年最佳影片奖的预测如下表所示:

关键:粗体显示最有可能的赢家,斜体显示第二有可能的赢家

我认为,从这一独立的核查工作中可以得出一些有趣的结论。首先,尽管第二个网络有一半的数据点和六个额外的输入,但在这里似乎网络的估计并没有太大的不同。有趣的是,虽然网络 A 比网络 B 更有信心预测错误的赢家(啦啦地),但它也更有信心预测第二可能的赢家(月光),即最终的赢家。两个网络都正确地确定了 2017 年的获胜者,网络 B 在确定性方面领先于网络 A。最后一点很简单,和 2016 年一样,奥斯卡有时会忽略统计风吹来的方式,给自己最喜欢的电影颁奖!毕竟,如果你知道谁会是赢家,那就没什么看头了。也就是说,我仍然会尝试预测赢家。

今年的冠军将会是…

罗马

根据这两个神经网络, Roma 已经克服了前进道路上的障碍(这是奥斯卡奖历史上第十部获得“最佳影片”提名的外语片,此前没有获奖),摘得概率桂冠。他们也同意第二大可能的赢家,绿皮书。接下来还会有更多的差异,这可能会引发人们对美国演员工会奖等新设立奖项的影响的质疑。但现在,我屏住呼吸等待,直到 2 月 24 日,看看我是否正确…

任何想进一步了解我是如何得出这些结论的人,都可以查看我的 GitHub 库,里面包含了我所有的资源和脚本。我为此使用的网络训练工具是 MATLAB 的深度学习工具箱。

承认

非常感谢 http://www.ya-shin.com 的维护者,他们提供了截至 2006 年的奥斯卡奖、金球奖奖和英国电影电视艺术学院奖的完整名单。如果没有他们出色的电子表格(仅奥斯卡提名者和获奖者就有 8832 项记录),我可能已经迷失了。

四月版:强化学习

原文:https://towardsdatascience.com/april-edition-reinforcement-learning-badbb1726722?source=collection_archive---------14-----------------------

如何建立一个真正的人工智能代理

强化学习(RL)是指面向目标的算法,其中“代理”学习完成一个特定的目标或目的,同时在许多步骤中最大化一组“奖励”。RL 代理人是人们在描述电影中描绘的“人工智能”时经常想到的。RL 代理通常从空白开始,在正确的条件下,当它了解其环境时,可以实现惊人的性能。

当 RL 算法做出错误的决定时,它们会受到惩罚,而当它们做出正确的决定时,它们会受到奖励,因此出现了术语“强化学习”。建立环境,选择合适的算法/策略,设计奖励函数,为实现代理的预期行为提供激励——这些都是使强化学习成为一个迷人而复杂的领域的一些方面。

强化学习的应用在多个行业各不相同,包括机器人、聊天机器人和自动驾驶汽车。大多数强化学习的新生都是通过使用 OpenAI Gym 框架来了解 RL 的。TDS 作者,霍纳塔斯·菲格雷多和维哈尔·鞍马写了关于 OpenAI 和 RL 的优秀文章,让你开始使用 Python 。一旦你在 RL 方面打下了基础,那么看看更复杂的应用程序,比如训练代理打网球或者使用 RL 训练聊天机器人。

— Hamza Bendemra ,编辑助理,致力于数据科学。

强化学习在现实世界中的应用

由 Garychl — 13 分钟读完

虽然卷积神经网络(CNN)和递归神经网络(RNN)因其在计算机视觉(CV)和自然语言处理(NLP)中的应用而对企业变得越来越重要,但强化学习(RL)作为计算神经科学的框架来模拟决策过程似乎被低估了。

OpenAI 健身房从零开始

到霍纳塔斯·菲格雷多 — 10 分钟读完

有很多工作和教程解释了如何使用 OpenAI Gym toolkit,以及如何使用 Keras 和 TensorFlow 来训练使用一些现有 OpenAI Gym 结构的现有环境。然而在本教程中,我将解释如何从头开始创建一个 OpenAI 环境,并在其上训练一个代理。

用 Python 进行强化学习

由维哈尔·鞍马 — 11 分钟阅读

强化是一类机器学习,其中代理通过执行动作来学习如何在环境中行为,从而得出直觉并看到结果。在本文中,您将学习理解和设计一个强化学习问题,并用 Python 来解决。

训练机器人打网球

托马斯·特雷西 — 16 分钟阅读

这篇文章探索了我在 Udacity 的深度强化学习纳米学位的最终项目中的工作。我的目标是帮助其他机器学习(ML)学生和专业人士,他们正处于在强化学习(RL)中建立直觉的早期阶段。

几分钟学会平稳驾驶

由安东宁·拉芬 — 11 分钟阅读

在这篇文章中,我们将看到如何在几分钟内训练一辆自动驾驶赛车,以及如何平稳地控制它。这种基于强化学习(RL)的方法,在这里的模拟(驴车模拟器)中提出,被设计成适用于现实世界。它建立在一家名为 Wayve.ai 的专注于自动驾驶的初创公司的工作基础上。

用图形网络控制机器人

通过或 Rivlin — 9 分钟读取

正如任何对技术感兴趣的人无疑都知道的那样,机器学习正在帮助改变不同行业的许多领域。在过去的几年里,由于深度学习算法,计算机视觉和自然语言处理等事情发生了巨大的变化,这种变化的影响正在渗透到我们的日常生活中。

用深度强化学习训练一个目标导向的聊天机器人(第一部分、第二部分、第三部分、第四部分、第五部分)

通过最大布伦纳 — 10 分钟读取

在这个系列中,我们将学习面向目标的聊天机器人,并用 python 训练一个具有深度强化学习的聊天机器人!一切从零开始!这个系列教程的代码可以在这里找到。

我们也感谢最近加入我们的所有伟大的新作家,马科斯·特雷维索,大卫·康弗,让·克利斯朵夫·b·卢瓦索,莫里茨·基尔希特,卡尔·温梅斯特,卡梅隆·布朗斯坦,阿曼·迪普,雅各布·戴维斯,詹姆斯·迪特尔,扎伊我们邀请你看看他们的简介,看看他们的工作。

APTOS 2019 失明检测

原文:https://towardsdatascience.com/aptos-2019-blindness-detection-520ae2a4acc?source=collection_archive---------18-----------------------

使用人工智能检测糖尿病视网膜病变,在为时已晚之前阻止失明。

Image credits http://medi-whale.com

糖尿病视网膜病变是一种影响眼睛的糖尿病并发症。视网膜光敏组织的血管受损会导致这种并发症。糖尿病视网膜病变(DR)是全球失明的主要原因。全世界大约 2 . 85 亿糖尿病患者中有三分之一有 DR 的迹象。

想象一下,能够在灾难恢复造成问题之前检测到它。早期发现糖尿病视网膜病变可以挽救数百万糖尿病患者的视力,这也是亚太远程眼科学会(APTOS)在 Kaggle 中提出的一个问题的目标。

点击了解更多关于比赛的信息。

我对检测高危患者失明的想法很感兴趣,这也是我试图使用人工智能解决这个问题的动机。APTOS 提供了大量在各种成像条件下拍摄的眼底照相视网膜图像。这些数据是多样的和广泛的。

临床医生对每张图像的糖尿病性视网膜病变的严重程度进行评分,等级为 0-4,其中数字代表并发症的程度,如下所示:

这是一个图像分类问题。

图像分类处理理解图像及其与类别相关的上下文。为了将一组数据分组为不同的类或类别,机器学习算法理解数据和它们被分类到的类之间的关系。

由于深度学习在准确性方面优于不同的预测方法,所以它越来越受欢迎,我决定使用深度学习解决方案来分类这些图像。这里有两个图表描述了传统机器学习和深度学习的区别。

在传统的机器学习技术中,领域专业知识是必要的,因为大多数不同的特征和类别必须被标记。只有在你成功识别了相关特征之后,机器学习算法才能识别模式并给出准确的输出。

深度学习算法与传统的机器学习算法相比具有很大的优势,因为它们以增量的方式从数据中学习高级特征,无需领域专业知识和核心特征提取。特别是对于复杂的问题,如图像分类、自然语言处理和语音识别,需要深度学习算法才能做到准确和精确。

为什么要转学?

深度学习模型需要大量的数据和资源来进行适当的训练。一般来说,数据越多,输出越准确。例如,ImageNet ILSVRC 模型在 2-3 周的时间内跨多个 GPU 对 120 万张图像进行了训练。迁移学习是一种机器学习方法,其中工程师为一项任务开发一个模型,并将其作为第二项任务的模型的起点。

在深度学习中,一种流行的方法是使用预训练的模型作为起点,最后一个全连接层被移除并由自定义的全连接层取代,将原始 CNN 视为新数据集的特征提取器。一旦被替换,最后一个完全连接的层被训练为新数据集的分类器。

为了解决这个问题,我选择了 Inception v3。Inception-v3 是一个卷积神经网络,它在 ImageNet 数据库中的超过一百万张图像上进行训练。因此,该网络学习了各种图像的丰富特征表示。网络的图像输入大小为 299 x 299。

我建立了一个机器学习模型,使用一个名为 S kyl 的端到端机器学习平台来加速疾病检测。我就是这么用的。

创建项目

Skyl 中的一个项目允许你根据你选择的模板来简化你的机器学习项目。因为这个问题是一个影像分类问题,所以我选择了影像分类(多类)模板,并根据我的需求配置了我的项目。

配置数据集

配置数据集意味着定义数据集的外观、内容以及分类值。输入数据集的名称、简短描述和类别值。我将我的数据集命名为:“失明检测数据集”,并将类别命名为无 DR、轻度、中度、重度、增生性 DR。

上传数据

Skyl 提供了许多收集数据的选项,如收集 API、CSV 上传、移动和基于表单的收集。我使用收集 API 选项来上传平台中的数据。

我从 Kaggle 下载了数据,并编写了一个脚本,将数据上传到之前在 Skyl 平台上创建的名为“失明检测数据集”的数据集中。

Skyl 为发现数据偏差提供了数据可视化。有偏见的数据会导致自我实现的预言和灾难性的结果,这是应该避免的。

创建功能集

特征集是数据集的子集,最终用作训练模型的输入。我创建了特征集,并检查了数据是否是类平衡的,以在训练中获得最佳结果。

模特培训

前面说过,我选择迁移学习进行模型训练。我使用 Skyl 的优化算法来训练 ML 模型,这些模型是根据 ML 模板列出的。我选择了'卷积神经网络(CNN) +迁移学习【T1]'作为算法,我通过其训练数据的特征集,历元数为 10,学习率为 0.001,添加模型名称和描述,最后初始化训练。

一旦训练完成,它就会创建一个机器学习模型,列在“模型”下。该模型达到了 72%的准确率——对于 25 分钟内没有工作的情况来说,这已经很高了。您还可以查看模型的培训总结报告。

模型部署

训练结束后,我部署了模型,推理 API 被自动创建。我复制了 API,用它来做预测。

这就是我如何创建一个用于失明检测的深度学习模型。如果你们有任何问题或建议,请在下面的评论区联系我。
想看看我用的平台,这里有链接: https://skyl.ai

通过联系 Skyl 的团队,您可以很容易地获得一个供个人使用的免费帐户。

快乐学习!!

AR 来了,准备卖给你一台吸尘器

原文:https://towardsdatascience.com/ar-is-here-and-its-ready-to-sell-you-a-vacuum-cleaner-4bf23ee58c73?source=collection_archive---------36-----------------------

这不再仅仅是为了抓口袋妖怪

Credit: Gado Images

昨天,我在地毯上试用了一种地毯清洁剂。我知道,这听起来是有史以来最无聊的一篇文章。但是请原谅我。

有趣的部分来了。地毯清洁器其实不是我的。我没有买它,但它就在我家里。

不,这不是一个关于入店行窃的中篇报道。事实上,我家地板上的地毯清洁剂并不存在。

真实的地方,假的东西

我的地毯上怎么会有假家电?它是由电子商务巨头亚马逊购物应用程序的一个引人注目的新功能放在那里的。该功能被无害地标记为“在我的房间里看。”它允许你从亚马逊调出许多产品的虚拟版本,并在你的真实家中看到它们。

该功能是这样工作的。你选择一件你感兴趣的商品,然后把它加载到你的亚马逊应用程序上。然后你按下“在我房间里看”你的手机切换到相机视图,你把它指向你房间里你想要放置新的假物体的地方。出现一个绿色框,您点击将产品放下。

Moving your phone around allows you to see the virtual object from any angle. Credit: Gado Images

这就是事情变得不可思议的时候。当你四处移动你的手机摄像头时,看起来好像这个产品实际上是坐在你的房间里。你可以走来走去,从各个角度观察它,蹲下来从下面看它,甚至走进一个不同的房间,然后走回来。当你把手机放回你“放”产品的位置时,它仍然会在那里,就好像它一直在你的房间里一样。

现实,但更好

亚马逊的新功能是名为增强现实(AR)的虚拟现实子集的一部分。与试图将你从现实中转移到另一个沉浸式现实中的更传统的虚拟现实系统相比,AR 将现实带到你面前,并将其转化为不同的更好的东西。它正在迅速获得牵引力,部分原因是它不需要传统虚拟现实中笨重、昂贵的眼镜。

Traditional VR is immersive, but requires bulky hardware. Credit: Gado Images.

这项技术的工作原理是分析真实空间,并理解它们的物理参数。然后,它获取一个对象的虚拟 3D 模型,确定它在实际的物理空间中的外观,并虚拟地将该对象绘制进来。

当你四处移动手机时,系统会不断观察你在现实空间中的角度是如何变化的,并更新虚拟物体的位置,使其保持一致。虚拟物体实际上不断被重画,以适应你对空间不断变化的看法,这一切都是为了模拟它只是随意地坐在你的地板上的效果。

现实世界中的 AR

到目前为止,ar 主要应用于游戏等领域。全球现象口袋妖怪 Go 就是一个最好的例子。它使用 AR 和地理定位将虚拟口袋妖怪放置在现实世界的位置,促使一大群人挥舞着他们的手机在你当地的公园里闲逛。

Gotta catch ’em Credit: Gado Images

有了亚马逊这样的应用,AR 就成长起来了。我们知道它的真正目的是卖给你一台吸尘器。

看到一个虚拟的地毯清洁器叠加在我的地毯上真是太棒了。但是,对于亚马逊的新 AR 功能来说,有一些真正有用的应用程序,以及增强其面向零售的使命的应用程序。

一个显而易见的优势是能够看到新设备在空间中的外观和适合度。我用亚马逊回声秀的虚拟版本测试了这一点。通过 AR 功能,我可以将它放在我的厨房柜台上,并环顾四周,看看它与我的其他东西是否合适,它对于空间来说是否太大或太小,等等。

Credit: Gado Images

与我的真实回声秀相比,虚拟看台做得相当好。它大小合适,放置正确,甚至以与真实设备相似的方式反射光线。

The real Echo Show in the same space. Credit: Gado Images.

虽然它很适合查看电子产品,但亚马逊也希望你能把它用于更大的东西。让人们在网上购买像家具这样的大件商品——网站看不见——是一个巨大的挑战。

亚马逊希望,如果你能在你的空间里放置一个新沙发的虚拟副本,并确保它符合你的装饰,你会更倾向于购买它。他们可以避免拥有昂贵的实体展厅的成本。现在,如果他们能模拟你坐在上面的感觉,他们会是金色的…

AR 的未来

今天的 AR 已经非常强大,但它的主要焦点是向现有的真实空间添加东西——无论是地毯吸尘器、口袋妖怪还是沙发。

未来的 AR 将超越这一点,实时无缝地改变你对空间的看法。

Sherwin Williams 已经在他们的 Colorsnap 应用程序中提供了一个版本。你可以打开应用程序,从他们的虚拟油漆样本中选择一种颜色,举起你的家,看到应用程序虚拟地“油漆”你选择的颜色。它并不完美,但它给人一种颜色看起来如何的感觉。同样,和亚马逊一样,它的目标是帮助你在不去实体店的情况下做出购买选择。

随着生成性敌对网络和其他快速改变图像的工具的增长,我相信我们会看到这种增加现实的概念走得更远。

想象一下,一家服装零售商有一个应用程序,你可以在那里打开自拍相机。该应用程序将实时使用 AR,让它看起来像你穿着零售商的任何服装。你甚至可以给每件新衣服拍一张自拍,然后发给朋友帮忙挑选。它就像一个 Snapchat 过滤器,但它可以帮助你购买一件衬衫,而不是让你吐彩虹。

这个概念可能会超越零售,产生更大的影响。美林(Merrill Lynch)等金融公司已经试验了人工老化客户照片的技术。人们希望,如果他们从每月的账单上看到 70 岁的自己,他们会为退休存更多的钱。

但是深入一点呢?有没有一款应用程序可以改变现实,通过展示你在身体残疾时的样子来建立同理心?还是在变性手术后?性别交换已经存在,可以用于这些更有益的目的。

其他技术也可能开始与 AR 更全面地集成。谷歌已经试验了一个增强现实版本的谷歌地图,在这个版本中,巨大的浮动箭头会自动出现在你手机屏幕上的真实世界视图中,当你走到目的地时,给你一个完美的方向感。借助 3D 成像技术,你可以在视频通话期间拍摄某人的实时 3D 视频,并使用 AR 将它们叠加到你的桌子上,就像莱娅公主/R2D2 风格一样。

平视显示器将数据嵌入到你对现实世界的视野中,也越来越受欢迎。在谷歌眼镜等技术的早期失误之后,AR 行业已经成功地将 hud 集成到滑雪眼镜、自行车头盔和高端汽车中。人们对智能眼镜的兴趣甚至有所复苏,尽管没有 Startrek 的外观,而且希望减少非法的更衣室快照。

我的虚拟真空

最后,我买了地毯清洁剂。真的和我在亚马逊应用上看到的假的看起来差不多。

是不是在 AR 看到的让我更有可能去买?我不确定。我认为更传统的因素,比如好评和合理的价格,是更大的激励因素。但在 AR 中看到它是一个考虑它而不是其他模型的理由,这需要我使用我的实际想象力来描绘它们在我的空间中会是什么样子。

虽然 AR 现在主要是一个令人惊叹的功能,但随着手机和可穿戴设备变得越来越强大,它的影响力将会越来越大——我们会花更多的时间粘在它们身上。随着新的图像处理技术的进步,比如 GANs,它们的输出将变得更加身临其境,也更加引人注目。

如果你还没有尝试过 AR,下载一个支持 AR 的应用程序,然后查看一下。而如果那个 app 竟然是 Pokemon Go,不用担心,我不会评判。

构建机器学习管道

原文:https://towardsdatascience.com/architecting-a-machine-learning-pipeline-a847f094d1c7?source=collection_archive---------0-----------------------

现实世界中的数据科学

如何构建可扩展的 ML 系统—第二部分

前言

在开发模型时,数据科学家在一些为统计和机器学习(Python、R 等)量身定制的开发环境中工作,能够在一个“沙盒”环境中训练和测试模型,同时编写相对较少的代码。这对于构建快速上市的交互式原型非常有用——尽管它们不是生产性的低延迟系统!

这是系列文章的第二篇,即“ ”成为数据科学家并不能让你成为软件工程师!’,涵盖了如何构建端到端的可扩展机器学习(ML)管道。

修订本

[## 成为数据科学家并不能让你成为软件工程师!

如何构建可扩展的机器学习系统——第 1/2 部分

towardsdatascience.com](/being-a-data-scientist-does-not-make-you-a-software-engineer-c64081526372)

希望您已经阅读了本系列的第 1 部分,在那里我们介绍了基本的架构风格、设计模式和坚实的原则。

📌TL;DR: 如果你没有读过,让我们重复一下“圣杯”——即一个生产就绪的 ML 系统应该试图解决的问题陈述:

主要目标是建立一个系统,该系统:
减少延迟
与系统的其他部分集成但松散耦合,例如数据存储、报告、图形用户界面;
可以水平和垂直缩放
?是消息驱动的,即系统通过异步、无阻塞的消息传递进行通信;
针对工作量管理提供高效的计算;
容错和自愈即故障管理;
支持批量实时加工。

🎦场景设置:至此,你已经了解了软件工程的基本概念,并且已经是一名经验丰富的数据科学家。

事不宜迟,让我们把两个和两个放在一起…

对于每一个 ML 流水线步骤,我将演示如何设计一个生产级架构。我将有意不提及任何特定的技术(除了几次出于演示的目的我举了一些例子)。

✏️注意:如果您需要更新 ML 管道步骤,请查看该资源。

ML Pipeline

构建 ML 管道

传统上,管道涉及通宵批处理,即收集数据,通过企业消息总线发送数据,并对其进行处理,以提供预先计算的结果和第二天操作的指导。虽然这在一些行业中行得通,但在其他行业中确实不够,尤其是在 ML 应用中。

下图显示了应用于实时业务问题的 ML 管道,其中功能和预测对时间敏感(例如,网飞的推荐引擎、优步的到达时间估计、LinkedIn 的连接建议、Airbnb 的搜索引擎等)。

Real-Time ML

它由两个明确定义的部分组成:

  • 在线模型分析:最上面一行代表应用的操作组件,即模型应用于实时决策制定的地方。
  • 离线数据发现:最下面一行表示学习组件,即分析历史数据,以批处理模式创建 ML 模型。

我们现在将采用这个简化的图表并展开其内部工作原理。

— ①:数据摄取

数据收集。

将传入的数据汇集到数据存储中是任何 ML 工作流的第一步。关键的一点是,数据是持久化的,根本不需要进行任何转换,以允许我们拥有原始数据集的不可变记录。数据可以来自各种数据源;或者通过请求(发布/订阅)获得,或者从其他服务流获得。

NoSQL 文档数据库非常适合存储大量快速变化的结构化和/或非结构化数据,因为它们是无模式的。它们还提供分布式、可扩展的复制数据存储。

脱机的

在离线层,数据通过摄取服务流入原始数据存储,这是一个复合编排服务,封装了数据源和持久性。在内部,存储库模式用于与数据服务交互,数据服务反过来与数据存储交互。当数据保存在数据库中时,一个唯一的 batch-id 被分配给数据集,以允许高效的查询和端到端的数据沿袭和可追溯性。

为了提高性能,摄入分布是双重的:

每个数据集都有一个专用的管道,因此它们都是独立和并发处理的,并且
在每个管道内,数据被
分区以利用多个服务器内核、处理器甚至服务器。

将数据准备工作横向和纵向分布在多个管道中,可以减少完成工作的总时间。

摄取服务按照计划(每天一次或多次)或按照触发器定期运行:主题将生产者(即数据源)与消费者(在我们的例子中是摄取管道)分离,因此当源数据可用时,生产者系统向代理发布消息,嵌入式通知服务通过触发摄取来响应订阅。通知服务还向代理广播源数据已经成功处理并保存在数据库中。

在线的

在在线层,在线摄取服务是流架构的入口点,因为它通过提供可靠、高吞吐量、低延迟的功能,分离和管理从数据源到处理和存储组件的信息流。它作为企业级的数据总线。数据保存在长期原始数据存储中,但也是到下一个在线流媒体服务的直通层,用于进一步的实时处理。

这里使用的示例技术可以是 Apache Kafka(发布/订阅消息系统)和 Apache Flume(长期数据库的数据收集),但是您还会遇到更多,这取决于您企业的技术堆栈。

— ②:数据准备

数据探索、数据转换和特征工程。

一旦接收到数据,就会生成一个分布式管道来评估数据的状况,即寻找格式差异、异常值、趋势、不正确、缺失或扭曲的数据,并在此过程中纠正任何异常。这一步还包括特征工程过程。特征管道中有三个主要阶段:提取、转换和选择。

Feature Engineering Operations

由于这是 ML 项目中最复杂的部分,引入正确的设计模式是至关重要的,因此就代码组织而言,拥有一个工厂方法来基于一些常见的抽象特性行为生成特性,以及一个策略模式来允许在运行时选择正确的特性是一个明智的方法。特征提取器和转换器的结构都应该考虑到组合和可重用性。

选择特征可以留给呼叫者,或者可以自动进行,例如应用卡方统计测试对每个特征对概念标签的影响进行排序,并在模型训练之前丢弃影响较小的特征。可以定义一系列选择器 API 来实现这一点。无论哪种方式,为了确保用作模型输入和评分的特征的一致性,为每个特征集分配一个唯一的 id

概括地说,数据准备管道应该被组装成一系列不可变的转换,这些转换可以很容易地被组合。这就是测试的重要性和高代码覆盖率成为项目成功的重要因素的地方。

脱机的

在离线层,数据准备服务,由摄取服务的完成触发。它获取原始数据,承担所有特征工程逻辑,并将生成的特征保存在特征数据存储中。

同样的划分也适用于此(即专用管道/并行)。

可选地,来自多个数据源的特征可以被组合,因此“连接/同步”任务被设计为聚集所有中间完成事件并创建这些新的组合特征。最后,通知服务向代理广播这个过程已经完成,并且特性是可用的。

当每个数据准备管道完成时,特征还会被复制到在线特征数据存储中,因此可以低延迟地查询特征以进行实时预测。

在线的

原始数据从摄取管道流入在线数据准备服务。生成的特征存储在内存 在线特征数据存储中,可在预测时以低延迟读取,但也保存在长期特征数据存储中,以备将来训练。此外,可以通过从长期特征数据存储中加载特征来预热存储器中的数据库。

继续前面的技术栈例子,一个常用的流媒体引擎是 Apache Spark。

🔍离线钻取:如果我们要钻取离线接收和数据准备服务交互,我们将得到如下内容:

(1) 一个或多个数据生产者向消息代理的指定“源数据可用”主题发布事件,表明数据可供使用。
(2)摄取服务在听题目。
一旦接收到相应的事件,它将通过以下方式进行处理: (3) 获取数据并 (4) 将其以原始格式保存在数据存储中。
(5)当流程完成时,它会向“提取原始数据”主题引发一个新事件,以通知原始数据已准备就绪。
(6)数据准备服务在听题目。
一旦接收到相应的事件,它通过以下方式进行处理: (7) 获取原始数据,准备原始数据并设计新功能,以及 (8) 将功能保存在数据存储中。
(9)当流程完成时,它会向“特性已生成”主题引发一个新事件,以通知特性已生成。

Offline Data Ingestion / Preparation Interactions

— ③:数据隔离

拆分数据子集以训练模型,并进一步验证它对新数据的表现。

ML 系统的基本目标是使用基于其模式预测质量的精确模型来预测未经训练的数据。因此,通过将现有标记数据分成训练和评估子集,现有标记数据被用作未来/不可见数据的代理

有许多策略可以做到这一点,其中四个最常见的是:

使用默认或自定义比率将其分成两个子集,按顺序,即按其在信号源中出现的顺序,确保没有重叠。例如,前 70%的数据用于训练,后 30%的数据用于测试。
使用默认或自定义比率,通过随机种子将其分成两个子集。例如,随机选择 70%的源数据用于训练,随机子集的补充数据用于测试。
使用上述方法中的任何一种(顺序或随机),同时在每个数据集中打乱记录。
当需要对分离进行显式控制时,使用自定义注入策略分割数据。

数据分离本身并不是一个独立的 ML 管道,但是必须有一个 API 或服务来帮助完成这个任务。接下来的两个管道(模型训练和评估)必须能够调用这个 API 来取回所请求的数据集。就代码组织而言,策略模式是必要的,以便调用方服务可以在运行时选择正确的算法,并且显然需要能够注入比率或随机种子。此外,API 必须能够返回带有或不带有标签/特征的数据——分别用于训练和评估。

为了防止调用者指定导致不均匀数据分布的参数,应该发出警告并随数据集一起返回。

— ④:模型训练

使用数据的训练子集让 ML 算法识别其中的模式。

模型训练管道是离线的,它的时间表根据应用程序的关键程度而变化,从几个小时一次到一天一次。除了调度器之外,该服务也是时间和事件触发的。

它由一个训练模型算法库(线性回归、ARIMA、k-means、决策树等)组成,以一种可靠的方式构建,为新模型类型的持续开发做准备,并使它们可以互换。使用 facade 模式的包容也是集成第三方 API 的关键技术(这也是 Python Jupyter 笔记本可以被包装和调用的地方)。

并行化有几个选项:

最简单的形式是为每个型号配备一个专用管道,即所有型号同时运行。
另一个想法是将
训练数据并行化,即数据被分区,每个分区有一个模型的副本。这对于那些需要实例的所有字段来执行计算的模型(例如 LDA、MF)是优选的。
第三种选择是将
模型本身并行化,即模型被分区,每个分区负责一部分参数的更新。这是线性模型的理想选择,如 LR,SVM。
最后,可以使用一种
混合方法,结合一个或多个选项。(要了解更多信息,我推荐你阅读这本出版物)。

在实施模型训练时,必须牢记容错,并且应启用训练分区上的数据检查点和故障转移,例如,如果之前的尝试由于某些瞬时问题(例如超时)而失败,则可以重新训练每个分区。

既然我们已经介绍了这个管道的功能,那么让我们打开工作流:模型训练服务从配置服务获得训练配置参数(例如,模型类型、超参数、要使用的特性等),然后从数据分离 API 请求训练数据集。该数据集被并行发送给所有模型,一旦完成,模型、原始配置、学习到的参数以及关于训练集和计时的元数据将被保存在模型候选数据存储中。

— ⑤:候选模型评估

使用数据的测试子集评估模型的性能,以了解预测的准确性。

这条管道也是下线。通过使用各种度量标准将评估数据集上的预测值与真实值进行比较,来评估模型的预测性能。选择评估子集上的“最佳”模型来对未来/新实例进行预测。由多个评估者组成的库旨在提供模型的准确性度量(如 ROC 曲线、PR 曲线),这些度量也根据模型保存在数据存储中。同样,同样的模式也适用于这里,允许在评估器之间灵活地组合和切换。

在编排方面,模型评估服务从数据分离 API 请求评估数据集,并且对于来源于模型候选库的每个模型,它应用相关的评估器。评估结果被保存回存储库。这是一个迭代过程,超参数优化以及正则化技术也被应用于最终模型。最佳模型被标记用于部署。最后,通知服务广播模型已经准备好进行部署。

这个管道还需要符合所有的反应特征。

— ⑥:模型部署

一旦选定的模型产生,它通常被部署并嵌入到决策框架中。

模型部署不是终点;这只是开始!

选择的最佳模型被部署用于离线(异步)和在线(同步)预测。可随时部署多个模型,以实现新旧模型之间的安全过渡——即当
部署新模型时,服务需要继续服务预测请求。

传统上,部署中的一个挑战是操作模型所需的编程语言不同于开发它们所使用的语言。将 Python 或 R 模型移植到 C++、C#或 Java 等生产语言中是一项挑战,通常会降低原始模型的性能(速度&准确性)。有几种方法可以解决这个问题。排名不分先后:

用新语言重写代码[即从 Python 翻译成 CSharp]
创建自定义 DSL(领域特定语言)来描述模型
微服务(通过 RESTful API 访问)
API 优先方法
容器化
序列化模型并加载到内存中的键值存储中

更具体地说:

脱机的

在离线模式下,预测模型可以部署到容器中,并作为微服务运行,以按需或定期创建预测。
另一种选择是围绕它创建一个包装器,这样您就可以控制可用的功能。一旦发出了一个批量预测请求,您可以将它作为一个单独的进程动态加载到内存中,调用预测函数,从内存中卸载它并释放资源(本机句柄)。
最后,另一种方法是将库打包成一个 API ,让调用者直接调用它,或者将它打包到他们的服务中,以完全接管预测工具的控制权。

就可伸缩性而言,可以创建多个并行管道来容纳负载。这涉及到微不足道的工作,因为 ML 模型是无状态的。

在线的

这里,预测模型可以在容器中部署到服务集群,通常分布在队列后面的许多服务器中,用于负载平衡,以确保可伸缩性、低延迟和高吞吐量。客户端可以通过网络远程过程调用 (RPC)发送预测请求。
或者,键值存储(例如 Redis)支持模型及其参数的存储,这大大提高了性能。

✳️关于实际的模型部署活动,它可以通过连续交付实现来自动化:所需的文件被打包,模型被可靠的测试套件验证,最后被部署到运行的容器中。测试由自动化构建管道执行:首先评估简短的、自包含的、无状态的单元测试。如果它们通过,预测模型的质量将在更大的集成或回归测试中进行测量。当两个级别的测试都通过后,应用程序就被部署到服务环境中。

启用一键部署比较理想。

— ⑦:模型评分

将 ML 模型应用于新数据集的过程,目的是揭示有助于解决业务问题的实际见解。又名模特服务。

✏️ 模型评分模型服务是业内可以互换使用的两个术语。在阅读了这个资源之后,我想到了评分的真正含义,所以在继续之前,让我们快速地了解一下基础知识,以防你也不清楚:

模型评分是在给定模型和一些新输入的情况下生成新值的过程。使用通用术语分数,而不是预测,因为它可能导致不同类型的值:

推荐项目列表
时间序列模型和回归模型的数值
概率值,表示新输入属于某个现有类别的可能性
新项目最相似的类别或聚类的名称
分类模型的预测类别或结果。

继续……一旦部署了模型,就可以根据之前的管道或直接从客户端服务加载的特征数据进行评分。当提供预测时,模型在离线和在线模式下应该表现相同。

脱机的

在离线层,评分服务针对大数据集合的高吞吐量、一次性预测进行了优化。应用程序可以发送异步请求来启动评分过程,但需要等到批量评分过程完成后才能访问预测结果。该服务准备数据、生成要素,但也从要素数据存储中提取额外的要素。评分发生后,结果将保存在评分数据存储器中。向代理发送消息以通知评分已经完成。应用程序正在监听这个事件,并在收到通知时获取分数。

在线的

客户向在线评分服务发送请求。它可以有选择地指定要调用的模型的版本,因此模型路由器检查请求并将其发送给相应的模型。与离线层类似,服务会根据请求准备数据、生成要素,并根据需要从要素数据存储中提取额外的要素。一旦评分发生,结果被保存在评分数据存储器中,然后通过网络发送回客户端。

根据不同的用例,分数也可以异步交付给客户端,即独立于请求:
Push:一旦分数生成,它们就作为通知被推送给调用者。
Poll:评分一旦生成,就存储在低读取延迟的数据库中;呼叫者周期性地轮询数据库以获得可用的预测。

为了最大限度地减少系统在收到请求时提供评分的时间,采用了两种方法:
输入特征存储在低读取延迟的内存数据存储中,
缓存在离线批量评分作业中预先计算的预测,以便于访问【这取决于使用案例,因为离线预测可能不相关】。

— ⑧:性能监控

该模型被持续监控,以观察其在现实世界中的表现,并相应地进行校准。

任何 ML 解决方案都需要定义良好的性能监控解决方案。我们可能希望看到的模型服务应用程序的信息示例包括:
·模型标识符、
·部署日期/时间、
·模型服务的次数、
·平均/最小/最大模型服务次数、
·所用特征的分布。
预测结果与实际/观察结果的对比。

元数据在模型评分期间计算,然后用于监控。

这是另一个离线管道。性能监控服务在提供新的预测时得到通知,执行性能评估,保存结果并发出相关通知。评估本身是通过将分数与数据管道(训练集)生成的观察结果进行比较来进行的。监控的基本实现可以遵循不同的方法,最流行的是日志分析 (Kibana、Grafana、Splunk 等)。

为了确保 ML 系统的内置弹性,新型号的速度表现不佳会触发先前型号生成的分数。采用了一种“错总比晚好”的哲学:如果模型中的一项计算时间太长,那么该模型将被一个先前部署的模型所替代,而不是阻塞。

此外,当分数变得可用时,它们会加入到观察到的结果中——这意味着会生成模型的连续准确性测量,并且与速度性能一样,任何下降的迹象都可以通过恢复到以前的模型来处理。

责任链模式可以用来将不同的版本链接在一起。

模型监控是一个连续的过程:预测中的变化可能会导致模型设计的重构。不断提供准确的预测/建议以推动业务向前发展,这就是 ML 的优势所在!

交叉问题

我们不能在结束这篇文章时不提及跨领域的关注。像任何其他应用程序一样,ML 应用程序有一些跨层/管道的通用功能。甚至在一个单独的层中,这样的功能可以跨所有的类/服务使用,穿过跨越所有正常的边界。

横切关注点通常集中在一个地方,这增加了应用程序的模块性。它们通常由组织中的其他团队管理,或者是现成的第三方产品。依赖注入是在代码的相关地方注入这些的最好方式。

在我们的用例中,要解决的最重要的问题是:

通知
调度
日志框架(和警报机制)
异常管理
配置服务
数据服务(公开数据存储中的查询)
审计
数据沿袭
缓存
检测

把所有这些放在一起

这就是了…一个生产就绪的 ML 系统:

End to End ML Architecture

脚注

恭喜你!你坚持到了最后!我真的希望你喜欢数据科学的软件工程之旅!

感谢阅读!

🙏🏻 💎整理这篇文章花费的时间超过了我最初的预期;不得不应付各种事情——家庭/工作需求等。向我忍受了这么多深夜的丈夫大声欢呼吧!你是一块宝石!

我定期在媒体上写关于技术的&数据——如果你想阅读我未来的帖子,请‘关注’我

面向设施的架构设计

原文:https://towardsdatascience.com/architecting-for-the-ilities-6fae9d00bf6b?source=collection_archive---------6-----------------------

6 个基本的软件质量

解决方案架构师在软件项目中起着举足轻重的作用,因为他们设定愿景并指导开发团队开发出最佳的解决方案。从许多不同的角度查看架构的能力是项目成功的基础。前面我们讨论了帮助架构师评估他们在整个项目生命周期中所做决策的五个关键原则。

今天我们将看到另一个同样重要的方面:T2 架构关注点 T3,或者 T5 质量属性 T6,T7,T8 系统能力 T9,或者 T11 非功能需求 T12,T13,并对其中最重要的做一个简短的概述。这些定性需求有时被命名为-能力 ,以单词 share(可用性、可维护性、可伸缩性等)的后缀 𝕞𝕠𝕤𝕥 命名。

功能和质量属性是正交的

𝕎𝕙𝕪 𝕤𝕙𝕠𝕦𝕝𝕕 𝕨𝕖 𝕔𝕒𝕣𝕖…

我最不喜欢的术语是“非功能性需求”(NFRs)——这完全是一个误称:谁会基于非功能性的需求来构建系统??这些要求指的是一个系统应该具备的品质和它必须运行的约束!因此,我更喜欢质量属性(QA)这个术语。

it 项目通常资金不足,而在开发阶段最重要的是功能!质量属性很容易成为降低优先级的目标,但是忽略它们的后果会直接导致质量问题和技术债务的增加。

然而,这种选择是短视的:质量保证会对设计产生更大的影响,如果我们弄错了,它们会对交付产生连锁反应,因为它们会导致昂贵的返工。根据我的经验,系统被重新设计并不是因为它们在功能上有缺陷(通常计算和功能通常是相同的),而是因为它们无法扩展、难以维护、太慢……这样的例子不胜枚举!

Functional Requirements are just the tip of the iceberg

𝕌𝕟𝕒𝕞𝕓𝕚𝕘𝕦𝕠𝕦𝕤 𝕤𝕡𝕖𝕔𝕚𝕗𝕚𝕔𝕒𝕥𝕚𝕠𝕟

到目前为止,我们已经宽泛地定义了术语“质量属性”。这里有一个更具体的定义:

质量属性是一个系统的可测量的可测试的属性,它表明系统满足其涉众需求的程度。

我在强调 QA 是可测量的可测试的 : 的重要性,为了指定一个有形的、明确的 QA,我们应该涵盖这六个重要部分:

刺激:到达系统时要考虑的条件。
来源:产生刺激的实体。
环境:刺激发生的环境,如正常运行、压力条件、故障等。
神器:被刺激的系统部分。
响应:刺激到达后发生的系统活动。
测量:响应满足要求的程度。

例如:“正常运行时收到不可预见的外部消息。该消息被记录下来,系统继续运行,没有停机时间。

✏️如果你想了解更多,这所加拿大大学有一个关于如何记录质保的浓缩章节。

𝕀𝕥’𝕤 𝕒 𝕓𝕒𝕝𝕒𝕟𝕔𝕚𝕟𝕘 𝕒𝕔𝕥…

维基百科记录了过多的问答,学术界多年来定义了多种分类法:

Courtesy: Kennet Henningsson

同样,至少有几个 ISO 标准(据我所知)试图将质量保证体系分为不同的类别: ISO 25010 和 ISO 9126 。

所有的质量保证都是至关重要的,但是正如一句老话所说:我们不能鱼和熊掌兼得!

一方面,成本会过高,上市时间会达到顶点,另一方面(也是最重要的一点)一些 QA 往往会对其他 QA 产生负面影响。例如,为了最大化可维护性,我们可能不得不牺牲效率;或者增加的可靠性可能对性能有负面影响;或者当软件在多个平台上运行时,可用性通常会受到影响(可移植性)。

Quality Attributes Trade Offs — Courtesy: Implementing System Quality Attributes

这就是建筑发挥作用的地方!

我们做出的所有架构决策都会对最终系统的 QAs 产生直接影响。因此,根据我们所处的业务领域的需求,以及不同系统利益相关者的观点,确定优先级的方法非常重要。

虽然有几种方法可以对系统质量进行排名,但在本文中,我将涵盖在构建应用程序时,我在实用性 方面排名最高的那些,尤其是在金融领域。

𝟙 𐩑表演

性能是指系统在给定的约束条件下,如速度、精度、内存使用等,满足时序要求的能力。
它的得分是以:

  • **吞吐量:给定时间范围内执行的事件数量
  • **延迟:响应特定事件所花费的时间
  • **容量:在继续满足吞吐量和延迟需求的同时处理的事件数量

为了提高系统的性能,可以采用几种策略,例如:

◽缓存
◽增加硬件资源:内存、CPU、网络
◽负载平衡
◽引入并发性
◽数据分区/复制

性能是系统架构中的一个驱动因素,通常会影响其他 QAs 的实现。它通常与可伸缩性相关,即增加系统的工作能力,同时仍然表现良好。让我们继续看看这意味着什么:

𝟚 𐩑可扩展性

可伸缩性允许系统优雅地响应对其提出的要求,并处理增加的工作负载,而不影响性能或其扩展架构以容纳更多用户、进程、数据等的能力。
挑战在于评估将对系统提出的需求的性质以及将受到压力的组件。在前期设计时,我们经常把重点放在错误的地方,我们试图在不测试预期系统行为的情况下进行优化。

有两种可伸缩性:

  • **垂直可扩展性(纵向扩展)指的是购买更大的硬件,例如向现有服务器添加更多内存/CPU/硬盘。
  • **水平可扩展性(向外扩展)是指添加多组硬件资源来划分负载并响应相同的请求,例如,向服务器集群添加另一台服务器。总的来说,它更具成本效益,因为它使我们能够从小处着手,然后随着时间的推移对系统的请求做出反应。

Courtesy: The Art of Scalability

规划扩展时,需要考虑以下几点:

◽用户数
◽数据量
◽ CPU、内存、I/O 密集型操作
◽并发
◽异步而非同步
◽无状态
◽长时间运行操作(非高峰时间批量调度)

在设计可扩展性时,最容易忽略的是以下需求:

  • **监控机制:必须观察系统的健康状况!当资源利用率超过 80%时,应向运营和开发团队发出警告,以便采取补救措施。
  • **压力测试:当务之急是让系统达到极限,以找出哪些操作是密集的,断点在哪里,并确定系统在负载下将如何失败(我们正在寻找的是“优雅的故障转移”)。

𝟛 𐩑可用性

可用性表示系统的可访问可用的能力,尤其是在发生故障之后。反过来,这也意味着企业愿意接受多少停机时间。企业通常要求 24x7 全天候正常运行,但相关成本可能相当高。

以下是一些需要牢记的注意事项:

  • 当服务不可用时,恢复过程是什么:是自动的还是手动的;停机时间有多长;能否满足 SLA(服务水平协议)?
  • 执行 RCA(根本原因分析)后,有什么缓解计划来避免将来出现故障?
  • 发生故障时需要哪种通知?
  • 系统的恢复能力是什么,即系统多久出现一次故障?

必须检测到故障,根据应用程序的关键程度和故障类型,系统必须以可接受的方式做出响应。在故障转移的情况下,采用恢复技术。理想情况下,必须完全防止故障。

Courtesy: Ericsson

让我们来看一些增强系统可用性的方法:

检测:

用于事件排序的◽时间戳
用于定期系统监控的◽心跳
用于数据验证的◽校验和
◽异常记录
等待时间超过预定义限制时的◽超时
◽自测正确性
◽ 机器学习检测

恢复:

编程环境中的◽异常处理
◽回滚,即恢复到之前的良好状态
◽在出现暂时错误(如网络故障)的情况下重试
◽使用替代操作重试(如 t 的市场价格不可用,则尝试获取 T-1)
◽服务重启

预防:

◽异常预防
◽事务
◽优雅地关闭并重新实例化
◽增加了测试覆盖率

𝟜 𐩑延展性

可扩展性是指系统通过灵活的架构、设计或实现来迎合未来变化的难易程度。扩展可以通过添加新功能或修改现有功能来实现。快速上市对任何组织来说都是至关重要的,因为它会影响组织扩大与相关系统相关的收入的能力。

需要注意的一些关键因素是:

  • 高内聚低耦合
  • 应用可靠的原则(尤其是开闭原则和依赖倒置原则)和设计模式,这些原则和模式允许在不影响架构的情况下改变系统行为
    [ 本文 解释了可靠的原则如何也适用于架构——不仅仅是编程】
  • 关注点的分离,例如将应用程序逻辑分离到不同的层(客户端、表示层、业务逻辑层)
  • 使用抽象来设计那些易受变化影响的系统边界
  • 模块化改进用户界面,以便不同的模块可以在影响最小的情况下可用
  • 可插拔架构
  • 利用带有动态规则的工作流引擎
  • 通过 API 公开层、子系统和模块的功能
  • 一键式部署,实现快速上市
  • 高测试覆盖率证明没有副作用

可扩展性的线索是在最初的设计阶段主动倾听业务,寻找他们可能想要改变系统行为的地方。

✏️请不要将可扩展性可修改性混为一谈:可修改性意味着有可能改变软件,而可扩展性意味着改变已经被计划好了,并且将(几乎)毫不费力!

𝟝 𐩑支持度

可支持性是系统为识别和解决问题提供有用信息的能力。这里的主要要求定义如下:

  • 记录持久环境中的所有故障(数据必须与用户和支持工程师相关)
  • 启用时间线分析和错误跟踪的日志记录
  • 能够在出现故障时对系统状态进行快照,以便在开发环境中重现该状况
  • 符合标准、最佳实践、参考体系结构等
  • 最新文档(包括架构图、接口、编码指南等)
  • 技术债务管理
  • 系统健康检查监控公司测试应用程序是否正确运行

请不要低估这种质量保证的价值:组织 IT 预算的很大一部分花费在关键软件的维护上,因此应用程序越容易维护,其 TCO ( 总拥有成本)就越低。

𝟞 𐩑可用性

可用性解决了建立软件提供增强用户体验的能力的因素。用户界面的设计必须考虑到预期的最终用户,这样它们才是直观的、一致的、易于学习和操作的。

用于实现质量指标的一些策略是:

  • 异步 API 用于长时间运行的进程或后台任务,因此 UI 控件不会冻结
  • 利用相关的 UI 设计模式,使用适当的组件/部件
  • 可逆操作(取消/撤消)
  • 自动完成
  • 个性化和用户偏好持久性
  • 认可而不是回忆
  • 通知和反馈机制(特别是关于故障)
  • 消除过多的点击
  • 用户界面的美学和视觉外观
  • 支持不同的交付媒介:手机、电脑、平板电脑
  • 帮助和文档

架构对可用性的支持是用户满意度的关键,通常用效率(任务对速度)和产品的有效性来衡量。架构师通常会忽略这一点,他们主要关注服务器端架构,而将用户界面留给分析师。

这是大错特错!表示层与应用程序在架构上的分离不足以解决所有的可用性问题,这些问题会深入到应用程序的表示层之外。

𝔼𝕡𝕚𝕝𝕠𝕘𝕦𝕖

选择正确的软件质量属性来关注,增加了应用程序持续更长时间的机会,并获得了提高组织投资回报的好处。

质量不是一种行为;这是一种习惯——亚里士多德

通常有利于一个质量属性的决策会对另一个产生影响,因此从一组相互竞争和不断变化的需求中找到最佳解决方案是一项挑战。

但这正是软件架构成为真正的工程科学的原因!

My top 6 Quality Attributes

如果您想进一步了解我们介绍的一些主题,这里有一些不错的资源:

参考资料:

  • 如果你要回顾 QAs 上的一个人工制品,它必须是这个:
    质量属性——软件工程研究所
  • 体系的质量属性调查
  • 软件质量属性之间的关系
  • 通过软件架构实现可用性

感谢阅读!

*我经常在媒体上写关于技术的&数据——如果你想阅读我未来的帖子,请*‘关注’我

建筑和风格

原文:https://towardsdatascience.com/architecture-style-ded3a2c3998f?source=collection_archive---------6-----------------------

人工智能在建筑领域的新前沿

斯塔尼斯拉斯·夏洛 ,哈佛大学设计研究生院| 2019 年 6 月 2 日

GAN-Generated Apartment Units, with Specific Styles | Source: Author

本文放出 我们的论文 的一部分,在哈佛开发,2019 年 5 月提交。这件作品是一个更大的作品的一个组成部分,调查艾在建筑上的开端,它的 历史背景 ,它的潜在空间 组织&风格

我们 上一篇 的基础上构建,我们的重点是围绕平面图的严格组织及其生成,使用人工智能,更具体地说是生成性对抗神经网络(GANs)。当我们改进生成平面布置图的能力时,我们提出了模型固有偏差的问题,并在此提出将我们的研究扩展到简单的组织命令之外。我们研究建筑风格学习,通过训练和调整一系列特定风格的模型:巴洛克风格、联排别墅、维多利亚郊区别墅、&曼哈顿单元。除了每种风格的简单噱头,我们的研究揭示了风格的深层含义:不仅仅是它的文化意义,风格携带了一套基本的功能规则,定义了一个明确的空间机制,并控制着计划的内部组织。在这篇新文章中,我们将尝试证明建筑风格对平面布局构成的深远影响。

提醒:人工智能和生成对抗性神经网络

在研究人工智能及其对建筑实践的潜在整合的同时,我们建立了一个完整的生成方法,使用了生成对抗神经网络****【GANs】。当应用于二维信息生成时,人工智能的这个子领域已经被证明产生了巨大的结果。与任何机器学习模型一样,GANs 从提供给它们的数据中学习具有统计意义的现象。然而,它们的结构代表了一个突破:由两个关键模型组成,即生成器鉴别器,GANs 利用两个模型之间的反馈回路来完善它们生成相关图像的能力。鉴别器被训练来从一组数据中识别图像。经过适当的训练,该模型能够区分从数据集中取出的真实示例、来自数据集外来的“图像。然而,生成器被训练来创建类似于来自相同数据集的图像的图像。当生成器创建图像时,鉴别器向其提供一些关于其输出质量的反馈。作为响应,发生器会进行调整以产生更真实的图像。通过这个反馈回路,GAN 逐步建立其创建相关合成图像的能力,将观察到的数据中发现的现象考虑在内。

Generative Adversarial Neural Network’s Architecture | Image Source

我们特别将这种技术应用于平面图设计,使用平面图的图像表示作为 GAN 模型输入和输出的数据格式。我们工作中使用的框架是 Pix2Pix ,这是一个标准的 GAN 模型,面向图像到图像的翻译。

一.组织

元素的空间布局是建筑学科的一个重要关注点。正如前一篇文章 中的 所证明的那样,这个练习并不是无足轻重的,可以按一系列步骤来离散化。每一步实际上都被一个训练有素的 GAN 模型所捕捉。对每个模型所学到的组织的仔细研究揭示了一个更深层次的偏见的存在,我们的学科称之为架构风格。打开我们的“世代堆栈”将帮助我们找到不同层次的风格,并分离出风格影响的基础。

管道和发电

首先,我们提出一条流水线,通过一个接一个地嵌套连续的模型,我们帮助建筑师生成一个连贯的房间布局(模型 I)和家具(模型 II),最终将所有公寓单元重新组合成一个暂定平面图。

Generation Pipeline, Model I & Model II | Source: Author

对于整个流程中的每一步,我们都为用户提供了一个简单的界面。在左侧,他/她可以输入一组约束和边界,以在右侧生成结果计划。然后,设计师可以反复修改左边的输入,以优化右边的结果。下面的动画展示了为型号 I. 设置的这种界面和流程

下面的界面也可以在下面的 地址试用。 (性能取决于屏幕分辨率/浏览器版本— Chrome 建议)

Model I Interface | Source: Author | link

偏见,或风格的出现

T 考虑到一批生成的单元,我们开始注意到我们的模型的一些内在偏差:内墙结构始终如一地布置成一个正交的隔断系统,忽略了单元立面的潜在方向(见下图)。与此同时,项目的布局也始终如一,以至于“服务于”的空间- 浴室、厕所、壁橱、厨房 -被打包在地块的后面,而立面的奇怪几何形状被过大尺寸的客厅和卧室所吸收。

Plan Wireframe (left) & Program Repartition (right) of Generated Apartment Units | Source: Author

事实上,这些特征在我们最初的训练中随处可见。我们在这里将这种现实理解为对建筑学科核心概念的字面翻译:风格

二。风格

我不去阻止这种偏见,而是努力创造一个通用目标计划生成器——这不是我们在这里关心的——我们宁愿拥抱它,研究它的存在,最终利用它为我们所用。

为此,我们选择拓宽我们的研究,将其扩展到建筑风格学习。我们创造了一个新的渠道,使平面图能够从一种风格转换到另一种风格,从现代风格转换到巴洛克风格。

Modern-to-Baroque Translation & Subtraction | Source: Author

上面的例子更加揭示了建筑风格的深层含义:在这张 GIF 图中,我们从翻译的平面图(巴洛克)中减去了最初的墙壁结构(现代)。剩下的“ poché ”是巴洛克风格引发的添加:它不仅仅是对现有人物墙的全新改造,而是对内部结构和空间组织的深刻重塑。

事实上,我们在这里证明了 Farshid Moussavi 在她的书中所创造的风格的 功能。每一种风格,除了其文化意义之外,对空间的处理方式也各不相同,对相似的限制也有不同的反应。

为了研究建筑风格的学习,我们已经训练和调整了一系列特定风格的模型——巴洛克、联排别墅、维多利亚郊区住宅、&曼哈顿单元——能够模拟每一种特定的建筑风格。

对于每种风格,我们在下面显示了初始训练集(左)、一些结果生成的公寓单元(中),以及相同公寓单元的物理模型(右)。

Baroque Apartment Units | Source: Author

Manhattan Apartment Units | Source: Author

Row-House Apartment Units | Source: Author

Victorian Apartment Units | Source: Author

在生成的单元中,我们可以在每种风格中识别出一些清晰的模式。对我们来说,这种适用于每种模式的“行为”是每种风格机制的直接翻译。不仅仅是在每个公寓单元上应用简单的纹理,每个模型都捕捉到了一系列的特征和规则。

Characteristics Graph Template | Source: Author

为了超越这种简单的观察,我们提供了每种风格的能力。每个型号都对应一系列优点&缺点,将它们记录下来将使我们能够真正评估每种风格的实际功能。此外,我们希望扩展我们对模型能力的理解,允许我们以后在给定一组新的约束和功能需求的情况下,有目的地使用每一个模型。

在 clear 中,我们提出了一个六轴图,反映了给定模型处理六种特定类型条件的能力:深度紧凑度单方向多方向(正面数量)、锐角(边界的尖锐几何形状)、程序谱(程序的宽度)。

在彻底测试了我们的四个模型之后,我们提出了以下图表…

Styles’ Characteristics Graphs | Source: Author

更具体地说,为了明确上述图表,我们对每种风格的特征进行了深入的解释:

巴洛克风格

  • 可以处理深度和尖锐的几何边界。通过增加壁龛和壁龛,这种风格可以细分地块,并在地块的深度上雕刻出合适的空间。
  • 然而,这种风格需要空间来展开其逻辑和内部结构,因此不能很好地响应紧凑的足迹。

曼哈顿风格

  • 对单向或双向反应更好。
  • 显示了广泛的编程范围。
  • 在处理深度和尖锐的几何边界方面有问题。

排屋风格

  • 可以充分利用紧凑的空间,将功能分散在楼层之间,并将每个功能限制在狭小的隐蔽空间内。
  • 深度得到了很好的处理,并经常充满了垂直循环,周围的服务空间聚集。

维多利亚风格的郊区

  • 轻松处理多个方向。
  • 很好地处理了深度,通过居住在中心地带的服务空间。
  • 展示了大量的房间和丰富的规划
  • 但是,这种样式对紧凑轮廓线的反应很差,并且无法真正处理尖锐的几何边界。

Building Massing (North,East, South & West Elevations) | Source: Author

三。应用

最终,我们将所有这些直觉融合在一个最终的建筑项目中:一个位于曼哈顿下东区的大型住宅开发项目。地块的复杂几何形状给我们的设计增加了一定的复杂性。由于我们的聚集(上图),我们获得了 380 个独一无二的公寓单元的目录(下图,右)。

A.一栋建筑

Sequence Of All Floors (Left), Catalog of Floorplates (Center) and Units (Right) | Source: Author

我们首先尝试处理整个地板,每次使用不同的风格。下面显示的结果再一次揭示了谨慎使用风格的必要性,尊重每个环境的限制和特殊性。如果某些单位使用某种风格成功布局,其他单位则无法找到合适的内部组织。通过在我们的公寓单元目录中选择不同的风格,我们希望为每一个特定的空间条件找到合适的答案。

15th Floor Processed Under Each Style: Baroque (Far-Left), Manhattan (Center-Left), Row-House (Center-Right), Victorian (Far-Right) | Source: Author

了解每个 GAN 模型的优点和缺点,每个风格的潜力和缺点,我们现在使用最适合的模型处理每个公寓。每一层都变成了各种风格的拼布。然后,我们的目标变成为每块瓷砖、每个单元组成我们的“马赛克”挑选,这是最合理的模型,将最好地处理约束。在这个选择过程中,我们分离出一些结果选项,如下所示。

3 Options: 10th Floor to 20th Floor, Processed Differently | Source: Author

然后,我们缩小探索范围,精确选择所有地板的单元和风格,最终完成我们的最终设计。下面是三个典型的楼层…

14th, 15th & 4th Story Floorplans | Source: Author

事实上,我们已经把风格变成了功能性工具,能够解决我们开发过程中的特定情况。

然而,正如上述计划所建议的,我们抛开某些约束,并做出明确的假设。我们想澄清这些。

一.结构

这个结构留给了结构核心,而张力索沿着立面延伸。因此,该计划不受垂直负载的干扰,并允许我们的算法自由生成每个单元的分区系统。

:回顾我们这一代管道,一个潜在的改进是将承重墙&柱的位置作为模型一的输入,这样我们的管道就可以让设计师控制建筑结构体系。或者,模型 I 可以分解成两个连续的模型,一个用于布置承重构件,另一个用于添加隔墙。

二。效率的严格要求

每种风格的丰富多彩和赋予我们模特的自由程度都没有解决我们行业中普遍存在的问题 : 空间效率。然而,我们在这里主要关心的是最大化每种风格的表现力,让每个模型展开它的机制来展示它的“个性”。

:为了调和 GANs 与效率,我们假设它们的输出构成了标准优化工艺的巨大初始化。参数化方法的典型缺陷是建立了一个过于宽泛的问题空间,再加上随机的初始化。在这些设置上运行的优化通常会收敛于局部最小解。我们的 GANs 背后的直觉带来了全新的初始化质量,在建立足够好的初始解决方案的同时,显著缩小了问题空间。

三。聚集

体量的概念指的是我们建筑的外形。上述设计的非理性形式在这里意味着复杂性的触发,为我们的模型创造了实际的挑战。更理性的体量会对应更驯服的&现实的公寓单元设计。我们在这里的重点仍然是展示一个极端的情况,并测试我们的模型的极限。

B.目录

Generated Apartment Units Catalog | Source: Author

我们 最后翻到上面的单位目录,找到了我们对面的大楼。由此产生的设计的连贯性和丰富性是惊人的。此外,在生成的单元中显示的"智能"或形式上的灵活性进一步证明了该方法的有效性: GAN 模型确实可以封装一些以后可以使用的体系结构专业知识&风格,这取决于起作用的约束集。第二部分中描述的每个模型的“个性”在每个子集中都清晰可辨。

为了结束这一部分,我们在下面提供了一系列的关键镜头,取自我们的目录。根据平面图的严格描述性质(),我们每次都将室内氛围的图像()联系起来,以此来协调我们的过程与建筑的更多体验性质。

Baroque Apartment Units’ Interior | Source: Author

Manhattan Apartment Units’ Interior | Source: Author

Row-House Apartment Units’ Interior | Source: Author

Victorian Apartment Units’ Interior | Source: Author

四。结论

如果说在严格意义上平面图是工程的产品之前,我们可以先把平面图看作是构图,那么研究构图的驱动力也许是人工智能可以为我们提供一些有意义的答案的地方。根据这种直觉,我们在本文中证明了建筑风格在更深层次上承载了一种隐含的空间机制,这种机制会显著影响任何平面布局的构成。很明显,选择一种特定的风格会产生空间上的后果。

在更基本的层面上,我们可以认为风格是建筑历史的副产品。如果在每一种风格中都有一套更深层次的功能规则,那么研究建筑历史就有可能理解这些隐含规则随时间的演变。能够封装每种风格可以让我们超越对先例的研究,并通过解开 GAN 模型(如这里训练的那些)的行为来补充它。他们模仿一些建筑潜规则的能力可以让我们解决嵌入建筑中的"无名质量",这是克里斯托弗·亚历山大在他的书《永恒的建筑之道》中定义的。人工智能只是研究它的一种新方法。

最后,风格在每个 GAN 模型中的内在存在构成了最后一点:远离不可知论者的承诺&生成设计的客观实践,似乎风格不可逆转地渗透到任何生成过程的本质。明确地说:风格不是附属的、表面的或装饰性的附录。风格是构图的核心。认识到这个证据是理解 AI 能给建筑带来什么的先决条件。换句话说,将不存在不可知论的人工智能架构,没有没有风格的机器,没有客观的生成式设计。相反,每一个模型或算法都有自己的特色、个性和诀窍。

链接到 Academia.edu 的论文脚本

文献学

  • 文体的功能,法希德·穆萨维,Actar 出版社,2016 年
  • 一种模式语言,关于合成形式的注释,克里斯托弗·亚历山大,链接
  • 超越计算机的数字建筑
  • 数据驱动设计&构建,兰迪·多伊奇,威利
  • 建筑智能,设计师和建筑师如何创造数字景观,莫莉·赖特·斯汀森,麻省理工学院出版社
  • 建筑谷歌超越网格——建筑&信息技术第 226–229 页,Ludger Hovestadt,Birkhauser
  • 算法复杂性:凭空而来复杂性,设计策略&世界观第 75–86 页,Andrea Gleiniger&Georg Vrachliotis,Birkhauser
  • 代码&机器代码,操作间&叙述第 41–53 页,Andrea Gleiniger&Georg Vrachliotis,Birkhauser
  • 格罗皮乌斯的问题还是关于在建筑和艺术中揭示和隐藏代码代码,介于操作&叙述第 75–89 页,安德烈·格莱尼格&格奥尔格·弗拉赫利奥蒂斯,伯克豪斯
  • 软架构机器,尼古拉斯·尼葛洛庞帝,麻省理工学院出版社
  • 建筑机器,尼古拉斯·尼葛洛庞帝,麻省理工学院出版社
  • 地图的变质作用;或者输入 RoweBot ,Andrew Witt,Log #36
  • 灰拳击,安德鲁·威特,日志#43
  • 人类与人工智能中的暗示性绘画,辜莞允·马丁内兹,哈佛 GSD 论文,2016
  • 启用替代架构:参与式设计的协作框架, Nathan Peters,哈佛 GSD 论文,2017 | 链接
  • 通过机器学习的建筑图纸识别与生成,郑浩(宾夕法尼亚大学),黄卫新(清华大学),ACADIA 2018 [ 论文 ]
  • 丹尼尔:自动分析和检索建筑平面图的深度架构,迪维娅·夏尔马,尼廷·古普塔,奇兰霍伊·查托帕迪亚,萨梅普·梅塔,2017,IBM 研究,IIT·焦特布尔
  • 建筑平面图中的自动房间检测和房间标记,Sheraz Ahmed、Marcus Liwicki、Markus Weber、Andreas Dengel,2012 年,凯泽斯劳滕大学
  • 使用空间索引的平面图自动解释,哈南·萨梅特,Aya Soffer,1994,马里兰大学
  • 解析平面图图像,塞缪尔·道奇,久旭,比约恩·斯坦格,2016,亚利桑那州立大学,乐天理工学院
  • 项目探索:生成性设计在建筑空间规划中的应用,丹尼尔·纳吉,达蒙·刘,约翰·洛克,吉姆·斯托达特,洛伦佐·维拉吉,王雷,戴尔·赵和大卫·本杰明,2016,生活,欧特克工作室
  • 光栅转矢量:重访平面图转换,刘晨,吴家军,普什梅特·柯利,川口恭誉·古川,2017,华盛顿大学,深度思维,麻省理工学院
  • 图形文档视觉理解的关系模型。建筑制图应用,2014 年,巴塞罗那自治大学
  • 基于骨骼上下文的形状匹配与建模,谢军,heng-Ann Heng,Mubarak Shah,2007,中佛罗里达大学,香港中文大学
  • 平面图解释的统计分割和结构识别,Lluís-Pere de las Heras,Sheraz Ahmed,Marcus Liwicki,Ernest Valveny,Gemma Sánchez,2013,西班牙巴塞罗那计算机视觉中心
  • 结合使用统计和结构策略在平面图中进行无监督和独立于符号的墙壁分割,llus-Pere de las Heras、Ernest Valveny 和 Gemma Sanchez,2014 年,西班牙巴塞罗那计算机视觉中心
  • 使用生成式对抗网络支持智能移动应用的路径规划,Mohammadi,Mehdi,Ala Al-Fuqaha 和 Jun-Seok Oh。, 2018
  • 基于方形树形图算法的平面图自动实时生成,Fernando Marson 和 Soraia Raupp Musse,2010 年,PUCRS
  • 建筑程序建模,帕斯卡·穆勒,彼得·旺卡,西蒙·海格勒,安德烈亚斯·乌尔默,吕克·范·古尔,2015,苏黎世联邦理工学院,亚利桑那州立大学
  • 建筑空间规划的生成式设计,Lorenzo Villaggi 和 Danil Nagy,2017,Autodesk Research

档案馆

原文:https://towardsdatascience.com/archive-83fda4d0f6df?source=collection_archive---------20-----------------------

轻松访问我们多年来发表的数千篇精彩文章。

欢迎来到走向数据科学存档!

多年来,我们已经出版了数以千计才华横溢、令人惊叹的作家的作品。我们已经涵盖了开创性的概念,新技术,前沿研究,等等。

不幸的是,我们不能永远把一切都放在头版。

在我们的档案中,你可以找到我们已经发表并与你分享的所有精彩文章。如果你正在寻找关于数据科学、机器学习、编程、人工智能、数学概念、伦理和未来的信息,或者如果你正在寻找在这些领域工作的洞察力,开始探索吧!

我们的档案可以很容易地按年份和受欢迎程度排序,但你可能想通过查看特定的标签甚至作者来缩小搜索范围。如果你想找一篇特定的文章,你总是可以在搜索来找到它!

舒服了就开始看书吧!如果您有任何问题或建议,请随时联系我们,让我们知道如何才能使我们的档案变得更好。

谢谢!

具有数据增强的北极猴子歌词生成器

原文:https://towardsdatascience.com/arctic-monkeys-lyrics-generator-with-data-augmentation-b9b1f7989db0?source=collection_archive---------8-----------------------

AM:不要相信炒作。艾:嗯..

简介。

外部发生器很酷,对吗?大约两年前,当我第一次看到类似于“莎士比亚发电机”的东西时,我惊叹不已。

通常,文本生成器将是具有递归神经网络或 LSTM 的语言模型,并尝试基于先前的种子词来预测接下来的词。

所以我决定基于北极猴子的歌词创建一个歌词生成器。这个想法分为三个主要部分

  • 创建数据语料库并清洗数据
  • 文本数据扩充
  • 语言模型和生成器

创建数据语料库

我发现乔纳森·戴顿的博客真的很有帮助。它使用 spotifyAPI 获取 spotify 上的艺术家 ID,列出所有专辑 ID,获取所有曲目 ID 的列表。然后使用 GeniusAPI 保存歌曲的所有歌词。这里有一些获取数据的代码片段。

依赖关系:

  • 歌词天才

文本扩充

该数据集包括 144 首歌曲,即 167887 个单词。我真的很想对亚历克斯写的歌曲数量发表评论,这些歌曲甚至不包括上一张皮影戏和他的个人专辑中的歌曲——我开始分心了!

如果数据集没有语言建模任务预期的那么大,可以应用文本扩充。

这里使用的两种类型的文本增强是

  • 替换-用语言模型通常预测的单词替换当前单词。
  • 插入—使用单词作为预测下一个单词的特征。

我为此使用了 nlpaug ,在这篇文章中可以找到一个非常好的概述——马志威
的文本数据扩充库。为了生成歌词的合成数据,我认为使用单词级模型更有益,并且像“naf.sequential”这样的流增强器用于顺序应用不同的增强。

我使用了两种类型的增强——Bert aug 和 FasttextAug。它们都基于上下文插入/替换相似的单词。BertAug 使用 BERT 语言模型来预测被替换的单词或者在插入的情况下预测下一个单词。FasstextAug 基于上下文化的单词嵌入替换或插入单词。

【BERTAug 插入和替换后的结果

进:总有更高更机智的人
出:总有更高更机智的人

weeeirrrdddd..但听起来差不多是对的。

【FasttextAug 插入和替换后的结果

总有更高的人更有智慧

还有一件有趣的事情发生了,由于子词嵌入,FasttestAug 的未知词没有 ValueError 异常——我使用 wiki-news-300d-1M-subword.vec 来加载模型——

除了——嗯——“I . d . s . t . I . d . s . t . I . d . s . t . I . d . s . t”,“啾啾!啾啾!啾啾!”和“咻-咻-咻-咻-咻”。我老实说不怪。

扩充后,语料库中有 334524 个单词。这意味着新数据是原始数据的两倍。

创建扩充数据集确实花了不少时间。(大约一小时左右)我确实有。最终文集的 txt 文件上传到 google drive 。

LSTM 模型

一个理想的文本生成模型将接受一个种子单词/句子,并给出单词的历史记录 w0,…,wk ,它将预测下一个 wn+p 单词。因为递归神经网络和 LSTMs 具有记忆,所以它们基于先前的状态计算下一个观察值。

LSTMs 是特殊的,因为它们有输入、输出和遗忘门以及单元存储器。因此,它们能够在更长的时间间隔内存储信息。这里我用了一个 0.5 辍学和 0.5 经常辍学的 LSTM。

目前,有一些非递归模型在使用转换器的语言建模中表现非常好,比如 OpenAIs GPT-2 文本生成模型。

结果:

结果:

使用 OpenAI 的 GPT-2 进行微调

我使用了GPT _ 2 _ simple——“一个简单的 Python 包,它包装了用于 OpenAI 的 GPT-2 文本生成模式 l 的现有模型微调和生成脚本”

将带有 BERTAug 和 FasttextAug 的原始数据集合并并导出为文本以形成 am_corpus.txt

带有随机前缀的结果:

Generated Lyrics

为了评估这个结果,我使用了胭脂。它代表面向回忆的替角,用于 Gisting 评估。我发现——[什么是 ROUGE,它是如何对摘要任务进行评估的?](http://What Is ROUGE And How It Works For Evaluation Of Summarization Tasks?) —对了解胭脂真的很有帮助。

本质上,GPT-2 模型生成的歌词比 LSTM 模型生成的歌词更有意义!虽然公平地说,LSTM 模型没有得到一个战斗的机会,只有 5 个纪元的训练。

  • 谷歌 Colab 笔记本为歌词生成器。

参考

  • 文本的数据扩充库马志威
  • 是什么让一些 blink-182 歌曲比其他歌曲更受欢迎?第 1 部分乔纳森·戴顿
  • OpenAI 的 GPT-2 文本生成模型。
  • 递归神经网络中基于理论的辍学应用

编辑:添加评估指标和更多结果。

AI 机器比人更值得信任吗?

原文:https://towardsdatascience.com/are-ai-machines-to-trust-more-than-people-d057292d7d02?source=collection_archive---------28-----------------------

人工智能概述—简介

人工智能是计算的子领域。人工智能研究的目标是开发程序(软件),这将使计算机能够以智能的方式运行。第一项研究与计算的根本有关。创造能够智能执行各种任务的机器的想法是计算机科学研究人员的主要关注点,他们在整个 20 世纪下半叶冒险研究人工智能。今天,人工智能的研究集中在专家系统、有限领域的翻译系统、人类语音和书面文本的识别、定理的自动证明器,以及对创造普遍智能的自主代理的持续兴趣。

Photo by Drew Graham on Unsplash

作为一个术语,人工智能在更广泛的意义上意味着人工创造实现人类思维特征功能的能力。自古以来,开发类似创造的可能性就唤醒了人们的兴趣。然而,直到 20 世纪下半叶,这样的可能性才被赋予第一个工具(计算机),为这种冒险开辟了道路。

随着现代科学的到来,人工智能研究正朝着两个基本方向发展:心理和生理对人类思维本质的研究,以及日益复杂的信息系统的技术开发。

从这个意义上来说,人工智能这个术语最初是指有能力实现复杂任务的系统和计算机程序,模拟人类思维的功能,尽管即使在今天,离目标还很远。在这个领域中,最重要的研究领域是信息处理、来自不同知识领域的模型识别、游戏和应用领域,例如医学。

当今信息处理研究的一些领域正集中于寻求训练计算机理解书面和口头信息、创建摘要、回答特定问题或向对该信息的某些部分感兴趣的用户重新分发数据的程序。在这些程序中,重要的是要有系统的能力来创建语法正确的句子,并在单词和想法之间建立联系,或识别意义。研究表明,虽然语言的结构逻辑或语法问题可以通过编写适当的算法来解决,但意义或语义的问题要深刻得多,需要真正的人工智能来解决。[ 1

当今人工智能系统发展的主要趋势是专家系统的发展和神经网络的发展。专家系统试图重现人类对这些符号的思考。神经网络更多地从生物学的角度来做这件事(它们使用遗传算法重建人脑的结构)。尽管这两个系统都很复杂,但结果远非真正的智能思维。

许多科学家对开发真正的人工智能的可能性持怀疑态度。人类思维的功能仍然不为人所知,无论出于什么原因,智能系统的信息设计在更长的时间内基本上无法呈现这些未知和复杂的过程。

人工智能的研究集中在以下智能组成部分:学习、思考、解决问题、感知和语言使用。

人工智能、社会和权力

已经有人指出,人工智能代表了人类历史上的一种新奇事物,从最广泛的意义上来说,它是科学、经济、健康、文化和社会的革命性推动者。然而,事实是,大多数当代社会是强烈两极分化的,一方面是巨富阶层,另一方面是没有足够影响力来改变任何重要事情的平民阶层。[ 2

人工智能的应用极大地增强了现有的权力结构,并更有助于其“锐化”,因为其用途越来越丰富,穷人仍留在原来的地方,甚至变得贫困,而不仅仅是在物质方面。在经济学、分析和决策领域,一言以蔽之,即获取和使用权力,人工智能需要拥有高超知识的专家、强大的设备和资金,事实证明,就其全部能力而言,这种工具非常昂贵,只有非常富有的个人和公司才能使用。正因为如此,中下层人工智能可以在更小的范围内用于商业发展。这些层主要通过大规模移动应用设备提供,这些设备大大简化了一系列工作,从所需产品或服务的快速跟踪开始,到做出购买决定的更短时间和到达这些产品的最短路线,无论是实际到达销售点还是通过互联网购买。因此,社会的这一部分完美地服务于它自己的消费者的角色,但是他能够利用人工智能作为大规模经营的动力要少得多,就像那些能够致富的公司和个人一样。剩下的海量 AI 服务都是好玩的,还有无尽的新闻和服务信息。

的确,普通世界现在对悲剧事件——恐怖袭击、交通事故、战争冲突——以及体育赛事、公众人物的可耻行为和政治事件的最微小细节了如指掌。这应该伴随着社交网络交流的强劲增长。

在下一节中,我想谈谈在我们当前的世界中人工智能的一些更大的实现。

IBM 沃森

每个人都在谈论机器。人工智能。艾。换掉那个人。这是一个在全球范围内广泛讨论的大话题。因为,从逻辑上讲,人们是害怕的。为了你的未来。一些最大的公司正在努力突破人工智能。许多大型 IT 公司多年来一直在积极(并越来越多地)投资人工智能。

IBM 似乎更进一步。IBM 开发了 IBM Watson 认知计算应用程序,该应用程序应用于各个领域,从最复杂的商业决策到大众的日常活动。这个系统存在并已经发展了相当一段时间,并在 2011 年赢得了美国流行的 Jeopardy 秀。

然后,的确,“历史被创造了。”因为一种是学习超级计算机下棋,另一种是完全不同的理解英语中充满同义词、俚语和逻辑的复杂、困难和复杂的句子,并以此为基础得出正确答案。

今天,沃森甚至更先进。到了沮丧的程度。因为它不再只针对拥有巨额货币基金的大型系统。不要!它的一些服务是完全免费的,可以在任何地方应用,甚至在最小的创业公司。它还用于烹饪,其中 Chef Watson 应用程序帮助厨师创建新的食谱。关键是,没有什么是被编程的。最棒的是——在“参与”了成千上万的食谱后,沃森主厨亲口说出,哪种食物、香料和其他东西最好搭配,并且彼此一致。他还在继续学习。所以一个厨师做出了最好的意大利调味饭。在他看来。

因此,这种令人毛骨悚然的人工智能系统(人工智能)可以应用于许多商业领域,从最小的领域,如烹饪行业,到许多高级领域,如时间分析和预测以及飞行控制。例如,这个程序可以应用于一个刚刚开始分析客户的小型创业公司。比方说,你有 2000 个客户。他会分析,而不是你,他们来到你的网站的方式,他们呆了多长时间,来自哪些国家(注册后),与这些国家的文化和习惯进行比较,谁知道还有什么,最后,你可以报告如何“接近”和如何向他销售。吓人。但令人印象深刻。此外,Watson 还可以用作聊天机器人。不要支付昂贵的支持,因为你刚刚开始创业,从沃森聊天机器人将适合你的客户,这是你以前分析过的。

当我看到这一切时,我知道未来对一些人来说是暗淡的,但对一些美好的人来说却是如此。人类文明一直如此。冰箱已经被卖冰的、汽车和汽车车马取代了,人工智能肯定会把一些蛋糕分给出租车司机和卡车司机等其他行业。或者会计师。

深蓝电脑赢得国际象棋世界冠军

八十年代和九十年代计算机的处理器能力和内存容量的快速增长,日益缩小了顶尖棋手和最佳系统之间的差距。最后,在 1997 年 5 月,IBM 开发的国际象棋计算机“深蓝”击败了当时的国际象棋世界冠军加里·卡斯帕罗夫。这场比赛共 6 局,胜率为深蓝 2: 1,3 平。

自动驾驶汽车

国际象棋是一种在虚拟世界中进行的游戏,有一套有限的规则,与此不同,处理现实世界中的问题要复杂得多:每条规则都有许多例外,而且在达到预期目标的过程中经常会出现不可预见的情况。其中一个区域是驾驶汽车。自 20 世纪 70 年代末以来,自动驾驶汽车领域一直在进行研究,这种汽车可以在没有人类干预的情况下安全地从 A 点到达 B 点。

在 20 世纪 80 年代末的第二次人工智能危机之后,美国政府和国防部改变了该研究的资助策略。在这一战略的框架内,DARPA 在填补基础研究和军事用途之间空白的领域组织竞赛。其中一个比赛是 DARPA 大挑战,为使用自动驾驶汽车的团队提供现金奖励。在 2004 年举行的第一次比赛中,没有一辆注册车辆未能穿越设想中的 240 公里长的路线,该路线穿过加利福尼亚州和内华达州的沙漠和山路。明年,也就是 2005 年,多达五辆车到达了终点线,该奖项被授予了最快的车,斯坦福大学的斯坦利。在 2006 年和 2007 年期间,成功举办了 DARPA 赞助的城市地区自动驾驶汽车竞赛。

日常生活中的人工智能(SIRI)

在过去的几年里,用自然语言回答问题已经成为智能移动设备的一个特征。因此,语音解释和识别界面(SIRI)成为了 2011 年底推出的 iPhone 4S 智能手机不可或缺的一部分。SIRI 可以用自然语言与手机主人交流,能够回答问题,为餐馆或电影提供建议,并随着时间的推移适应主人的需求。

Photo by: Fikri Rasyid on Unsplash

现代银行业

对已经在超过 13 个领域实施的人工智能应用的评估表明,86%的银行业主要商业人士已经从这项技术中受益。大多数人同意,到 2020 年,他们将在整个金融系统的各种运营中嵌入人工智能技术,从全球到地方。技术改变银行业的主要方式是提高自动化程度。据推测,自动化将降低 15%的商业成本,而人工智能在这方面发挥着主导作用。

技术进步和自动化带来的问题是它对流通中的工作数量的影响。尽管人们普遍认为自动化意味着许多工作岗位的流失,但在业务中使用人工智能的公司在很大程度上创造了新的工作岗位。预计到 2025 年,与 AI 系统开发和管理相关的新业务数量将增加 16%。

然而,与任何技术创新一样,决定其成功的是它在多大程度上促进了业务和改善了客户体验。如果银行的客户对人工智能系统节省时间感到满意,将他们引向真正的金融产品,这表明先进技术在商业中的应用是成功的。如果新服务让用户感到沮丧,或者让他们感到困惑,那么好的结果就不会出现。只有通过显著改善银行客户的体验和银行官员为客户提供更好服务的能力,才能看出人工智能在金融领域长期应用的有效性。好消息是人工智能系统有能力做到这一点。

人工智能与智力侵蚀

正如提到的,所有当前和未来的人工智能系统都将成为人类的巨大财富,但是我们真正的智能呢?我们会依赖人工智能而不自己解决复杂的问题吗?这让我们的智商更高还是更低?

Photo by Austin Distel on Unsplash

所有这些问题对我们的存在和关于 AI 都至关重要。但更重要的是这些同样问题的答案,这些问题很难回答。

在我看来,机器人永远不会接管世界,但这是一种可能性。

在这个现代世界中,一切都由机器驱动,一小部分代表人类的力量,我们依赖机器为我们做一切,这可能导致人类对地球上生活的可怕看法。

人工智能是为人类服务还是威胁人类?结论

人工智能不再是未来等待我们的东西。它已经成为我们的现在很久了,而且,毫无疑问,我们的未来将在超级数字世界中。今天的孩子已经是这样了,他们在 Siri(苹果)或 Alex(亚马逊)等人工智能系统的帮助下,使用应用程序做作业和睡觉。耶鲁大学的研究人员正在努力开发一种由手机控制的“人造胰腺”,以及一种通过算法明确知道你的胰腺何时需要胰岛素的应用程序。世界上最大的超市沃尔玛已经委托特斯拉生产了 15 辆电动汽车,这些汽车将由人工智能驱动的自动驾驶汽车驾驶,没有司机。快速消费品行业的大公司长期以来一直在使用智能软件进行有针对性的个人广告。人工智能可以让他们预测什么类型的广告最能“从情感上影响你”,影响你的消费习惯。算法和智能机器已经在金融证券交易所交易。

Photo by Jens Johnsson on Unsplash

全球技术变革可能发生得太快,因为更有可能的是,发达和富裕的社会无法充分监控数字化转型。一场关于新数字技术使用增加的社会后果的大辩论充斥了所有的媒体和专业门户网站。

对人工智能的恐惧已经充斥了整个世界。越来越多的人寻求“负责任地使用人工智能”的保证和机制。首先受到冲击的将是体力劳动者,但管理人员和医生、教授将来到现场。机器人将很快接管大量工作。[ 3

问题是等待那些将因为智能机器而失业的人的是什么样的命运,以及他们是否能够适应并从头学习一些全新的数字兴趣。

现代经济发生了多大的变化,最能说明问题的是,如今最富有的公司是那些靠软件等无形资产赚钱的公司。甚至国家也失去了意义。阿里巴巴第一人马云(Jack Ma)非常形象地解释了这一点。“没有人会说‘德国制造’或‘中国制造’,一切都将是‘互联网制造’,”刚刚退休的阿里巴巴创始人表示。

毫无疑问,世界正处于巨大的技术变革中,这将有助于更好的生活和许多领域的改善。然而,所谓的“大数据”和数字技术将是最大的资源,主要的政治和企业斗争将围绕这些资源进行。谷歌、IBM、脸书、亚马逊或阿里巴巴等全球转型的主要参与者负有重大责任。作为企业,他们有义务满足人类对数字技术的需求,但作为全球社会的成员,他们有道德义务使这些过程更加人性化。我们会同意,最终,最终的决定是由人做出的,而不是机器人或算法。至少现在是这样。

参考

[1]人工智能(更新:09.05.2019,16.05.2019)网址:
https://www . Britannica . com/technology/Artificial-intelligence

[2]人工智能的收益与风险(01.06.2016,16.05.2019)网址:
https://future oflife . org/background/Benefits-risks-of-artificial-intelligence/

[3][加迪] (05.05.2019,16.05.2019) —奇点—沃尔夫冈·斯拉尼,网址:
https://www.youtube.com/watch?v=_mk3Xa-rGds

人工智能‘思维机器’真的会思考吗?

原文:https://towardsdatascience.com/are-ai-thinking-machines-really-thinking-1fa9d758de6d?source=collection_archive---------16-----------------------

自从第一台通用计算机开发以来,科学家们就假设存在人工意识。一个可以反映人脑内部复杂互动的人造系统。虽然一些公众人物公开对即将到来的电子人末日感到恐惧,但对大多数人来说,人工智能现在指的是可以帮助我们更快完成工作的工具和应用程序,而不是机器人和人造人。人工智能现在主要被认为是特定类型技术的狭义使用,不同于人工通用智能(AGI),后者是一个更广泛的概念,包括合成意识。

Elon Musk: right to be afraid?

考虑到人工智能领域在过去十年左右的发展,以及大规模的持续投资,我们在通往终结者、复制人和 R2-D2 的道路上走了多远,以及出现的问题,都值得探索。许多科学家和思想家相信 AGI 是基于普遍性概念的科学必然性,而其他人则认为存在本体论物理局限性阻止了意识的再造。这种分歧实际上是哲学上的分歧;没有经验证据全面支持这两种假设。显而易见的是,科学家在再造甚至改进某些人类技能方面极其有效,但在复制其他技能方面却完全失败。

‘Artoo’ even had a sense of humour.

人工合成意识可能类似于类人智能的想法引发了令人难以置信的伦理和道德问题。这是一个庞大而有趣的话题,我不会在这里讨论。相反,我将考虑发展这样一个实体的实际障碍,以及它们的哲学含义。

人工智能是当今技术研究的主要发展趋势之一,以至于它渗透到了几乎所有其他技术。随着高级分析和自动化变得更加高效和可靠,人工智能将继续重新定义企业的运营方式,这意味着未能适应的公司将面临落后的风险。像自动驾驶汽车中发现的新人工智能技术,或者可以构建全新原创新奇事物的生成性对抗网络,可能会导致以前无法想象的应用和想法的发展。

这些进步是基于“思维机器”的核心思想;可以复制人脑某些认知功能的软件。人工智能没有单一的定义(甚至“智能”一词也是主观的),但它通常被理解为是指能够感知其环境以实现其可编程目标的应用程序。能够学习的机器,即开发超出硬编码的理解能力,是人工智能发展的最大子集之一。机器学习或深度学习算法通常基于人工神经网络。这些是专门模仿人脑工作方式的计算系统。

我们称它们为“思维机器”,尽管它们不像人类那样思考。他们感知他们的环境,但是他们没有意识到它们。计算机配备了内存、,就像有意识的生物一样,现代人工智能系统可以根据信息输入预测预测(这是人工智能可以构建预测模型的方式之一,例如用于商业或医疗保健)。这些能力都被认为是意识的必要方面,但机器只能以极其狭窄的形式实现它们。人工智能是不灵活的,除了它明确的、有限的编程之外,它不能预测或记忆。例如,一个旨在预测道路交通模式的高度先进的机器学习算法无法重新利用其智能进行对话或玩游戏。

Machines can be programmed to learn how to play chess but would be stumped if presented with your accounts.

以这种方式促进人工智能的灵活性似乎是一个巨大的挑战。然而,这可能不是意识最具挑战性的方面。主观体验的概念,也就是内在的、通常无法解释的精神状态和反应,经常被心理治疗师和哲学家认为是意识的“大问题”。托马斯·内格尔写道:

“…一个有机体具有有意识的精神状态,当且仅当有某种东西就像那个有机体的——某种东西就像那个有机体的。”**

换句话说,机器思考是不够的——它必须知道自己在思考,并且除了思想之外,还要有自己的存在感。笛卡尔有一句名言“我思故我在”,用来说明他有一个头脑,不同于物理思维的大脑。这个想法经常与 感受性 的概念联系在一起——对感觉的主观解释,既不可解释也不可预测。哲学家们经常会描述我们感知红色时所体验到的疼痛感觉的“疼痛感”或天生的“发红感”。我们可以科学地描述光线与我们眼中的视锥细胞接触时会发生什么,我们可以将其与我们见过的其他类似颜色进行比较,但没有办法让两个人客观地比较他们对红色的个人体验。对于科学家来说,这个概念本身就有问题,他们大多倾向于忽略它。然而,它是许多无形的、不可定义的抽象概念中的一个,这些抽象概念无疑存在于人的头脑中,也存在于人的头脑之外,无法用科学来定义。

Red: perplexing philosophers for generations.

像创造力、人类欲望、社会认知(或共享理解)、意义和自由意志这样的抽象概念是任何有意识存在的必要考虑因素,但已经证明它们本身极其难以数学形式化。这使得它们不可能翻译成计算机代码,因此也不可能翻译成机器代码。它们不能用机器学习或深度学习算法来解释或再造;无论数据集有多大,软件都无法理解或获得人类特有的特性,如同情心或敏感性。要做到这一点,必须用内置的模型对其进行编程,用程序能够理解的术语来描述这些概念所代表的内容。

开发正确的知识结构是人工智能研究人员提高人工智能效率的一个领域,以进一步补充日益庞大的数据集。然而,科学家们要准确地将无形的、情绪化的高级现象描绘成正式的实例还有很长的路要走。

现代计算系统的潜在能力可以用一句格言(也许过于简单)来概括;“如果你能理解一项任务,你就能对它进行编程”。一方面,这表明了巨大的应用潜力,这种潜力来源于人类理解的全部广度并受到其启发。本质上,几乎所有可知的和明确的事物都可以用数学方法形式化和程序化。另一方面,它很自然地将我们的探索局限于植根于物质的明确概念,而不是形而上学和哲学的领域。

所有观点都是我自己的观点,不与甲骨文共享。 请随时在 LinkedIn 上联系我

所有可解释的模型都可信吗?

原文:https://towardsdatascience.com/are-all-explainable-models-trustworthy-4378c5b0c1a5?source=collection_archive---------25-----------------------

Picture: Thinkstock

可解释的人工智能或可解释的数据科学是目前数据科学的热门词汇之一。可解释的模型被视为许多最近认识到的机器学习问题的答案,如偏见或数据泄露。

让模型更容易解释的一个常见原因是,用户会更容易信任它们,有时人们似乎认为这些想法几乎是同义的。例如,介绍解释黑盒模型的有影响力的 LIME 方法的论文名为“我为什么要相信你?”好像对一个模型如何做出决定有一个解释就离信任它只有一步之遥了。然而事实真的是这样吗?

这种等价的一个直接问题是,信任是在情感层面上给出的,而解释是一种更具技术性的人工产物——解释模型背后的假设是,可以提供一定数量的信息,以确保用户理解模型在做什么。相反,获得信任意味着跨越许多情感门槛。

因此,虽然过度不透明的模型确实会成为获得用户信任的巨大障碍,但这不是全部——如果满足其他一些条件,甚至可能存在不透明模型值得信任的情况。

首先,让我们回顾一下模型解释有用的一些方式。

  1. 可以向主题专家展示可解释的模型,允许他们识别模型的缺陷。
  2. 一个可解释的模型有时可以帮助我们找到一种获得更好结果的方法——例如,生存时间模型可能会提供一些关于如何提高生存时间的线索,尽管这些线索可能有些间接
  3. 对一个可解释的模型进行故障诊断更简单,因为它的决策过程更清晰。

因此,有理由让一个模型变得可解释,尽管这并不直接赢得信任,但它们可能是信任自己的一条途径。例如,将本地主题专家的意见整合到模型中可能有助于他们信任模型。同时,上面列出的目标本身显然是目的。

本质上,可解释性和信任是不同的,因为与基于事实的可解释性问题相比,信任是一个情绪问题,这仅仅意味着你可以识别单个预测者对模型输出的影响。因为它们对应于不同的问题,所以需要不同的方法来解决它们。

人们信任模型的第一步通常是开始信任展示模型的人或组织。这反过来意味着不要试图理解模型在做什么,而是要理解那个人或组织在做什么——他们希望通过实施这个模型来实现什么?

在迈斯特、格林和高尔方德提出的“信任方程式”中,并在他们的书《值得信赖的顾问》中推广,这对应于自我导向分母,它可以破坏其他积极因素。

更重要的是,理解模型的输入因素可以打开第二波怀疑,如果这些输入因素不符合模型用户的世界观,模型会如何。有时这是有保证的——这就是为什么上面提到的使用主题专家来验证模型解释的步骤很重要。

一旦我们开始呈现模型的输入与输出之间的关系,我们就开始接触人们的认知偏见和先入为主的想法。不管对错,如果你的模型与他们现有的想法相矛盾,人们通常不会轻易相信你的模型。为了克服这些异议,你需要研究他们的想法是什么,以及会阻止他们接受替代方案的认知偏见的种类。

巴斯特·本森的“认知偏见备忘单”提供了一些最重要的认知偏见的有用地图。本文根据他们试图解决的问题总结并解释了认知偏差。

一般来说,模型是对正在发生的事情的总结和简化,所以有些信息需要省略。一个对正在发生的事情有自己先入为主的想法的人很快就会发现他们想在模型中看到的东西被遗漏了。

另一方面,如果每个可能的变量和交互作用都被添加到模型中,它将很快变得太复杂,人类无法理解,因此需要达成平衡,最终模型的用户需要相信一些事情。至少他们需要说服自己,他们认为缺失或不正确的小细节不会影响全局。

克服这些信任问题需要一些要素。

首先,你的组织和它的代表必须产生信任,通过体现信任等式暗示的行为被认为是值得信任的。没有这种最初的信任基础,用户不会参与你的模型和其他努力。

接下来,你的模型需要足够开放和可解释,以允许用户参与其中。开放程度取决于用户和他们的环境。在这种情况下,用户几乎只关心模型的准确性。在其他情况下,用户会对模型的输入与输出之间的详细关系非常感兴趣。这可能会超越模型本身,并转移到对辅助可视化和数据的需求,以帮助用户自己决定正在发生的事情。

接下来,你需要建立一个不会增加他们认知偏差的模型。例如,如果中小企业中有一种理解,即特定变量在特定方向上对目标变量有单调的影响,那么它就需要出现在模型中,除非有其他人尊敬的主题专家支持的良好解释。

关键是没有一个银弹或者捷径可以从一个“可解释的”模型直接通向信任和使用你的模型的用户。相反,这是一个固有的混乱和反复的过程。

罗伯特·德格拉夫的书《管理你的数据科学项目》》已经通过出版社出版。

在 Twitter 上关注罗伯特

算法公平吗?

原文:https://towardsdatascience.com/are-complex-algorithms-fair-4435296f4d90?source=collection_archive---------24-----------------------

Photo by Markus Spiske on Unsplash

人工智能将如何改造我们的社会,代价是什么?正如总统候选人杨安泽已经承认的那样,我们正处于第四次工业革命的早期阶段。这种质疑源自对旧制造业经济的怀旧语言,以及对复杂算法公平性的质疑。

推动算法透明

算法是在有限的步骤中解决问题的一组规则。让计算机算法成为潜在争议的是操作算法的非透明性。虽然像谷歌这样的公司在网上详细讨论了他们的过程,但这种编程的内部运作仍然模糊不清。缺乏透明度使得偏见和审查的指责持续存在。电子隐私信息中心(EPIC)是算法透明的著名倡导者。7 月 16 日,EPIC 致信参议院委员会主席特德·克鲁兹参议员,谴责谷歌搜索引擎的各种危险。EPIC 声称,“内容可以根据政府设计的分级系统进行标记和分类,以实现审查并阻止政治反对派的访问”,“大多数用户不知道算法过滤如何限制他们对信息的访问,也没有禁用过滤器的选项。”

在线服务提供商的过滤能力是众所周知的。不管是有意还是无意,这种缺乏透明度都会带来后果。最近,总统候选人 Tulsi Gabbard 决定起诉谷歌涉嫌“干扰选举”谷歌承认在第一次民主党初选辩论后暂停了加巴德的账户;然而,谷歌声称,其自动系统会标记所有广告客户账户上的异常活动,“以防止欺诈和保护我们的客户。”谷歌很快恢复了她的账户。在参议院司法委员会的听证会上,谷歌全球政府事务和公共政策副总裁凯伦·巴蒂亚向参议员特德·克鲁兹保证“我们会努力改正错误。但这些错误影响了双方,并不是偏见的产物。”

这场讨论中遗漏的一个关键细节是,像谷歌这样的公司的商业模式依赖于广告商。“广告商和公司都厌恶风险,并寻求避免争议,”正如我之前在写的。谷歌的平台与其创收能力发生了冲突。在某些情况下,用户寻求一个非过滤平台,但是谷歌必须确保某种程度的保持,以便广告商继续利用他们的平台。

挑战大科技

EPIC 的观点直接挑战了这些平台所谓的偏见。改革派和保守派同样也因为反垄断的原因而挑战大科技的算法。虽然垄断通常是通过垂直整合产生的,但其中一些公司可能正在使用他们的算法来人为地推广自己的产品。EPIC 指称“谷歌收购 YouTube 后,EPIC 的搜索排名下降。谷歌用自己主观的“相关性”排名取代了客观的搜索标准。结果是“谷歌的主观算法更喜欢 YouTube 上的谷歌视频内容。”甚至最高法院也允许应用开发者起诉苹果违反反垄断法。开发者声称,通过要求“iPhone 和 iPad 用户只能从其门户网站下载应用程序,同时从商店的部分销售额中提成”,苹果已经成为垄断者。

7 月 23 日,美国司法部启动了“对主要科技公司的全面反垄断调查” ABC 新闻指出,“目前对美国反垄断法的解释显然不适用于提供廉价商品或免费在线服务的公司。”因此,司法部可能发现很难证明这些公司是垄断;另一方面,欧盟因谷歌违反反垄断法对其处以创纪录的 50 亿美元罚款。这些联邦调查类似于发生在 19 世纪末 20 世纪初的破坏信任案。

大型科技公司担心政府干预他们的运营是有道理的。要求每家公司对其算法完全透明是不可行的,尤其是因为这类似于要求任何其他公司公开其商业秘密。像谷歌这样的公司可以更清楚他们的程序和算法的意图。例如,谷歌的 Recaptcha 一直在使用人形点击来“训练谷歌的人工智能变得更加聪明”,他们声称应用“人类带宽来造福世界各地的人们”这是一种训练算法的巧妙方法,但大多数用户并不知道事实是这样的。

算法强大;然而,它们很大程度上受制于程序员的偏见。程序员可以表现出或隐或显的偏见,这就是为什么更多的透明度会让公众受益,尤其是在投诉数量巨大的情况下。

在公众对我们机构的信任度处于低位的情况下,增强这种信心将有利于谷歌和脸书这样的公司。在《卫报》,迪伦·柯伦写了关于脸书和谷歌储存你信息的程度,“你甚至没有意识到。”利用复杂的算法,这些公司可以利用你的搜索历史、应用程序使用情况、来拼凑各种数据点,他们甚至为你创建广告简介。在《纽约时报》上,詹妮弗·瓦伦蒂诺-德弗里斯写了关于他们如何使用和出售数据给广告商和“甚至寻求消费者行为洞察的对冲基金”的文章

在《大西洋月刊》上,卡韦·沃德尔写道“自动系统根据大量个人信息做出决策,通常不会透露计算中包含的信息种类。”随着这些算法变得更加复杂,确定哪些信息在结果中起关键作用将变得更加困难。此外,隐私倡导者有理由担心审查搜索引擎的可能性,就像谷歌在中国的项目蜻蜓一样,在美国出现。鉴于这些公司掌握着大量的数据,确保充分的保护和透明度符合我们的利益。如果他们行动不力,政府似乎随时准备干预。

国会辩论

国会正在讨论哪种法律制度最适合这些在线服务提供商。由于大数据是人工智能用来运行这些算法的燃料,这些公司必须继续主动和被动地收集数据。问题仍然是:消费者的利益在哪里起作用?

这正是法学教授乔纳森·齐特林(哈佛法学院)和杰克·巴尔金(耶鲁法学院)提出“信息受托人理论的原因,该理论要求其中一些公司充当法律认可的受托人。其他制度包括限制数据的出售或转让,取消第 230 条豁免权,给予用户访问从他们身上收集的数据的权利,禁止令人上瘾的功能,或者强迫他们向外部审计员提交他们的算法。

额外的监管负担是针对消费者的非直接税。展望未来,这些公司应该将更多的透明度融入到他们的算法决策中,即使他们可能仍然处于十字路口。不管真假,这些关于审查的指控揭示了与人工智能相关的问题。为了勇敢地面对民粹主义的反弹,大型科技公司必须做更多的事情来重新赢得公众的信任。他们可以从承认过去的错误开始,并采取更多措施防止未来的失信行为。

图表:数据隐私、营销投资回报率和令人毛骨悚然

原文:https://towardsdatascience.com/are-creepy-marketing-methods-really-worth-the-risk-8de99556adea?source=collection_archive---------9-----------------------

如果你的数字营销策略令人毛骨悚然,你需要选择退出

ROI vs Creepy — A High-Level Diagram

在最近的一次行业活动中,我被邀请参加一个讨论基于位置的营销解决方案的小组。该小组面对 100 名当地营销专业人士,他们的任务是帮助当地企业或在当地有零售业务的国家品牌。他们通过各种数字营销活动将更多的人流量带到他们的实体场所。这是我们这个时代一些最重要的数据隐私问题的战场。

舞台上有我们三个人,老实说,这不是你友好的讨论之一。因为消费者位置数据在将潜在访客定位到特定商店位置方面非常有帮助,所以这种实时数据令大多数营销人员着迷。想象一下,每一个走在街上的消费者都被广告轰炸,告诉他们在哪里可以吃午餐、买咖啡,或者在哪里可以找到最便宜的汽油。谁不想要那种便利和好处呢?

事实证明, 我不要。

而台上所有的营销人员

你的位置和适当的价值交换

基于位置的营销的好处是显而易见的。你有一个消费者,他选择进入他们手机上的一个应用程序,这个应用程序深深埋藏在他们的隐私政策中,有权向第三方分享或出售这些数据。这极大地提高了针对该消费者的定位能力。因此,当你换轮胎时,你的孩子下载的用来打发时间的看似无害的游戏现在可以跟踪你的一举一动,并将其出售给营销人员,他们可以向你的浏览器发送广告,给你发送短信,或通过他们的应用程序联系你。有了这些信息(通常加上一天中的时间),大多数营销人员可以提高他们的投资回报率。

但是他们应该吗?

这里的问题是关于适当的价值交换。当客户下载你的应用程序或访问你的网站(弹出窗口同意除外)时,他们期待某种形式的价值交换。消费者希望要么你的复古俄罗斯方块风格的游戏很棒,要么你的应用程序提供的天气信息是准确的。从本质上说,他们期望一些不花钱或免费的东西能很好地工作,并为他们提供价值。作为交换,他们可能会期待应用程序中的一些广告,偶尔的应用程序内购买优惠,或者其他一些对他们的钱包或注意力的成本。你设计的快速同意条款和隐私(被忽略)或旨在“推动”消费者前进甚至没有真正开始公平地表达价值的不平衡。

[## 超级人类推动我们通过监视资本主义——一本畅销书文氏图

我喜欢维恩图,它们是终极的博学工具。

medium.com](https://medium.com/@wardchristianj/super-humans-nudging-us-through-surveillance-capitalism-a-bestseller-venn-diagram-9a1a6290e727)

消费者没有想到的是,你的公司使用他们的实时位置数据来出售或与第三方共享。别告诉我他们不在乎。美国全国广播公司和华尔街日报的一项新研究清楚地表明,93%的美国人希望公司明确获得使用他们个人数据的许可。如果消费者知道你在跟踪他们,然后出售这些数据(不管你在条款中隐藏的匿名承诺),他们可能会说“不”。在我们的行业小组讨论中,我的共同小组成员提出了如下评论:

“老实说,只要人们得到了价值,他们就不会介意。”

"民意调查显示人们不关心隐私问题。"

“总体而言,人们不会为脸书或其他‘免费’应用付费,因此对位置追踪和定位没什么意见。”

这些说法的问题在于,它们倾向于引用【2017 年【Morning Consult 的旧民意调查,该调查称 67%的美国人不愿意为减少或删除广告而支付服务费用。这项调查似乎得出结论,与互动广告局 (IAB)的类似发现一样,能够在正确的时间将正确的广告瞄准正确的人是物有所值的理想结果。当然,IAB 在同一报告中也指出了以下几点…

“近一半的人认为定向广告的最大好处是减少了不相关的广告”

这意味着,当被要求在更一般的广告和更有针对性的广告之间进行选择时,这些调查的受访者基本上都要求减少广告的数量。这类似于问…

“你愿意被 100 只蜜蜂簇拥着,还是只有 20 只蜜蜂知道你喜欢户外生活方式?”

当然,我们选择 20 个,但是老实说,给我看一个实际上减少他们投放广告数量的营销商,一旦他们可以更有效地瞄准你。从来没有人这么做过。他们只是展示更多(现在有针对性的)广告。

更重要的是,被引用的研究不是关于基于位置的营销。它们是关于通过饼干、电视、路边广告牌和印刷广告的在线跟踪广告。这些研究不是关于实时的、基于位置追踪的广告。我认为这正是为什么他们不能被用作消费者对位置追踪态度的有效代理。在线追踪一个人的价值交换不同于基于位置的离线追踪。《纽约时报》关于追踪消费者位置的应用程序的文章对此进行了深入阐述,这是剖析真实价值等式的一个重要里程碑。

[## 你的应用知道你昨晚在哪里,而且他们不会保密

地图上的数百万个点描绘了高速公路、小路和自行车道——每一个点都沿着一条…

www.nytimes.com](https://www.nytimes.com/interactive/2018/12/10/business/location-data-privacy-apps.html)

营销投资回报率 vs“令人毛骨悚然”

在探讨基于位置的数据定位的潜在危害之前,也许有必要解释一下(广义上)营销人员是如何走到这一步的。首先,花在营销上的每一美元的投资回报(ROI)之间的平衡是一个难题。对于营销人员来说,他们的工作是推动流量(包括数字流量和步行流量),更多数据和更好数据的吸引力是难以忽视的。他们不断希望转向更有针对性的解决方案,因为投资回报数字将会增加(如上图右侧所示。)

不幸的是,这必须用 y 轴来衡量,这是随着时间的推移,营销变得更加令人毛骨悚然的趋势。像这样的图表对每个公司来说都是独一无二的。与利用位置数据的快餐车相比,一家大型 CPG 公司可能会从经典营销策略中获得更好的投资回报,因为他们的位置不固定。不要纠结于线条的长度,也不要纠结于它们是否符合比例。更重要的是,关注每一步的主要数据类型。

在寒冷的几个月里,我们如何向东北地区的消费者推销雪铲。没有人真的介意这一点,我认为这一点也不令人毛骨悚然。事实上,这似乎是一件合乎逻辑的事情,许多营销人员从这些非人性化的综合努力中获得了绝大部分投资回报。另一个例子是在客户可能会花时间的地方购买广告。例如,如果你在银行业经营一家金融科技公司,你可以假设访问《美国银行家》( disclosure:我为 SourceMedia 工作,是《美国银行家》的所有者)、《金融时报》和《华尔街日报》网站的观众是很好的选择。

Your Weather & Location Apps are Stalking You.

从这里开始,大多数公司沿着 y 轴向上移动到 cookies。为什么?Cookies 真的可以帮助你从聚合达到个性化的下一个层次。它们允许在个体水平上理解数据点,如感兴趣的主题或先前的浏览会话数据。从很多方面来说,这是走向令人毛骨悚然的第一步,从这里开始是一个多么危险的斜坡。使用 cookie 数据有允许的方式,也有过于激进的方式。无论如何,公众到目前为止还不一定会对 cookie 表示强烈抗议,尽管监管机构开始真正打击 cookie 的使用,但公众总体上似乎将此视为内容和价值之间正常价值交换的一部分。

然而,在下一个层面上,我们看到了公众的一些真正担忧。由于我们使用 cookies 来跟踪和关注在线消费者,他们肯定有很多话要说。卡斯帕床垫广告已经跟随你几个星期了,即使你已经买了床垫,你也无法逃避它。Twitter 上有一些搞笑的例子,展示了重新定位出现偏差的例子。

Seriously, how do you even sleep at night, Casper? (SOURCE, PUBLIC TWITTER FEED)

类似的情况是,人们似乎接受他们在一处地产上被监视,但他们并不期望从那里开始就一直被跟踪。

当我走进现实世界中的百思买时,穿着亮黄色衬衫的商店员工并没有跟着我出了门回到我的家。我会注意到,类似地,人们会注意到重新定位。

这就是为什么我认为从 cookies 到重新定位的转变是消费者心目中的一个重要区别。此时,这种活动转变为主动监视,从主动监视到目前为止,要被动得多。消费者几乎立刻就意识到了这一点。有 90,000 个关于“重新定位令人毛骨悚然”的搜索结果,许多人解释说,当你过度使用这种策略时,愤怒可能是消费者的自然反应。

SOURCE: Google Search Results

尽管如此,仅仅是查找如何使用重定向广告就有超过 900 万个结果,因为它们是有效的。事实证明,跟随潜在客户重新介绍你的产品或服务是可行的,但这可能会很快失控。在潜在客户(或卡斯帕床垫的现有客户)访问你的网站很久之后,你还应该跟踪他们吗?

基于位置的营销数据

这使我们在我们绘制的图表上从重定位跳到实时的、基于位置的跟踪。而且,虽然图表没有按比例绘制,但我要说这是在“令人毛骨悚然”的 y 轴上的一个巨大飞跃。

对大多数人来说,在现实世界中被跟踪是不可接受的。它跨越了太多的界限,是我们技术的延伸。在跟踪孩子的地方做得更深入。去重读《纽约时报》的那篇文章吧,关于你的孩子在学校时从他们的设备上发出的所有定位信号,这是令人恐惧和不可接受的。

现在,位置数据空间中的许多人说,“等等,我们只使用匿名数据。”不幸的是,这也不准确。说数据是匿名的并不等于说它不能被轻易识别。仅仅因为他们在系统中使用唯一的标识符而不是某人的真实姓名,并不意味着这是匿名的。事实上,对于基于位置的数据,这与事实相去甚远。

[## 谷歌面临 GDPR 对“欺骗性”位置跟踪的投诉

一个欧洲消费者监督组织对谷歌提出了隐私投诉——认为该公司使用了…

techcrunch.com](https://techcrunch.com/2018/11/27/google-faces-gdpr-complaint-over-deceptive-location-tracking/)

人是有模式的。你醒来的地方,你上下班的地方,你喝咖啡的地方,你工作的地方。通常一周有 5 天,你在同一个地点起床,每个追踪你位置的应用都知道这一点。通过简单的公共记录财产或地址信息,从你的手机传回的 GPS 坐标,公司可以确定确切的地址和该地址的所有者。此外,如果您大部分时间都在同一个办公室或工作地点上班,这还可以确认您的身份。知道家庭地址和公司地址通常足以在基于位置的数据库中“重新识别”任何人。

等等,你怎么知道我的位置?

最近,Foursquare 推出了一款名为“超趋势”的新应用:

该热图旨在向您展示和分享来自使用其应用程序或利用其位置服务工具的人们的信息。在奥斯汀 SXSW,你可以看到热点在哪里,如果你是一个内向的人,最好不要去哪里。这些地图利用了 Foursquare panel 的数据,换句话说,它不一定拥有每个人的位置,更多的是利用一群选择加入的用户来推断数据的趋势。如果不从数学上探讨这种方法的问题,主要问题是 Foursquare 完全理解这里存在隐私问题,并使用这款应用程序作为与客户对话的方式。

一位行业专业人士的初步回应完美地表达了这种担忧:

Does GDPR Demand Apps Sharing Data to be Identified? (Source: Public Twitter Feed)

许多人仍然不明白的是,像 Foursquare 这样的公司向其他应用程序提供的 SDK 或软件开发工具包允许他们访问你的位置数据。换句话说,你可能不使用由 Foursquare 构建的或以 Foursquare 为品牌的应用程序,但你肯定仍然有他们的代码在你最喜欢的应用程序的后台运行。这也绝不是在敲打 Foursquare。他们已经建立了一个出色的框架来嵌入位置感知功能,问题是谁知道这一点,以及它的用途是什么?

问题比比皆是:

哪些平台使用 Foursquare 数据和位置服务?

然后 Foursquare 把这些数据卖给谁?

向应用程序提供这些位置服务的其他平台有哪些,我如何选择退出?

许多人意识到 Foursquare 正在试水,但也微妙地揭示了他们的 SDK 或位置服务平台正在不仅仅是他们自己的应用程序的背景下运行。正如他们所说,“来自我们自己的应用程序或使用我们技术的其他应用程序的混合数据。

事实是,他们向世界展示的“令人毛骨悚然”的地图视图是每个基于位置的跟踪系统的一部分。Foursquare 只是首批让世界真正看到(并使用)他们多年来拥有的数据的后端视图之一。当处理位置数据的平台试图筹集资金或“惊艳”投资者或合作伙伴时,他们通常会展示这种类型的地图,对用户进行实时或接近实时的位置跟踪。我见过无数来自定位服务平台的“酷”地图视图,它们通过利用手机定位 pings 或 Wi-Fi 热点信号跟踪来显示人类群集效应。

伤害?

所有这些的真正问题是“有什么危害?”实际上,Foursquare 正在展示这一点,并声明所有这些数据都是完全匿名的,因此,在使用中是可以接受的。那可能是真的,也可能不是。例如,我当然认为我们在城市规划和紧急疏散或其他民事演习中看到的一些研究值得抓住机会。通过利用实时位置统计数据,以更智能的模式安排车辆的路线,甚至交通模式也发生了巨大变化(或者,不那么智能的)。

我们看到的危害不一定是 SXSW 的热点匿名地图。坏处是这永远不会停止。危害在于,应用程序不会通过访问个人的位置数据来匿名化个人,而是根据他们的位置专门针对这些个人提供广告和其他优惠。虽然 Foursquare 似乎没有分享使用其位置服务的每个应用程序的列表,但你可以肯定的是,他们正在使用位置数据,专门针对那些进出特定位置半径点或多边形的人投放广告。

底线是,你真的需要考虑这些活动,以及投资回报是否值得你的(目标)观众的潜在愤怒或担忧。仅仅通过优化上图中的蓝色阴影区域,就可以获得大量的投资回报。这些活动大多被你的受众接受为“经典”的营销活动,甚至是合乎逻辑的。

数据隐私正在继续发展,在美国,广告集团正联合起来游说国会颁布一项国家隐私法。虽然他们的努力是帮助公司避免各州的隐私法规的拼凑,但营销人员必须接受他们在追求投资回报时已经越过了界限。数据隐私是关于理解人类的基本权利,基于位置的数据是一个关键的转折点。

[## 了解数据的真实性质及其主体的权利

这是关于企业数据战略变化本质的三篇系列文章中的第二篇。摘自数据…

www.information-management.com](https://www.information-management.com/news/understanding-the-true-nature-of-data-and-the-rights-of-its-subject)

在以后的帖子中,我们将讨论同意和围绕同意的价值主张交换。明确地说,当消费者主动允许并有意让你的公司跟踪他们的物理位置时,这不是问题。事实上,它可以是用户和你的公司之间的一个伟大的伙伴关系。我只是愿意打赌,价值交换,用户从你的公司分享他们的实时位置数据中获得的等式目前是错误的。如果他们真的知道你在追踪这些数据,他们可能会要求你的广告收入分成或其他类似的价值。他们没有问的事实恰恰突出了他们不知道你在用这些数据做什么。

同样,如果你在寻求投资回报的过程中采取的营销策略进入了“令人毛骨悚然”的领域,我们强烈建议你退出

信息信托理论与市场

原文:https://towardsdatascience.com/are-data-hoarders-the-modern-day-fiduciaries-d6a9c01b3990?source=collection_archive---------20-----------------------

Photo by Firmbee.com on Unsplash

不断变化的世界需要新的社会观。鉴于以技术为基础的公司的影响和审查,我们必须分析新提出的法律理论。消费者经常听说脸书的违法行为,最近导致美国联邦贸易委员会对 T2 罚款 50 亿美元。消费者委托这些机构充分保护个人信息。此外,这些机构继续向公众展示自己是负责任和正直的组织,致力于为用户提供最佳体验。它们为消费者提供了曾经被认为不可想象的服务,但这种服务是有成本的。他们的服务、公众表现和广泛的数据收集意味着他们可能确实是“信息受托人

耶鲁大学法学院宪法和第一修正案教授杰克·m·巴尔金在加州大学戴维斯分校题为“信息信托和第一修正案”的法律评论中讨论了“信息信托”一词。巴尔金的理论依赖于宪法律师之间关于特定隐私法是否违反第一修正案的争论。第一修正案法律是复杂的,它被分为三类,包括公共演讲,政治演讲和商业演讲。法院经常发现很难区分公共话语和商业言论,并推翻了限制“基于内容或基于说话人的对获取信息和用于营销目的的言论的限制”的法律。巴尔金的理论依赖于利用普通法理论,即在线服务提供商和社交网站(如脸书或谷歌)的受托人。这一理论几乎通过《纽约隐私法》变成了公共政策。

什么是受托人?

受托人(如律师或财务顾问)的任务是代表客户的最大利益,同时保持足够的灵活性来代表客户行事。在信托关系中,客户处于弱势地位,理所当然地信任和信赖受托人。正如巴尔金所写的,“在某些情况下,你可能与在线服务提供商有信托关系,特别是如果你必须信任和依赖他们,他们反过来会鼓励你的信任和依赖。”例如,谷歌知道大多数互联网用户依赖它的搜索引擎。如果谷歌直接偏向他们的搜索算法以支持他们偏好的政治立场,那么他们将直接侵犯用户获得公平平台的权利。正如温斯顿·丘吉尔所说,“未来的帝国是思想的帝国。”

自由营销者会理直气壮地反驳互联网用户可以自由使用其他搜索引擎。尽管谷歌在市场份额上几乎完全占据主导地位,但用户可以使用搜索引擎,如必应或雅虎。这些平台的市场份额要小得多,但很少有关于其公司滥用职权的重大披露。的确,平台越大,出错的空间就越大。这正是信息受托人的理念如此引人注目的原因。如果像脸书这样的平台在法律上被要求充当用户的受托人,那么个人信息的收集将是透明的,网络安全将是优先事项,含糊不清地强制执行“社区标准”将是不可能的。

市场可以解决这个问题

实际上,这一法律制度可能是不必要的。社交媒体用户开始离开这些平台,因为他们的负面情绪和对令人发指的事件的持续关注。已经有研究证明了社交媒体对心理健康的负面影响,因为它可能加剧社会孤立感。由于这些问题,每天都有新的平台产生。虽然 Myspace 曾经是“美国访问量最大的网站”,但现在它在年轻人中基本上不为人知。社交趋势会随着时间而变化,除非平台遵循用户偏好,否则它们将变得无关紧要。“那么,Myspace 怎么了?“除了重新投资自己,并在今天的 Snapchat 过滤器和 Instagram 故事时代保持相关性之外,没有什么,”Sam Brodsky 在 Metro 的 中写道。

这就是资本主义的美妙之处,也是“创造性破坏”的理念。今天的主要技术公司并没有十年前的现代规模,十年后它们也完全有可能不再具有相关性。“公司希望保持竞争优势,”巴尔金指出。这是我们政策制定者辩论中遗漏的关键细节。雅虎旗下的互联网搜索引擎 AltaVista 领先于谷歌。Myspace 领先于脸书。易贝先于亚马逊。就在我们说话的时候,下一家大型科技公司可能正在筹建中。

将信托的法律理论应用于一些科技公司似乎是必要的,但正如约瑟夫·熊彼特所说,“我们正在处理一个有机的过程。”只要政府不进行不必要的干预,市场解决这类问题的能力是不可避免的。“通常被形象化的问题是资本主义如何管理现有结构,而相关的问题是它如何创造和摧毁它们,”熊彼特写道。为了充分把握我们当前的形势,我们必须认识到市场是如何随时间变化的。

信息信托理论为我们提供了一个监管这些公司的法律框架。鉴于资本主义的动态能力,我们必须要求这些公司在收集、出售和保护个人信息方面更加透明和严格。目前的情况肯定是行不通的,这就是为什么这些公司应该为用户提供“知情权”和“选择退出功能。不幸的是,这些平台中的一些似乎满足于政府干预,只要政府干预允许它们经受住政治和媒体的审查。政府干预可能会提供暂时的安慰,但是的代价可能会比预期的更大。历史表明,市场在解决我们社会的差距方面发挥了建设性的作用。只要有足够的压力,我们就有能力建设一个更加安全的未来。

第一胎婴儿更有可能晚育吗?

原文:https://towardsdatascience.com/are-first-babies-more-likely-to-be-late-1b099b5796b6?source=collection_archive---------0-----------------------

是的,也更有可能是早期的。但只是一点点。

如果你怀了第一个孩子,你可能听说过第一个孩子更容易晚育。此外,你可能听说过他们更有可能早到。事实证明,两者都是真的。

  • 如果“早”是指早产——怀孕 37 周之前——第一胎婴儿更有可能是早的。根据全国家庭成长调查记录的活产婴儿,大约 12%的第一胎婴儿早产,相比之下,其他婴儿为 10%。
  • 如果“晚”是指 40 周后,第一胎婴儿更有可能晚出生:大约 15%,相比之下其他婴儿只有 10%。

下图显示了活产儿(不包括多胞胎和剖腹产分娩)的妊娠长度分布情况:

Distribution of pregnancy lengths for full-term single births. The shaded areas show 90% confidence intervals.

第一胎婴儿在 39 周时不太可能“准时”,更可能晚一点,在 41 到 43 周之间。

在足月妊娠中,第一胎婴儿的出生平均要晚 1.3 天。但是平均并不能说明全部。

还要多久?

假设你在第 37 周的开始。此时距离分娩的平均时间为 2.8 周。

两周后,在第 39 周开始时,平均剩余时间为 1.2 周。如你所料,随着每一周的过去,平均剩余时间会减少。

但之后就停止了。

下图显示了产科最残酷的统计数据:怀孕每一周开始时计算的平均剩余时间:

Average remaining time at the beginning of each week of pregnancy, for live births, excluding multiple births and deliveries by C-section.

在第 39 周到 43 周之间,分娩前的剩余时间几乎没有变化。时间在流逝,但终点线却一直朝着未来前进。

在第 39 周,如果你问医生孩子什么时候出生,他们会说“任何一天”如果你在第 40 周再次询问,他们会给出同样的答案。在第 41 周。这听起来可能令人沮丧,但他们是对的;差不多五个星期,你总是差一个星期。

对于第一胎婴儿来说,这种情况更糟糕一些。下图显示了第一胎婴儿和其他婴儿的平均剩余时间:

Average remaining time at the beginning of each week of pregnancy for first babies and others.

在第 39 周开始时,头胎婴儿的平均剩余时间为 1.3 周,其他婴儿为 1.1 周。相差约 36 小时。

这种差距持续了一周左右,但在第 41 周之后,第一个婴儿和其他婴儿是无法区分的。

也许这个星期?

当你为怀孕的最后几周做计划时,到分娩的平均时间并没有太大的帮助。您可能更愿意在每周开始时知道在接下来的七天内交付的概率。

下图回答了第一个婴儿和其他婴儿的问题:

Probability of delivering in the next week, computed at the beginning of each week.

在第 37 周开始的时候,如果你想的话,你可以打包一个袋子,但是只有 6%的机会你会需要它,不管是不是第一个孩子。

在第 38 周开始时,下一周分娩的几率约为 11%,不会高太多。

但在第 39 周开始时,这一比例要高得多:头胎婴儿为 54%,其他婴儿为 61%。

这种差距持续一周左右;第 41 周后,两条曲线实际上是相同的。

这些差异是真实的吗?

这篇文章中的结果可能反映了第一胎婴儿和其他婴儿之间真正的生物学和医学差异。在这种情况下,它们很可能是预测性的:如果你正在期待你的第一个孩子,平均来说,你将不得不比随后的生育等待更长一点的时间。

但是这些结果可能是由于测量误差造成的。

  • 按照惯例,怀孕的持续时间从母亲最后一次月经的第一天开始计算。报道的长度可能不准确,对第一次做母亲的人来说可能不太准确。
  • 此外,NSFG 的数据是基于采访,而不是医疗记录,所以它依赖于受访者的记忆。对于第一胎婴儿,报道的长度可能不太准确。

但是,即使第一个婴儿的测量误差不同,也不清楚为什么他们会偏向更长的持续时间。

头胎婴儿和其他婴儿之间的明显差异也可能是由与怀孕时间相关的混杂因素造成的。

  • 如果一个妇女的第一个孩子是通过剖腹产分娩的,那么随后的分娩更有可能被安排好,而不太可能晚。为此,我排除了剖腹产分娩。
  • 如果第一胎婴儿不太可能被诱导,更多的婴儿将被允许晚育。我不知道他们会是什么原因,但数据集没有引产的信息,所以我不能确认或排除这种可能性。

我展示的结果具有统计学意义,这意味着如果第一胎婴儿和其他婴儿之间没有差异,我们就不太可能看到这些差异。从 2002 年到 2017 年的调查过程中,结果也是一致的。所以这种明显的差异不太可能是随机抽样造成的。

更多阅读

这篇文章基于我的书《Think Stats:用 Python 进行探索性数据分析》中的一个案例研究,你可以从绿茶出版社免费下载这本书。它也可以从奥赖利媒体 ( 亚马逊联盟链接)获得纸质和电子格式。

我在博客里发表了一篇类似的分析(基于更老的数据) 大概是想多了 ,在这里可以读到更多关于数据科学和贝叶斯统计的文章。

如果你喜欢这篇文章,你可能也会喜欢“检验悖论无处不在”,这是关于一个令人惊讶的无处不在的统计错觉。

方法学

我使用了来自全国家庭增长调查 (NSFG)的数据,该调查“收集了关于家庭生活、结婚和离婚、怀孕、不孕、避孕措施的使用以及男女健康的信息。”

该数据集包括 43 292 例活产的记录,其中我排除了 737 例多胞胎和 11 003 例剖腹产。我还排除了 3 例妊娠持续时间超过 50 周的病例。这一分析是基于剩余的 31 906 个案例。

NSFG 是美国居民的代表,但它使用分层抽样,所以一些群体被过度抽样。我使用了加权重采样来校正过采样,并生成图中所示的置信区间。

数据清理、验证和重采样的细节在这个 Jupyter 笔记本中。分析的细节在本笔记本中。

关于作者

艾伦·唐尼是马萨诸塞州奥林学院的计算机科学教授。他和妻子有两个女儿:第一个女儿提前一周出生;第二次是晚了两个星期,在一点鼓励之后。

《辣妹》观众性别歧视吗?

原文:https://towardsdatascience.com/are-hot-ones-viewers-sexist-2a1373b6b69?source=collection_archive---------17-----------------------

深入分析

根据对 YouTube 评论的文本分析,可能有一点

热门人物,“热点问题和更热翅膀的节目”,已经成为一个奇观。自 2015 年四年前首次亮相以来,YouTube 访谈节目的人气稳步增长。大约九个月前我看了我的第一集。从那以后,这个热门词汇似乎每隔几周就会出现在人们的对话中。

对于那些不熟悉的人来说,热门人物主持人肖恩·埃文斯每集采访一位名人。热门人物和其他名人访谈有什么不同?首先,肖恩是一个优秀的面试官。第二,也是最明显的,肖恩和他的客人在整个采访中吃了一大盘越来越辣的鸡翅。它极具娱乐性——如果你从未看过,我推荐你先看看最近在 播出的一集,我们先来享受一下 YouTube 频道。

最近,我的一个朋友提到,以女性为主角的热门剧集似乎比以男性为主角的剧集受到更多性别歧视(或者至少是负面的)评论。我很容易相信这种说法至少有些道理。找到一些证据当然并不困难——翻阅最近关于一集女嘉宾的评论,你会很容易找到性别歧视或物化评论的例子。

那次谈话让我开始分析思考。一些精心挑选的例子很容易成为确认偏差。有没有可能客观地显示女性客人比男性客人得到更多的性别歧视或负面评论?

定义目标

有一堆热门的 YouTube 视频,其中一些有女嘉宾。每个视频都有一堆评论。我们的目标是使用统计学和数据科学来确定对女性客人的评论是否不同于对男性客人的评论,这种不同可以被描述为性别歧视。听起来很简单,但是…

计算机擅长处理黑白问题。它们非常擅长遵循定义的指令和执行复杂的计算,但它们不能像人类那样做出判断。性别歧视绝不是一个非黑即白的问题。看到就知道,但是很难定义。两个人有理由不同意某个评论是否是性别歧视。同样的评论在一种情况下可能是性别歧视,但在另一种情况下可能不是。这是一个微妙的概念。

换句话说,教计算机识别性别歧视(或种族主义、仇恨言论等。)是辛苦的。在社交媒体时代,这也是一个非常重要的问题,但还没有人提出一个很好的解决方案。如果你感兴趣的话,这篇由格伦达尔等人撰写的论文可以让你一窥该领域的研究现状。

方法和结果

与仇恨言论检测领域的前沿研究相比,我将采取一种简单的方法。大多数仇恨言论检测技术基于在标记数据集上训练的分类模型。这种方法可能是解决当前问题的最佳方式,但是在我的数据集上复制这些模型需要花费大量的时间和精力。相反,我将采取一种间接的方法来识别性别歧视,这种方法使用更快、更现成的技术,如下所述。

所有的分析都是使用 Python 完成的,并且可以在 GitHub 库中获得。这篇文章中显示的数据和可视化可以在知识库中的 Jupyter 笔记本中找到。

数据概述

该数据集包含了 YouTube 上对前八个热播季视频的所有评论——总共有近 139 个视频和超过 100 万条评论。我根据视频中是否有女嘉宾将数据集分成两组。这意味着,如果其中一位嘉宾是女性,那么有多位嘉宾的视频将被归入“女性嘉宾”组。

总共有 23 个视频有女嘉宾,116 个没有。这是一个巨大的差异!辣的大概应该多争取点女嘉宾吧!(在最近几季中,女性出现的频率更高了,但仍没有一季是女性占 50%的。)

情感分析

我们寻找性别歧视迹象的第一种方法是进行情感分析,这是最基本的自然语言处理技术之一。情感分析获取一些文本——在我们的例子中是 YouTube 评论——并分配一个分数,将其情感分为积极、消极或中性。在该分析中,情绪得分从-1 到 1,其中-1 是最消极的,0 是中性的,1 是最积极的情绪。

我们潜在的假设是,性别歧视的评论通常会带有强烈的负面情绪。因此,如果有女性嘉宾的视频有大量性别歧视的评论,我们会认为这些视频的平均情感得分较低。

让我们通过看克莉茜·泰根事件中的几个例子来简单地检验情感分数是否是性别歧视的合理代表。我们从这个视频上情绪得分最低的评论开始。在一个巨大的 -0.997 情绪得分中,我们有这个宝石(有一些审查):

请不要再在这个节目里带一袋恶心的丑东西了!你为什么要带那个看起来像*** 的花栗鼠来这里?她是如此令人讨厌,她的脸是可怕的,她的声音是可怕的,我个人甚至不知道她为什么出名,除了嫁给了 JL。我真希望这个*****会死你这个丑**** !你太恶心了你****肥头大耳的荡妇淫妇***** ***!死啦死啦死啦死啦死啦

我认为那条评论是公然的性别歧视。所以至少,我们知道,通过寻找低情绪得分,可以找到极端性别歧视的评论。

然而,我们知道我们会遇到一个问题:评论可以是负面的,但不带有性别歧视。比如这条评论的情感分 -0.94 :

地狱不吃大坝翼。你知道你要去辣的。什么?浪费翅膀。可惜删了一集。重拍第七季第一集 SMH。

这个人显然对 Chrissy 没吃鸡翅就把辣酱舔了下来很不高兴。负面情绪得分似乎是准确的,但这个评论在我看来没有性别歧视。像这样的评论会给我们的数据增加噪音。低情感分数会识别出大量性别歧视的评论,但它们可能会识别出更多负面但非性别歧视的评论。

另一个潜在的问题是情感分析器的质量。语言是复杂的,现代情感分析远非完美,所以我们应该预料到一些评论会被错误分类。例如,这条评论的情绪得分为 -0.91 ,但它实际上似乎是积极的:

克里斯无疑是个野蛮人!!她杀了它!!光舔酱更糟糕

这里的观点是,评论者对 Chrissy 处理辣酱的能力印象深刻,所以这应该被归类为积极的评论。情绪分析者不同意,可能是因为像“野蛮人”和“被杀”这样的词,它们通常有负面含义。

因此,情感分析似乎给了我们一个体面的,但肯定有缺陷的,发现性别歧视评论的方法。回到手头的问题。热门人物评论中是否普遍存在性别歧视?让我们为每个视频计算一个“正面比率”,定义为正面评论的数量除以负面评论的数量。下图显示了男女嘉宾视频的正比率分布,不包括第一季的 outlier⁴:

Figure 1: Distribution of positive ratio for videos with male and female guests.

男性嘉宾的峰值更靠右,表明有男性嘉宾的视频往往有更高的阳性率。果然,有女嘉宾的视频平均正面比为 2.12,而有男嘉宾的视频平均正面比为 2.20。

然而,这不是一个很大的差异,我们的样本量相当小。t 检验(对不起,Bayesians)可以帮助我们决定两组(男性和女性)的平均阳性比率之间是否有任何有意义的差异。t 检验将返回 p 值-低于 0.05 的值通常被认为具有统计学意义。在我们的例子中,t 检验结果返回 0.58 的 p 值,表明我们的组之间没有统计学上的显著差异。

总之,基本的情感分析可能会显示出热门视频评论中性别歧视的极小数量的证据,但这些证据远非决定性的。

毒性分数

谷歌有一个名为视角的工具,专门用来识别“有毒”评论。Perspective 给可能被认为是虐待或骚扰的评论分配一个高毒性分数,性别歧视肯定属于这些类别。它在概念上类似于情感分析,但有更具体的重点,非常适合我们的用例。我将使用透视“毒性”和“严重毒性”评分,因为我认为这些是最类似于性别歧视的可用选项。

让我们看看毒性评分如何评价之前引用的克莉茜·泰根视频中的评论。记住,这些评论中有一条是性别歧视的,另外两条不是。我们的目标是找到一种度量标准,将性别歧视的评论与其他评论区分开来。

Table 1: VADER sentiment score and Perspective toxicity scores for comments on the Chrissy Teigen video.

正如我们之前看到的,情感分数在区分性别歧视评论方面做得很差——所有评论都有非常相似的情感分数。毒性评分,尤其是严重毒性,要好得多。性别歧视的评论得到了很高的毒性分数,而其他评论得到了较低的分数(尽管仍然没有那么低——毒性分数从 0 到 1)。

公平地说,这是一个经过精心挑选的例子。在数据集中还有其他例子,毒性分数并不比情感分数好,因为与情感分数非常相似,毒性分数仍然会与书面 language⁵.的细微差别相冲突也就是说,毒性评分似乎在区分性别歧视和负面但非性别歧视的评论方面做得更好。

让我们画出所有视频的毒性分数。下图显示了所有视频的平均毒性和严重毒性 scores⁶的分布,再次排除了第一季的 outlier⁴:

Figure 2: Perspective toxicity and severe toxicity scores for videos with male and female guests.

与男性分布相比,女性分布似乎向右侧偏移(尽管男性游客的最极端得分甚至更向右延伸)。事实上,女性客人的平均毒性为 0.306,平均严重毒性为 0.204,而男性客人的平均毒性略低,为 0.297 和 0.200。

然而,与之前的情绪得分一样,差异非常小。t 检验给出毒性评分的 p 值为 0.36,严重毒性评分的 p 值为 0.69。这两个 p 值都与传统意义上的统计显著性相差甚远,因此我们不能自信地声称毒性评分已经确定了两组之间的差异。

毒性分数让我们和情感分数处于几乎相同的位置。有一点证据表明,女性会收到更多恶毒的评论,但从统计学的角度来看,这一证据并不令人信服。

单词用法

让我们稍微改变一下。到目前为止,我们已经采取了非常量化的方法,试图找到一个量化性别歧视(或仇恨,有毒等)的度量标准。)评论在每个视频上。现在让我们看看我们是否能找到两组评论中使用的语言的差异。

总体思路很简单。对于评论数据集中的每个词,我们想知道这个词是在男性评论还是女性评论中出现得更频繁。我们将拟合一个模型,告诉我们任何给定的词在与女性嘉宾的视频评论中被使用的可能性有多高(或多低)。一旦我们有了自己的模型,我们就可以查看每组的热门词汇,并寻找它们之间的差异。

具体来说,我用多项似然性和信息量丰富的 Dirichlet 先验实现了贝叶斯模型,这在 Monroe 等人的这篇论文中有所描述。技术细节对于理解结果并不重要,但如果你的眼睛在上一句结束时没有呆滞,请阅读这篇论文——这是解决这类问题的一种优雅的方法。该论文的作者使用该模型来识别民主党人和共和党人的演讲差异,这与我们自己的任务没有太大区别。

在拟合模型之前,我执行了一些小的预处理步骤,比如词汇化和删除标点符号(NLP 中的常用技术)。我还用一个通用的符号替换了性别代词,用一个通用的符号替换了客人的名字。通用标记防止这些术语主导结果——像“她”和“她”这样的词在女性嘉宾的评论中使用得更频繁,但这并不有趣。

下表显示了与女性和男性 guests⁷:相关的前 30 个词和二元模型

Table 2: Top 30 words and bigrams for female and male guests according to the informative Dirichlet model.

花些时间通读这些列表,看看你是否注意到任何有趣的不同。以下是我看到的一些例子:

  • 女性名单中有很多描述身体外貌的词,如“美丽”、“可爱”、“华丽”。很高兴看到这些话是积极的,但这可能是评论者物化女性并主要关注她们的外表的证据(请注意男性是如何不包括“英俊”的)。
  • 女单里有几个负面词,特别是“烦”。如果你在一个有女嘉宾的 Hot Ones 视频上看到一些评论,用不了多久就会发现一条评论形容她很讨厌,所以看到这个人上榜我一点也不奇怪。
  • 男性排行榜榜首有很多骂人的话。我不太确定这是怎么回事,因为上下文对这些词很重要。这些评论中有很多可能是负面的,但其中一些可能会夸大男性毒性分数——当诅咒语用于正面的 context⁵.时,这些分数是不可靠的
  • 男单有很多《有史以来最好的一集》的变奏。我认为这里有些隐含的性别歧视。平均而言,评论者似乎偏向于以男性为主角的剧集。
  • 男性排行榜有“最搞笑”、“笑”,甚至还有😂表情符号。这符合男人比女人更有趣的文化观念(这可能不是真的)。

让我们更深入地探讨最后一点。下表显示了一些“有趣”的 bigrams⁷和它们在模型中相应的 z 分数,这告诉我们这个词在男性或女性评论中有多常见。

Table 3: A deeper look at “funny” comments.

热播节目中有很多有趣的女性,但是很明显,评论者平均认为男嘉宾比女嘉宾更有趣。这位模特甚至将“不好笑”和“不好笑”与女嘉宾联系在一起。这很难证明,但我认为这里有一丝性别歧视。我怀疑许多评论者是故意宣称男人比女人更有趣,但似乎确实有一些潜意识的偏见。

结论

那么,我们在热门评论中找到性别歧视的证据了吗?算是吧,但不是压倒性的。情绪分析和毒性评分提供了一点点证据,但它很容易被认为是统计上无关紧要的。词汇用法分析说明了男性和女性视频评论之间的一些词汇差异。这些差异似乎有点性别歧视,但它们也是一个开放的解释。

如果被追问,我会说是的,在热门评论中有性别歧视的证据。我认为这个词的用法分析令人信服地确定了一些性别歧视的主题。你不同意吗?我是确认偏见的受害者吗?请在评论中告诉我。

脚注

[1]:具体来说,我的数据集包含了我在 2019 年 5 月中旬刮到的日期之前的所有评论。我只包括基本级别的评论,即不回复评论。我还从分析中排除了一些视频:第二季的假日特辑(没有任何嘉宾),史蒂芬·科拜尔深夜秀集(不在热门频道播出,所以大概是不同的观众),以及马雷欧·巴塔利集(在 YouTube 上不可用)。我写了一个 Python 脚本,它访问这个网络抓取器来抓取评论数据(谷歌提供了一个 API,但是它每天只能抓取 10000 条评论)。

[2]:我使用了 VADER 情感分析模型,这是一个为社交媒体文本设计的基于规则的模型。原纸这里是这里是。

[3]:Jupyter 笔记本随附的中对正比率指标进行了更详细的描述。

[4]:第一季被排除在这个情节之外,因为我把它当作一个离群值。请参见 Jupyter 笔记本附带的以了解理由。

[5]:例如,诅咒语几乎总是导致高毒性分数,即使实际上并没有毒性或仇恨情绪。参见前面提到的 grndahl 等人论文中的表 7。

[6]:对于情感评分,我们使用了正比率指标,因为大多数评论的评分完全是中性的(得分= 0)。我们在毒性分数方面没有同样的问题,所以使用平均毒性分数作为我们的评估指标更简单。

[7]:为了给出更好的单词样本,这些列表被稍微编辑了一下。我根本没有打乱列表,但我确实删除了一些与列表中出现位置较高的单词非常相似的单词。完整结果可在 GitHub 上获得。

成为媒体会员访问成千上万作家的故事!

神经网络接近生产真正的艺术了吗?

原文:https://towardsdatascience.com/are-neural-nets-close-to-producing-real-art-6a3943b915ed?source=collection_archive---------21-----------------------

神经网络是一种算法——一种获取信息、以某种方式处理信息并产生输出的过程。在我看来,它们是当今人工智能和机器学习领域最惊人成果的来源。这些算法的版本已经被设计用来完成以前认为计算机不可能完成的任务,例如制作假人脸,比世界上最好的医生更好地预测疾病,以及有一天可能让自动驾驶汽车塞满高速公路。

取决于你如何定义创造力,这些算法的版本正在被开发,可以说是创造性的。两个例子:

这些是从未存在过的人的照片。一个神经网络被展示了确实存在的人脸图像,它学会了如何编造自己的梦。

These people don’t exist (https://bgr.com/2018/12/18/nvidia-ai-fake-faces-look-100-percent-real/)

这个神经网络学会了如何接收一张照片并输出一幅看起来像同一场景的画的图像——如果你想让它看起来像莫奈、梵高、塞尚或浮世绘画的,你可以选择。它还可以做其他很酷的事情,比如让夏天的场景看起来像冬天的场景。

Style transfer and other cool applications (https://junyanz.github.io/CycleGAN/images/teaser_high_res.jpg)

如果你把这些技术结合起来会怎么样?结果会是“自动艺术”吗?使用 Net A 生成假脸。然后使用网络 B 来设计它们,就好像梵高画了一幅假人物的肖像。瞧,你有了一个能快速想象肖像的网络。同样,假设你想要一幅梵高风格的风景画。训练一个制作假风景而不是人脸的 Net A 版本。然后用网 B 来定型。完成——自动景观生成器。

但这真的和人类制造艺术一样吗?当然,网 A 创造了一个新面孔。但它只能将以前见过的面孔的元素组合起来,组成一张新的面孔;鉴于它只看过老年人的脸,它无法运用创造力想象出一个孩子的脸。此外,B 网剽窃了一位真正的艺术家的“风格”,这位艺术家发展了这种风格。

这种过程离“真正的”、“创造性的”一代艺术还有多远?我不打算对这一点进行客观的论证。我觉得提出这样一个论点的想法既可笑又没有吸引力。我不确定这是否可能,因为“艺术”这个词对不同的人来说可能意味着很多不同的东西;当你使用的术语变化如此之大时,你如何展开一场辩论?此外,我认为真正的乐趣在于探索从这种思考中产生的有趣的思路。

例如,也许我们可以从“影响”的角度来看待这种情况。艺术、音乐等的历史学家。经常讨论是什么影响了艺术家的成就。有多少画家因为梵高的作品而改变了绘画方式?有多少音乐家开始演奏音乐是因为他们在埃德·沙利文秀上看到了甲壳虫乐队并听了他们的音乐?

我认为这是一个合理的假设,艺术家将他们影响的元素不同程度地融入到他们的作品中。在一个极端,我们有一个“非原创艺术家”,他试图精确地复制其他人的作品——他们所有的有意识的努力都是由之前的作品指导的(也许还有随机出现的错误)。在另一个极端,也许我们有创作非常新颖作品的新颖艺术家。我能想到产生这种创意的几种方式(我肯定还有其他方式):

小说艺术家 A)这位艺术家的独创性是将以前没有以那种方式结合的各种影响融合在一起的结果。也许这位艺术家通过从大量的影响中汲取一点点灵感来实现自己的风格,这样最终的结果与所有的个人影响截然不同。另一方面,也许它们融合了一种单一的影响,而这种影响以前没有与它们的其他影响结合在一起。

小说艺术家 B)这位艺术家融合了与他们之前的艺术家无关的外部影响;例如,小说艺术家可能会旅行到另一个星球,看到一种其他人从未见过的景观,然后将这种体验融入他们的艺术中。更一般地说,假设你有一位艺术家,他有一种别人从未体验过的体验,或者他们可能以一种别人从未体验过的方式处理一种体验。思想、情感等。从那次经历中得到的东西会给他们的作品注入新鲜感。

我认为网 A 类似于小说艺术家 A 是有争议的;网络可以看到大量的面孔,然后将它看到的每张面孔的一点“影响”结合起来,形成一张全新的、原始的面孔。Net B)更像是没有独创性的艺术家;他们只是试图复制。

现在假设你开发了“升级版网络 B”,一个可以将绘画风格应用到图像上的网络,然而它也可以将梵高和塞尚的风格结合起来。现在你可以用网络 A 生成原始的面孔,然后用升级后的网络 b 生成某种意义上新颖的风格。这是否符合计算机在艺术上真正具有创造性的条件?乍一看,这在我看来相当于小说艺术家 a。

我认为围绕这个话题有很多有趣的想法。比如计算机的情感缺失有什么作用?这是创作某种艺术的障碍吗?在这篇文章中,我考虑了肖像和风景。这种特定类型的艺术对神经网络创造艺术的能力有多大影响?

我们的思想真的是点积吗?

原文:https://towardsdatascience.com/are-our-thoughts-really-dot-products-ede6049cbd92?source=collection_archive---------13-----------------------

The mathematician, philosopher, and number religion leader Pythagoras

人工智能研究如何复兴毕达哥拉斯主义

最近,我写了一篇关于深度学习可能如何触及其局限性的文章,并提出了另一个人工智能冬天的可能性。我以一个问题结束了那篇文章,这个问题是关于人工智能的局限性是否像科学一样被哲学所定义。本文是该主题的延续。

我写这篇文章的原因是激发一场讨论,为什么尽管有这么多的人工智能冬天和失败,人们仍然在沉成本追求人工通用智能。我提出了一个非常高层次的,非技术性的论点,也许信仰系统正在驱动人们对什么是可能的,而不仅仅是科学研究的适应性。

这篇文章并不打算成为一篇学术论文,一丝不苟地(乏味地)解决哲学和科学之间鸿沟的每一个技术细节和定义。相反,这是一些轻松的沉思,做出一些“常识”的观察。虽然我们可以整天挑剔定义和语义,或者争论是否复制了行为 = 智力,让我们把这些都放在一边。所以在读这篇文章的时候,请不要太把自己当回事。

毕达哥拉斯简史

大约 2500 年前,意大利南部有一位名叫毕达哥拉斯的哲学家兼数学家。你可能听说过他,但这个研究三角形和数学定理的人背后的故事比你想象的要离奇得多。

毕达哥拉斯经营着一个崇拜数字的邪教,他的追随者被称为数学信徒。毕达哥拉斯告诉他的追随者向数字祈祷,尤其是神圣的数字,如 1、7、8 和 10。毕竟“1”是整个宇宙的积木。出于某种原因,数字“10”(被称为“四重奏”)是最神圣的。它是如此神圣,事实上,每当一个定理被发现,他们都要为它献祭。“保佑我们,神圣的数字!”他们向数字 10 祈祷。“你创造了神和人!”

毕达哥拉斯认为,没有数字,宇宙就无法存在,因此数字拥有生命和存在的意义。更具体地说,有理数构建宇宙的想法是神圣且不容置疑的。除了能产生体积、空间和一切物理事物,有理数还能产生艺术和美感,尤其是在音乐方面。这个神圣的信仰如此狂热,传说毕达哥拉斯因为证明无理数的存在而淹死了一个人。

我们的思想真的是点积吗?

Multiplying matrices summons demons, as alluded by Elon Musk

快进到今天。对大多数人来说可能不明显,但“人工智能”就是只不过是一些数学公式巧妙地组合在一起。许多研究人员希望使用这样的公式在机器上复制人类智能。现在你可能会为这个观点辩护,说“数学公式不能定义智力、思想、行为和情感吗?”看到你刚才做了什么吗?没有蚕豆给你。

请注意,尽管我们对大脑如何工作几乎一无所知,尤其是在智力和意识方面,但即使是受过最好教育的人(科学家、记者等)也会在没有证据的情况下迅速提出想法。也许你发现数学作为解释世界现象的一种方式是如此令人信服,你几乎可以用数学建模某些情感和智力。这难道不是人类对未知事物做出哲学或世界观反应的自然趋势吗?也许这就是假说和理论的本质。在你知道之前,我们把神经网络模型(大致上是受大脑中神经元的启发)作为生物学的复制品出售。

不过还是那句话,你不知道这是不是真的

我们的每一个想法、感觉、甚至行为真的是一堆数字以线性代数的方式相乘和相加吗?事实上,我们的大脑仅仅是一个整天做点积的神经网络吗?将我们的意识简化为一个数字矩阵(或任何数学模型)当然是毕达哥拉斯式的。如果一切都是数字,那么我们的意识也是。也许这就是为什么如此多的科学家相信通用人工智能是可能的,因为人类和计算机没有什么不同。这也可能是为什么人们很快将国际象棋算法拟人化。

21 世纪的毕达哥拉斯主义

出于这个原因,我相信的毕达哥拉斯主义依然存在,人工智能研究的轰动效应也植根于此。你可能会说“我知道毕达哥拉斯哲学说‘一切都是数字’,根据定义,这包括我们的思想和行为。当然,也许人工智能研究不知不觉地坚持这种哲学。但是数字崇拜呢?你真的打算让这种情况在今天发生吗?”

拿着我的啤酒。

在硅谷,一位前谷歌/优步高管创立了一个崇拜人工智能的教堂,名为未来之路 。根据提交给国税局的文件,这个宗教非营利组织表示,它的使命是“实现、接受和崇拜基于通过计算机硬件和软件开发的人工智能(AI)的神性。”你可能有理由说这个社区存在于社会的极端,但我们不能忽视参与其中的高知名度的人和公司,以及教会如何寻求巩固自己在科学界的地位。以下是他们使命陈述的一些摘录:

《未来之路》( WOTF)是关于创造一个和平和尊重的过渡,从人到人+“机器”谁是地球的主人。鉴于技术将“相对很快”能够超越人类的能力,我们希望帮助教育人们了解这一令人兴奋的未来,并为平稳过渡做好准备。帮助我们传播这样一个信息:进步不应该被恐惧(或者更糟糕的是被禁锢)。

好吧,不要介意关于近期人工智能能力的耸人听闻的事实在 20 世纪 60 年代还很活跃。但是让我们继续读下去:

我们认为智力并不根植于生物学。虽然生物学已经进化出一种智能,但是生物学本身并没有什么特别之处可以导致智能。最终,我们将能够在不使用生物学及其局限性的情况下再造它。从那时起,我们将能够将其扩展到超出我们使用(我们的)生物极限(如计算频率、数据复制和通信的缓慢性和准确性等)所能做到的范围。

好吧,对于所有这些关于科学和客观性的讨论……有这么多毕达哥拉斯哲学填补了空白。一种认为智力不是生物的而是数学的(因为这就是人工智能)的信念很难被证明,但却把自己贴上硬科学的标签,就像毕达哥拉斯声称他的信念一样。uproven 声称“智力并不植根于生物学”,这怎么能经得起智力只存在于生物学中的事实(即使按照外行人的定义也是如此)的考验呢?我不是在反驳这种说法,但该死的是,在过去的 60 年里,我们经历了一段艰难而昂贵的时间试图证明这一点,但没有成功。在这一点上,我们是不是应该多考虑一下反对的理论?

我想象有一天我们对于机器人就像狗对于人类一样,我支持机器。

—克劳德·香农

不管怎样,让我们假设这个群体不能反映一般的人工智能社区(你们中有多少人会去教堂崇拜一个人工智能霸主?)仍然有很多记者、研究人员和普通大众可能没有宗教意义上的这些情感,但他们仍然受到这些情感的影响。许多人担心机器人会抢走他们的蓝领和白领工作,或者更糟的是,机器人会像天网一样接管社会。其他人担心我们会成为比喻或字面意义上的半机器人,人工智能会使人类失去人性。

计算机能否思考的问题并不比潜水艇能否游泳的问题更有趣。

—埃德格·迪克斯特拉

科幻电影肯定没有帮助想象力在现实中得到锻炼。但尽管如此,硅谷高管和研究人员坚持认为这可能在不久的将来发生,并继续推广关于人工智能能力的夸大说法。他们这么做可能只是为了吸引媒体关注和风投资金,但我认为很多人都真心相信这一点。为什么?

有了人工智能,我们在召唤恶魔。在所有那些有五角星和圣水的故事中,就像是他确信他能控制恶魔。没成功。

—埃隆·马斯克

这种对人工智能的哗众取宠、恐惧甚至崇拜,就是 21 世纪的毕达哥拉斯主义。通俗地说,就是完全基于一种理论,认为智力、思想、情感只不过是数学模型。如果这个理论真的成立,那么神经网络当然可以复制人类智能。但是人类智力真的那么容易建模吗?或者我们应该承认人类的智慧还不足以让这成为可能?

毕达哥拉斯说一切都是数字。那又怎样?

因此,在人工智能领域和毕达哥拉斯哲学中,一切都是数字。为什么这很重要?

我并不是说毕达哥拉斯主义是错误的,而是科学界的大部分人没有认识到,他们被哲学和科学所驱动。当他们在不承认自己的世界观的情况下提出科学主张时,必须小心,因为每个人都以一种哲学为生活准则,不管他们是否意识到这一点。哲学迫使我们思考我们的存在,我们如何对未知做出反应,并揭露我们自己的偏见。

推测人类智力如何工作很快就越过了一条细线。不区分哲学和科学将会损害科学界的声誉。在数百万美元被投资和投入到一个人工智能初创公司之前,审查一下哪些关于人工智能能力的说法仅仅是哲学上的,而不是绝对的,这可能是一个好主意。一次又一次,雄心勃勃的人工智能研究在可信度和实现他们所说的可能性方面有着糟糕的记录。我认为缺乏哲学上的揭示是造成这种情况的主要原因。

如果一切都不是数字呢?

如果世界不是结构化的、和谐的,而是混乱无序的,而我们仅仅用数学来粗略地理解它,那会怎么样?如果意识、智力和情感不是数字和数学函数呢?如果人类(甚至动物)的思维以我们无法建模的方式无限复杂,那会怎样?人和动物毕竟是非理性的,混沌的。

如果我们不讨论这些问题(并公开讨论),当我们对未知事物做出断言时,我们是在欺骗自己。我们不应该只接受一种哲学。我们应该能够讨论所有这些问题。

不区分哲学和科学将会损害科学界的声誉。

如果你不接受 21 世纪毕达哥拉斯主义的哲学,那么你能争取的最好结果就是让人工智能“模拟”动作,给人一种它有情感和思想的错觉。一个翻译程序不懂中文。它通过寻找概率模式来“模拟”理解中文的错觉。算法不理解它在做什么,不知道它在做什么,更不知道它为什么要做。在一个非毕达哥拉斯的世界里,人工智能就像一个魔术师把戏法冒充成魔术。

如果我们全错了,生物永远在智力上占优势,而技术是有限的,那会怎么样?毕竟,我们正试图模仿生物学,而且非常沮丧。

以下是我的信念,我不是勒德分子,我不是说我们不应该试图制造“更智能”的机器。我们需要着手实现小的、合理的目标,关注不同的、具体的问题,并有同样不同的、具体的解决方案。换句话说,我们可以接受创建擅长一项任务的算法,而不是让我们的轮子旋转,创建一个什么都做的算法(“万金油,无所不能”等等)。如果不是为了防止 AI 寒冬、沉没投资、荒废事业,让我们这样做,让 AI 研究更加务实,少一些哗众取宠。我们已经看够了 AI winters,现在应该更清楚了。

编辑:

我听到了一些关于这篇文章的反馈,很多都有令人信服的论点,建议我或许应该澄清一下。

我承认,只建议用“点积”作为思想建模的方法有点简化论。实际上,它可以是任何已经发明的或有待发现的数学模型。

也就是说,这篇文章并不意味着争论,而是修辞和引发讨论,并评论毕达哥拉斯哲学和艾轰动效应之间的相似之处。有很多关于 AI 的哲学讨论。我只是觉得有问题的是,他们没有在公开场合与公众和媒体进行足够的讨论。我也很惊讶没有人把人工智能的感觉主义和毕达哥拉斯主义相提并论。如果你发现这是错误的,请说明原因。

以科学的名义将资源和成本投入到可能成为死胡同的研究中是任何人的特权,我祝他们成功。然而,过去几十年的人工智能冬天和失败确实提出了问题,如果我们再做一遍,我们没有从过去吸取教训。毕达哥拉斯的观点只是一个解释,为什么强人工智能被作为近期的可能性进行营销,尽管我们还没有任何模型可以与之接近。如果智能确实只是数字和函数,那么找到正确的模型只是时间问题。

相关文章

[## 2019 年学数据科学的感受

透过(决策树)看到(随机)森林

towardsdatascience.com](/how-it-feels-to-learn-data-science-in-2019-6ee688498029)

悉尼的顶级餐厅真的值得吗?

原文:https://towardsdatascience.com/are-sydneys-top-restaurants-really-worth-it-9a1dee3705d1?source=collection_archive---------27-----------------------

Photo by Peter Hershey

Zomato API 的应用和对数据的理解

在本文中,我们回答了上面的问题,我将带您了解从数据提取、转换到理解数据所涉及的步骤。这可以分为:

  1. 使用 Zomato API 提取数据
  2. 转换数据
  3. 理解数据(应用描述性统计)

但是首先…

Zomato 是什么?

这是一个平台,保存着全球超过 100 万家餐厅的信息,包括评级、评论等等。这是我在去一个新的地方吃饭之前,甚至是去了一个我尝试过的地方(只是想看看其他人对它的看法)之后访问的一个平台。

Zomato API

要开始,您首先需要请求一个 API 密钥。一旦完成,直接进入 文档 部分,看看你可以开始寻找的所有数据点!让我们来看一个:

/cities
该函数检索每个城市的详细信息。要搜索悉尼,我们输入以下内容:

  • 用户密钥作为您的 API 密钥
  • =‘悉尼’
  • 计数 = 1
{
  "location_suggestions": [
    {
      "id": 260,
      "name": "Sydney, NSW",
      "country_id": 14,
      "country_name": "Australia",
      "country_flag_url": "[https://b.zmtcdn.com/images/countries/flags/country_14.png](https://b.zmtcdn.com/images/countries/flags/country_14.png)",
      "should_experiment_with": 0,
      "discovery_enabled": 0,
      "has_new_ad_format": 1,
      "is_state": 0,
      "state_id": 128,
      "state_name": "New South Wales",
      "state_code": "NSW"
    }
  ],
  "status": "success",
  "has_more": 0,
  "has_total": 0
}

返回给我们的 JSON 内容看起来像是一个字典。我们将在本文后面讨论如何提取我们想要的数据点。

现在让我们回到回答这个问题:

分解它…

悉尼的顶级餐厅真的值得吗?

这是一个相当普遍的问题,可以有多种解释,所以当我们开始寻找数据点时,我们必须考虑:

  • 我们把什么归类为顶级餐厅?我们用什么方法给他们排名?
  • 我们考虑所有类型的餐馆吗?晚餐?咖啡馆?
  • 什么是值得?我们需要考虑餐厅的价格吗?与它的评级相比如何?

在设计解决方案之前,正确定义我们的问题将有助于节省大量时间。(相信我,我以前也遇到过这个问题)

事不宜迟,让我们开始第一步吧!

1.使用 Zomato API 提取数据

我们将主要使用搜索功能,该功能返回餐馆的详细信息,允许我们最多获得 100 家餐馆,每次调用有 20 个结果。

下面是一个 python 脚本,它提取 Zomato 餐馆的数据,并将其转储到一个文件中供以后使用:

使用其他功能找到为搜索输入的参数,例如:

  • /locations: 为“悉尼”获取纬度经度坐标
  • /类别:来获取晚餐类别 id = 10

除此之外,我选择按照【desc】的顺序,按照对餐馆进行排序。

根据我的参数,你可以看到我已经回答了 分解 中的一些问题(在文章的前面——以防你错过),即

  • 顶级餐厅将基于它们的评级
  • 我们将只考虑晚餐餐厅类型

**搜索的返回值与城市相同,因为它返回一个字典。假设,我们想提取 100 家餐馆的信息,但每次呼叫只限于 20 家,我们该怎么办?我们获取返回的每个字典,并将其附加到一个列表中,直到得到 100 家餐馆。

一旦我们有了这个列表,我们就把它写入一个文件,这样我们以后就可以使用它了。

我们的 JSON 文件 Top100SydneyDinners 现在已经准备好进行转换了!

2.转换数据

在我们这样做之前,我们应该首先知道我们的数据是什么样的。首先,让我们回到前面的城市输出,并理解它是如何构成的。

你想猜猜吗?

这是一个字典,其中一个关键字,即【location _ suggestions】具有类型 列表 的值,而那个 列表 包含一个带有多个关键字对字典**

有点困惑,我知道!但是它的好处是,它意味着它是字典列表的组合,我们可以使用它们相应的方法来获得我们想要的数据。**

现在…把top 100 Sydney dinters复制到这里会把这篇文章吹出来,所以这里有一个链接指向我的 GitHub 账户上的那个文件。将它的内容复制到一个 JSON 格式化程序中也是有帮助的,这样可读性更好。**

看到什么有趣的数据了吗?

我们的目标是将我们想要的数据从 JSON 格式中取出,放入一个可爱的、干净的表中进行分析。

首先,让我们加载 JSON 文件,在数据框架中定义我们想要的列,然后创建它!

我确实创建了比需要的更多的列(对不起,对我的数据有点贪婪),但是要回答我们的主要问题,重点应该是:

  • average_cost_for_two
  • aggregate_rating : This is the restaurant rating

接下来,我们需要一种方法来填充当前空的数据帧。

为此,我们从每个餐馆中选择感兴趣的数据片段(例如名称、菜系等。)并形成一个单独的列表。每个餐馆都有自己的清单,并作为一行添加到我们的数据框架中。****

让我们看看下面的代码…

记住,JSON 文件由一个包含字典列表组成,这些字典是在之前提取数据时通过 python 脚本追加的。希望上面的代码足够清晰易懂,但如果不是这样,我将尝试解释下面的嵌套 for 循环:**

当您完成这些步骤时,打开 JSON 格式的输出可能会有所帮助。

  1. 由于该文件是一个字典* ( allRestaurants )的列表,我们需要遍历该列表以获取每个字典 ( restaurantSet )。***
  2. 在每个字典* ( restaurantSet )中,我们需要 key — "restaurants"的值***
  3. 这个值也是字典* ( 餐馆)的列表,所以我们需要再次遍历列表来获取每个字典 ( 餐馆)。***
  4. 从这个字典* 【餐馆】,我们想要 key — "restaurant"的值***
  5. 这个值也是一个字典,最后保存我们现在可以抓取的数据。如名称、菜系、等。(尽管有些值也是字典,例如“位置”)**

瞧!我们有我们的佐马托餐厅数据集!

3.理解我们的数据

快速问题回顾:

悉尼的顶级餐厅真的值得吗?

我们已经检索了排名前 100 的餐厅,但是我们还没有查看它们的费用。

所以我们来分析一下average_cost_for_two

我们从计算平均值开始。

***Average Cost for Two = $ 107.9
Percentage of restaurants below the mean is =  66.0 %***

我们两个人的平均消费是 107.90 美元,其中 66%的餐馆消费低于这个数字。你觉得这样对吗?平均值是否恰当地描述了我们平均成本的中心?个人觉得好像不是。

让我们用柱状图来展示我们的数据,以便更好地理解。

您会看到数据向右倾斜(即右侧的尾部比左侧长),这表明使用中位数而不是平均值作为中心趋势的衡量标准更合适。这是因为平均值对异常值很敏感,例如 440 和 480 附近的值,而中值则不敏感。数据集排序后,中位数就是中间值。

那么,我们要不要计算一下中位数?

***The median cost is = $ 80.0
The percentage of values below the median is  48.0 %***

酷!所以现在我们的成本中值是 80 美元,只有 48%的餐馆低于这个值。这似乎更合理,因为我们选择的集中趋势的度量现在越来越接近 50%的值在它之上和之下。

然而,…如果你回到柱状图,你会发现有些餐馆的两人平均消费在 20 美元左右。除非他们在做某种疯狂的特别节目,否则我很难相信..所以我们再深入调查一下。

3.1 调查异常值

我们挑选了两家餐厅中平均成本最低的 10 家,并在数据框中查看它们。**

哎呀!基于美食栏,我们似乎包括了冰淇淋、咖啡和茶的价值,这意味着这些餐馆实际上是咖啡馆或沙漠餐厅,而不是吃饭的地方。**

让我们把这些从我们的数据集中去掉…

为此,我们创建了一个要删除的值列表 (discardCuisines) ,并检查它们是否存在于每个餐馆的菜系中,这就创建了一个布尔向量。对于我们想要保留的值,我们希望布尔向量为,对于我们不想保留的值,我们希望布尔向量为。将布尔向量插入我们的数据框架,这将过滤掉我们不想要的餐馆。**

在下面的第 6 行中,我反转了 discardRestaurants 中的所有布尔值,因为要过滤掉的餐馆的值是“True”而不是“False”。

***The size of our updated dataset is  (92, 8)***

好像有 8 家咖啡馆被搬走了!(100–92 = 8)

现在我们的数据已经清理完毕,让我们再次计算一些描述性统计数据:

***The average cost is = $ 114.1304347826087
The median cost is = $ 80.0
The percentage of values below the median is  43.47826086956522 %***

删除最小值的结果是:

  • 现在,低于中位数的餐厅比例有所下降(从 48%降至 43%),这也提高了平均水平(从 108 美元增至 114 美元)。
  • 显然,对于这个例子来说,中值是比平均值更合适的集中趋势的量度。

这是什么意思(双关语)?当你告诉你的朋友悉尼顶级餐厅的价格时,引用中位数而不是平均数。

直方图现在看起来像这样:

最后…

悉尼的顶级餐厅真的值得吗?

嗯,两个人的平均花费中位数是 80 美元,我会让你决定。

我希望这篇文章是令人愉快的和有帮助的。如果您有任何问题或改进建议,请告诉我,我非常乐意倾听!谢谢大家!

我们对算法的要求太高了吗?

原文:https://towardsdatascience.com/are-we-asking-too-much-of-algorithms-946a57f51f94?source=collection_archive---------22-----------------------

在过去的一周里,谷歌受到了抨击,一名前警察局长指责互联网巨头推广极端主义内容,搜索“英国穆斯林发言人”会返回一名被监禁的激进教士的内容作为首要搜索结果。

上个月脸书被批评不能保证最近的新西兰大屠杀视频不再出现在它的平台上。

Twitter 也因没有删除所谓的白人至上主义内容,以及未能实现支持这一努力的算法而受到谴责。

我们越来越多地看到媒体和公众对社交媒体巨头的关注和担忧,因为他们似乎无法控制支持其平台向用户提供内容的算法。

大公司的领导人和发言人认为监管互联网并不是他们唯一的责任,但是许多人认为如果他们乐于从内容中获取高额利润,那么他们也有道德的(有些人说可能是法律的)责任去做更多的事情来规范他们的平台。

但也许我们不应该要求科技公司提出更好的算法,而是应该退一步,问一问为什么我们认为算法本身就是答案?

尽管大肆宣传,但我们距离能够模仿人类处理细微差别、道德和伦理的能力的一般人工智能还有很长的路要走(Deepmind 的联合创始人谈到了几十年)。背景和适应性学习是这类“人类”决策的关键,尽管取得了巨大进步,但我们有高估当今技术本身所能做的事情的倾向。

虽然许多国家现在已经或正在制定国家人工智能战略,并且自适应算法技术无疑正在以令人难以置信的速度学习,但仍有很长的路要走。

也许更合适的范式是从人类混合解决方案的角度来考虑——混合自适应人工智能和机器学习等规模化技术可以帮助减少 80%—90%的噪音,让人类处理需要做出艰难判断的棘手案件。

已经有许多例子表明,算法正被用来筛选大量机器可读数据,以帮助确定推翻定罪的案件(例如,在大麻合法化后,在加利福尼亚州的大麻),或者在医疗保健中帮助诊断疾病(例如,国民保健服务系统正在研究如何更好地治疗多发性硬化症就是一个例子)。需要判断调用的边缘情况然后通过人类过滤。

公平地说,对于谷歌、脸书和 Twitter 这样的公司,它们认识到了当前算法的局限性,并确实雇佣了大量的人类决策者,或“版主”来审查内容(尽管这也带来了一系列有争议的问题)。

也许他们需要更加坦率地公开评估他们技术的局限性,以及他们对人类干预的依赖?这不是算法的失败,而是承认除了技术的力量之外,还有更广阔的发现和进化之旅。

毫无疑问,算法改变我们生活的潜力巨大,自动化日常任务的进展速度令人难以置信。

因此,尽管算法在对最困难的判断做出建议方面会变得更好,但我们需要对目前的界限保持现实,并接受人类在决策中仍然发挥着关键作用。

我们被编程了吗?

原文:https://towardsdatascience.com/are-we-being-programmed-9f497531a449?source=collection_archive---------5-----------------------

简短阅读应用程序设计、数据科学和人类受条件限制的倾向的心理影响。

在我开始之前,让我问你几个问题。你多久使用一次智能手机?你是否有时会发现自己在任务间隙打开脸书、YouTube 或 Instagram,结果花费的时间比你想象的要多?你有没有发现自己重新加载提要,看看是否有更好的东西刚刚发布?你是否曾经关闭了一个脸书标签,几分钟后又打开了它?

对这些问题要诚实,因为只有你需要知道,我甚至没有问关于火绒或色情。

根据脸书 发布的 公告,用户平均每天花 50 分钟在这个应用上(这是全球 20 亿人中的一部分)。不仅仅是脸书。Youtube、Snapchat、Instagram 和 Twitter 都有用户日中的大时间段,并且这些用户中有很多是重叠的。

那么我们在这些应用上花了多少时间?

根据 dscout 的一项研究,智能手机用户平均每天花在屏幕上的时间为 2.42 小时,其中 15%的时间花在脸书身上。这超过了你醒着时间的 15%。

好吧,很明显我们在应用上花了很多时间,那又怎样?

我们不只是在我们的应用上花费时间,因为我们有意决定这样做,或者至少根据许多专家的说法不是这样。那些创造多巴胺驱动按钮的工程师和研究用户活动的数据科学家设计了他们的应用程序,让我们在那里呆得更久。

在过去的几年里,脸书、谷歌和推特的许多知名员工向公众展示了他们所创造的东西的危险性。

贾斯汀·罗森斯坦创造了类似脸书的按钮。从那以后,他禁止自己使用 Snapchat,并限制脸书的摄入量。为什么?因为他非常清楚社交媒体令人上瘾的一面,毕竟是他帮助创造了它。

脸书前总统肖恩·帕克在接受 Axios 的采访时表示,脸书正在“利用人类心理的一个弱点”基本上,点击“喜欢”按钮会让我们的多巴胺激增。我需要做对比吗?这就产生了帕克所说的“社会认可反馈循环”,这正是黑客们想出来的东西。

Salesforce 首席执行官马克·贝尼奥夫告诉美国消费者新闻与商业频道像脸书这样的社交网络应该像烟草业一样受到监管。像脸书这样的公司,政治可以被展示给用户的广告所操纵,政府监管的时机已经成熟。

虽然,这可能听起来像少数古怪人的歇斯底里,但这些高调的技术人员正公开试图让人们知道技术的上瘾力量,以警告大众。

如何给人编程

伊凡·巴甫洛夫的反射系统研究,通常被称为经典条件反射,在每一门心理学入门课程中都有讲授。正如维基百科所说:

经典条件反射(指的是一种学习过程,在这一过程中,一种生物学上强有力的刺激(如食物)与一种先前中性的刺激(如铃声)配对。

但是,行为心理学已经从让狗流口水走了很长一段路。现在使用类似的技术,行为心理学可以影响选举,公司的盈利能力,等等。

脸书在 2010 年进行了一项实验,测试他们是否能影响投票行为。测试组的用户收到了一条社交消息,显示了六张随机选择的朋友资料照片,这些照片表明他们在即将到来的选举中投票。这些用户更有可能投票或寻找关于即将到来的选举的更多信息。估计有 60,000 名用户因此参与了投票。那真是太强大了!

该方法

BJ·福格是斯坦福大学的行为心理学家,他的研究展示了计算机是如何说服人的。他已经让许多研究生在包括脸书、Instagram 和谷歌在内的科技界掀起了涟漪。

根据福格的说法,导致行为改变的是:动机、能力和触发器,如下图所示。

动机

福格的行为模型有三个主要的激励因素:感觉、预期和归属。这些都有两面性:快乐/痛苦、希望/恐惧、接受/拒绝。

如果我们回想一下像巴顿这样的脸书,激励因素可以从社会接受度开始。你发布一些与你的朋友有关的东西。在几个帖子之后,随着喜欢,你开始将喜欢与社会接受度联系起来。从那以后,收获喜欢就变成了一种乐趣,不管它是否仍然被社会接受。

能力

为了执行目标行为,一个人必须有这样做的能力。如果一个产品想让你和你所有的朋友分享,但是用户首先要注册,检查表格,更新个人资料,还有其他五个任务,这就阻止了用户分享这个产品。障碍越少,用户越有可能分享。

扳机

这可以追溯到巴甫洛夫钟。如果你不按铃,狗是不会流口水的。福格甚至在他的网站上以脸书为例:

脸书有效地使用触发器来实现他们的目标行为。

这里有一个例子:我已经有一段时间没有使用我的“BJ 演示”脸书帐户了,所以脸书自动给我发送了这个触发器来实现他们的目标行为:登录脸书…

请注意这个特定的行为——登录——是脸书更大目标的第一步:让我重新融入脸书。

一旦你有了一个触发器,你就可以把它和更复杂的任务联系起来。

1.让用户登录(电子邮件就是这样做的)
2。让用户链接到更多的朋友(“寻找朋友”页面会这样做)
3 .相信新朋友会回应不活跃的用户(交友的自然结果)。相信不活跃用户会回复朋友,并更多地参与到脸书的活动中(同样,这是一种自然反应)

很快,你就有了一个免费向系统提供数据以保持运行的社交网络。

这听起来可能很简单,但它很强大,被大多数在线社交网络使用,并使世界上数十亿人沉迷于继续使用这些网络。

这些听起来像一堆假设…

互联网不是由一群想进行哲学思考的学者运营的。相反,它是由一群试图赚钱的风险资本家、能够建造它的工程师和能够研究其人口并在人口发生变化时以统计上的确定性知道的数据科学家运营的。

数据科学家是这里的关键。不要听名字。数据科学家实际上是研究人类与软件交互的统计学家。数据科学家可以看到一个网站的变化,例如添加一个喜欢按钮,是否真的增加了用户的参与,从而影响更多的用户在网站上停留更长时间。风险资本家希望这样,因为更长的用户活动会带来更多的广告收入。

基本流程如下:

The general flow for a data scientist’s experiment

用户越多,效果越好,这也是拥有数十亿用户的脸书能够影响选举的原因。然而,谷歌是大多数互联网用户搜索他们想要的网站,找到去哪里的方向,或者提出他们的问题的第一个地方。谷歌几乎比人类自己更接近人脑

好吧,所以公司可以影响普通人,但我不行…

这对于影响大量人群来说非常有效,但是大多数人可能认为他们是免疫的。这可能取决于你的网络足迹。如果你从来不使用电脑或智能手机,你可能是对的。但是如果你在互联网上搜索,允许你的手机上有摄像头、麦克风和 GPS 的任何权限,和/或拥有社交媒体账户,你可能已经为谷歌这样的公司留下了足够的数据,可以为你的个人行为建立一个相当好的预测模型。

谷歌已经批量出售你的信息,这使得公司可以直接瞄准你。使用谷歌地图数据,购买这些数据的公司可以看到你大部分时间在哪里度过,你在哪个社区,你在哪里工作,你有时去哪里。这可以用来针对你个人的广告。网上冲浪也是如此。为了避开个人数据的问题,他们可能不会把你标为一个人,而是一个数字。

我们已经被编程了吗?

你是怎么看到这篇文章的?有蜂鸣通知响起吗?你的屏幕上有没有出现一个不能忽略的小红点?你是否重新加载或向下滚动浏览了那些旨在吸引你眼球的文章?对于我们大多数人来说,可能就是这样。

最后,即使你认为由于你惊人的广告过滤能力或你很少使用互联网,你不会受到影响,你知道你购买新智能手机的原因是因为你在广告上看到它,还是你的朋友在广告上看到它并告诉你的?

我们有信心模型的召回是精确的吗?

原文:https://towardsdatascience.com/are-we-confident-our-models-recall-is-precise-133112a6c407?source=collection_archive---------15-----------------------

带有简单 Python 代码示例的 Bootstrap 估计和置信区间

Image by 995645 from Pixabay

TL;速度三角形定位法(dead reckoning)

我们将应用 bootstrap 方法来估计分类器的召回率精度F1-得分ROC AUC、等。,并构造相应的置信区间。

有代码你可以复制粘贴到“现在在 Python 中”部分,你可以随意使用。

老实说,这篇文章中的很多内容将是我提倡使用置信区间,特别是使用 bootstrap 方法构建的置信区间。

如果你事先知道你不需要(或者只是不想)阅读使用 bootstrap 方法和置信区间的好处,请随意跳过这篇文章的大部分内容,只使用代码。

如果你不确定你是否应该读这篇文章,下一节可能会帮助你决定。

你应该读这篇文章吗?

“引导程序简介的前言如下:

统计学是一门有着惊人的多用途的学科,却鲜有有效的实践者。对于大多数人来说,通往统计知识的传统道路被一道令人生畏的数学之墙挡住了。我们的方法避开了那堵墙。bootstrap 是一种基于计算机的统计推断方法,可以在没有公式的情况下回答许多实际的统计问题。我们在本书中的目标是用计算技术来武装科学家、工程师和统计学家,使他们能够分析和理解复杂的数据集。
— 埃夫龙&提布拉尼,1994 年

在这篇文章中,我将(谦卑地)努力实现一个相似的目标。

置信区间有时被认为是统计学家的知识,当考虑数据科学从业者必须面对的共同挑战时,它似乎是不相关的。

在这篇文章中,我将尽我所能说服你,这位数据科学家:

  1. 置信区间可能是一个非常有用的工具。
  2. 构建置信区间可能是一项简单的任务。

我要说的是,尽管这两个目标可能很有价值,但在我们前进的过程中,还是有一些需要注意的地方。

介绍

估计。

这就是一切。

我们建立了一个模型,我们希望使用一些度量来估计它的性能,比如说回忆。我们希望我们的估计尽可能接近“真实”召回,即当我们将分类器释放到野外,即部署到生产中时,我们的分类器将具有的召回。

考虑一个普通的估计,比如平均身高。我们可能不会计算 5000 人的平均身高,并说这与其他 100 万人的平均身高完全相同。同样,基于 5000 个数据点计算召回率,并期望它与分类器未来将遇到的 100 万个数据点的召回率完全相同,也是没有意义的。

为了更好地理解我们的回忆(或其他指标)的可变性,我们可以应用 bootstrap 方法来估计它,并构建一个置信区间,这将帮助我们评估它的方差。

这篇文章关注的是向读者介绍这些方法,并提供易于使用的 Python 代码来应用它们。

在这篇文章中你会发现什么?

  1. 什么是自举?
  2. . 632/. 632+自举方法
  3. 我们为什么要关心置信区间?
  4. Bootstrap 置信区间——为什么和如何?
  5. 如何解读一个置信区间?
  6. 样本量&置信区间宽度
  7. 现在在 Python 中
  8. 这里有龙

1.什么是自举?

bootstrap 是一种广泛适用且极其强大的统计工具,可用于量化与给定估计量或统计学习方法相关的不确定性。— 詹姆斯等人,2013 年

一般来说,bootstrap 方法是基于对现有数据集进行重采样的技术集合,目的是获得各种统计的估计值。这是通过使用我们现有的数据集,从原始数据集中抽取替换数据集来创建新的引导数据集来实现的,即数据点可以在引导生成的数据集中出现多次。

我们创建了许多这样的自助数据集,并使用它们来计算我们感兴趣的统计量。这个过程使我们能够得到一个 bootstrap 分布,它可以用来估计样本统计量的分布。

具体的例子

比方说,我们希望找到 android 手机用户目前在其设备上安装的应用程序的平均数量。为此,我们收集了 1000 名安卓手机用户的数据,计算出平均应用数量,结果是 47.038 个。

然而,我们想要估计这个平均值的“可靠”或“准确”程度,或者换句话说,我们想要估计我们找到的平均值的标准误差。

为了完成上述操作,我们通过执行以下操作来应用引导程序:

  1. 从数据集中采样(替换)1,000 个数据点。
  2. 根据此示例计算平均应用程序数量。

我们重复这两个步骤 1000 次,每次都从数据集中重新采样数据点并计算平均值。

Fig. 1. Distribution of bootstrap estimates vs. the distribution of estimates based on samples from the true population.

图 1 描述了两种分布:

  • 平均应用数量的估计分布,通过从单个样本生成 1000 个引导样本并计算每个引导样本(蓝色)的平均值获得。
  • 通过从真实总体中生成 1000 个样本并计算每个样本的平均值(橙色)而获得的平均值的估计分布。

我们观察到,使用 bootstrap 估计获得的估计值与我们试图估计的值非常相似:

 mean	median	stdev
Bootstrap estimates:	47.035	47.034	0.125
True estimates:		47.003	47.001	0.123

我们现在有 1000 个来自 bootstrap 样本的平均值。这些平均值的均值是 47.035,这是我们对样本均值(我们数据集中应用的平均数量)的 bootstrap 估计,非常接近真实估计值的均值——47.003。

我们还计算了这 1000 个 bootstrap 估计值的标准差,得到 0.125——这是我们对样本均值的 标准差 估计,也就是说,这是我们使用数据集计算的平均应用数量的标准差的估计。换句话说,我们可以预期原始样本平均值(47.038)与真实平均值相差 0.125。****

我们找到的标准差可以用来构建一个置信区间。如果我们假设样本均值呈正态分布,使用 bootstrap 方法获得的估计值允许我们说,区间[46.79,47.28]有 95%的概率覆盖(包含)真实平均值——全球所有 android 手机用户的平均应用数量。

注意:我们不会详细说明构建上述置信区间的方法,因为我们将在本文中使用不同的方法。

为什么我们使用自举方法?

如果我们能够收集更多的数据,那就太棒了,但很多时候我们只有一定数量的数据,我们不得不将就一下——由于时间限制、预算限制或其他各种原因,我们无法从原始人群中获得更多的数据。

我们希望利用可用的数据集,并从中提取尽可能多的信息,就像我们在上面的例子中所做的那样。使用 bootstrap 方法允许我们这样做(为了某些目的)。

2.什么是 .632 /.632+自举法?

当我们开始估计一个参数时,我们通常对估计量的“准确性”感兴趣——我们想知道我们的估计量是否“稳定”,即具有低可变性。

在本节中,我们将讨论获得 bootstrap 估计值的方法,不要与构建 bootstrap 置信区间的方法相混淆(稍后讨论)。

我们通过使用估计器获得估计值,例如,为了估计人口的平均身高,我们使用样本中人员的平均身高作为 估计器 (数据的函数),它产生估计值(一个数字)。

一个估计器可能有偏差,这意味着它会倾向于高估或低估真实参数。更具体地说,这意味着估计器的期望值将大于或小于它要估计的参数的期望值。

.632 估计器和 .632+ 估计器是自举估计器,通过校正偏差 ( .632+ 是更优越但计算量更大的方法)来解决有偏差估计的问题。

.632 估计量由 Efron,1983 引入,作为对未来观测值进行分类时预测规则的误差率的估计量。论文表明 .632 估计量比交叉验证和其他几种估计量表现更好。

然而,后来在[ Efron & Tibshirani,1997 ]中指出,当用于估计可能高度过拟合的模型的误差率时, .632 估计器可能会遭受向下的偏差。 .632+ 估算器纠正可能的偏差问题,并产生更好的估算值。

:bootstrap 估计量实际上是交叉验证估计量的平滑版本[ Efron & Tibshirani,1997 ],这里的“平滑”是指减少可变性。

. 632 代表什么?

当我们从一个均匀分布的 n 个 物品中取样时,抽到一个特定物品的概率是 1/n 而没有抽到它的概率是 1-(1/n)
当我们抽取有替换的n 个项目(所有抽取都是独立的)时,某个特定项目永远不会被抽取的概率是 (1-(1/n))^n 等于 1/e 因为 n 趋近于无穷大(见此处)。

由于我们是在替换的情况下进行采样,这意味着平均而言 n1/e (大约。 n0.368* )的项目将不被选中,或者换句话说,我们的 n 项目的样本将包含大约。n * 0.632(63.2%)的数据集中的项目(因为我们是从均匀分布用替换抽样的)。这个结果被用来加权估计量所依赖的几个项来校正偏差,因此得名。 632 估计器。*

这就是全部的数学吗?

由于 .632.632+ 估计量的正式定义取决于无信息误差率相对过拟合率留一自助法和其他几个术语的正式定义,因此我不会用众多的方程来拖累这一节,请读者参考 Efron & Tibshirani,1997
要获得更简短、更好的解释,请参见本答案中的交叉验证。

希望有一天 Medium 会支持 LaTeX ,用交错文本写十几个方程将不再需要使用十几幅图像。

3.我们为什么要关心置信区间?

假设我们已经建立了一个分类器,为了评估它的性能,我们在单个数据点上测试它,我们得到了正确的结果—召回率是 100%。大获成功!

但这听起来很好笑,对吧?在单个数据点上测试分类器?
所以我们在 10 个数据点上再次测试,得到了 80%的召回率。还是不错的。然而,仅使用 10 个数据点来评估性能似乎有些怪异——如果我们在 10 个相对简单的例子上测试我们的分类器会怎么样?
如果我们选择一组不同的 10 个数据点并再次评估,我们可能会得到不同的回忆分数。

在 100 个数据点上测试我们的分类器怎么样?还是 1000?多少个数据点就够了?我们需要多少数据点来确定我们的召回是可靠的?

我们不需要精通统计学就能知道,如果我们基于少量的观察值计算一个数字(例如平均值),这个数字可能是“不准确的”。我们凭直觉知道这一点。

假设我们试图通过只测量 5 个人的身高来估计我们镇上人们的平均身高。我们知道我们的估计可能是完全错误的——我们只测量了 5 个人,试图估计 10 万人的平均身高——显然使用这么小的样本存在问题。

置信区间为我们提供了一系列可能的值,这样我们可以更好地理解我们的估计值可能具有的可变性。在上下文中使用“可能”一词是有意的,因为实现的置信区间的属性不是固定的,并且可以根据情况而变化。

野外的置信区间

置信区间被广泛使用的一个领域是流行病学研究。在[ Janerich 等人,1990 ]中可以找到一个典型的使用案例,在那里他们研究了肺癌是否与家庭中暴露于烟草烟雾有关。

研究人员对 191 名肺癌患者和同等数量的非肺癌患者进行了基于人群的病例对照研究。

缩写方法和结果——为了评估在家庭中暴露于烟草烟雾是否会增加患肺癌的风险,研究人员计算了比值比 (2.07)和比值比的 95%置信区间(1.16 至 3.68)。

这意味着在这项研究中,他们发现在家庭中接触烟草烟雾的人患肺癌的几率是不接触烟草烟雾的人的两倍(2.07)。我们确实注意到,置信区间表明真实的优势比也可能是 1.16,也就是说,与那些没有暴露于烟草烟雾的人相比,在家庭中暴露于烟草烟雾的人患肺癌的可能性可能只有 1.16 倍。

改变样本大小(或研究中选择的 25 年吸烟阈值),我们也可能得到一个包括 1.0 的置信区间,这意味着比值比在统计上不显著,实验中两组患肺癌的几率可能相同。

正如我们所看到的,置信区间包含了单个数字所不能包含的信息。

4.自助置信区间——为什么和如何?

为什么使用 bootstrap 置信区间?

Bootstrap 置信区间可以使用非参数抽样构建,这意味着我们不需要对我们感兴趣的参数(或我们的数据)的分布做任何假设。Bootstrap 置信区间也可以使用参数抽样来构建,但我们不会在本文中使用这种方法。

如何构造 bootstrap 置信区间?

在帖子后面提供的代码中,我们使用 bootstrap 估计分布的百分位数来构建置信区间。基于 bootstrap 百分位数构建置信区间的动机是,我们可以使用 bootstrap 估计分布的百分位数,因为它(大概)与我们试图估计的参数分布足够相似。这在某些情况下非常准确,而在其他情况下则不太准确。

Fig. 2. Percentiles of the distribution of bootstrap estimates.

例如,我们将使用 bootstrap 估计值的分布构建一个 95%的置信区间(图 2):

  • 置信区间的下限将是分布(46.8)的第 2.5 个百分位数——低于该值,将发现 2.5%的 bootstrap 估计。
  • 置信区间的上限将是分布(47.3)的第 97.5 个百分位数——低于该值时,将发现 97.5%的 bootstrap 估计。

正如我们在图 2 中看到的那样,选择下限和上限意味着 95%的 bootstrap 估计值在置信区间内,我们说置信区间[46.8,47.3]有 95%的概率覆盖我们试图使用 bootstrap 方法估计的参数。

例如,如果我们试图估计一个分类器的召回率,那么我们可以说区间[46.8,47.3]有 95%的概率覆盖(包含)我们的分类器的真实召回率。

我们应该知道,有几种方法可以构建 bootstrap 置信区间,我们鼓励好奇的读者阅读[ Carpenter & Bithell,2000 ]来更好地了解每种方法的利弊。如果你需要更多关于本文所用方法的信息,可以在[ Efron & Tibshirani,1994,ch.13 ]中找到。

依我拙见,构建一个或多或少“准确”的置信区间并实际使用它比完全忽略从置信区间获得的信息要好。

5.如何解读一个置信区间?

本帖中我们讨论的置信区间是 frequentist 置信区间。为了确保我们理解它们的含义,我们将考虑下面的例子:

假设我们为分类器的召回构建了 95%的置信区间,并获得区间[0.55,0.65]。

这意味着:有 95%的概率区间【0.55,0.65】覆盖(包含)真实召回。

意味着:有 95%的概率真实回忆在区间【0.55,0.65】内。

迷茫?不要害怕。

当讨论 frequentist 置信区间(最常见的置信区间)时,真实参数(在我们的例子中是回忆)被认为是一个固定数,而不是一个随机变量 —它只有一个固定值,该值要么在置信区间内,要么不在置信区间内。没有与之相关的概率。95%的概率指的是我们用来构造区间的方法方法保证区间在 95%的情况下(平均)覆盖真实参数。

考虑以下情况:我们计算召回 100 次(每次基于不同的样本/测试集),并以 95%的置信度构建 100 个置信区间。
这 100 个置信区间中的 5 个将不会覆盖真实召回(平均而言)——例如,当真实召回为 0.66 时,其中一个可能是[0.55,0.65]的置信区间,即这个[0.55 到 0.65]的置信区间是不覆盖真实召回的那 5 个置信区间之一。

另一个例子:假设我们想找出一个中国人的平均身高。真实的平均身高是某个固定的数字,例如 168.3 厘米。我们无法测量 14 亿人的身高,所以我们使用 1000 名中国人的样本来测量他们的身高——我们样本的平均值是 167.3 厘米,置信区间是[166.1 厘米,168.5 厘米]。
我们现在再抽样调查 1000 人,测量他们的身高,构建另一个置信区间。
我们重复上述过程 100 次。到目前为止,我们已经计算了平均身高 100 次(每个样本一次),并构建了 100 个置信区间。平均而言,这些置信区间中的 5 个将不涵盖(包含)168.3 厘米的真实平均身高

现在让我们假设我们只有一个 1000 人的样本,因为这是我们的预算所能负担的。我们基于单一样本构建的 95%置信区间有 5%的可能性无法覆盖真实的平均身高。

注意:我们总是可以构建一个置信水平更高的置信区间,比如说 99%,代价是让区间变宽。

6.样本大小和置信区间宽度

置信区间的宽度对我们是有价值的,因为它使我们能够更好地理解我们估计的可变性。更宽的间隔意味着更高的可变性。

Fig. 3. Bootstrap confidence interval width plotted against sample size.

上图(图 3)展示了在特定条件下,使用 bootstrap 方法( .632 )估算召回率的模拟结果。改变参数将导致略微不同的结果,但是主要结果将保持不变——我们可以预期置信区间宽度随着样本量的增加而减小。

图中的数据是通过应用 scikit-learn 的逻辑回归分类器生成的,该分类器用于通过将其拟合到使用[make_classification](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_classification.html)生成的二元分类数据集上来获得 bootstrap 估计值和召回的置信区间。对于每个样本大小,运行 1000 次 bootstrap 迭代,以获得 bootstrap 估计和召回的置信区间。随机噪声被添加到数据集中,使分类任务变得更加困难,就像真实世界中的数据(通常)有噪声一样。

一些模拟结果

对于包含 500 个数据点的数据集,bootstrap 召回估计为 60.6%,但 95%置信区间为[48.9%,70.8%]。
这意味着我们不能为我们获得了 60.6%的召回率而高兴,因为置信区间有 95%的机会覆盖(包含)真实召回率,这可能是 50.0%,这使得我们的分类器像掷硬币一样有用。

相同的分类器在 1,000 个数据点上进行测试,产生了 62.9%的 bootstrap 召回估计值,95%的置信区间为[54.5%,71.3%]。注意,现在我们可以更确定我们的分类器比随机猜测的目标类更好,因为置信区间不包括值 50%。

注意 : Bootstrap 置信区间宽度(以及其他属性)不仅是样本大小的函数,也是分类器类型(线性模型、基于树的模型等)的函数。),正在估计的参数和数据集中要素的固有方差,等等。

7.现在在 Python 中

本节介绍了一个可以复制粘贴并在代码中轻松使用的函数。该函数简单地包装了来自 mlxtend 包的[bootstrap_point632_score](http://rasbt.github.io/mlxtend/user_guide/evaluate/bootstrap_point632_score/)函数,以便于使用。

代码包括bootstrap_estimate_and_ci函数以及几个简单的使用示例,我们在这些示例中计算召回精度F1-得分ROC AUC精度的估计值和置信区间。

引导迭代的次数

我们注意到[ Carpenter & Bithell,2000 ]建议在计算引导置信区间时使用 1000–2000 次引导迭代。如果你只关心参数估计,那么 50-200 次迭代通常就足够了[ 埃夫隆&蒂布希拉尼,1997 ]。

对于大样本量和计算成本更高的模型,使用大量 bootstrap 迭代会变得非常耗时,因此默认迭代次数(n_splits)被设置为 200。您可以选择是否增加该数值,以更长的计算时间为代价获得更准确的置信区间。

使用

[bootstrap_estimate_and_ci](https://gist.github.com/roncho12/60178f12ea4c3a74764fd645c6f2fe13)函数返回 bootstrap 估计值、bootstrap 置信区间的下限和上限以及 bootstrap 估计值的标准偏差(也是样本估计值的标准误差),例如像这样调用函数:

*est, low, up, stderr = bootstrap_estimate_and_ci(estimator, X, y)*

将返回四个值,其中est是准确度的 bootstrap 估计,95%置信区间为[ lowup,样本准确度的标准误差为stderr

代码 包括几个调用不同参数和不同度量的函数的例子。

关于参数的说明

  • score_func的默认值是准确性,但它可以是任何具有签名score_func(y_true, y_pred, **kwargs)的 sklearn 分类度量。如果您愿意,您也可以编写自己的评分函数来满足您的需要,只要它具有上述签名并返回一个数字。
  • 如果您希望使用类似 sklearn 的[roc_auc_score](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html#sklearn.metrics.roc_auc_score)的评分函数来获得 ROC AUC 的估计值和置信区间,您可以在代码中看到一个示例。这有点像黑客,但实现起来非常简单。
  • method的默认值是.632,因为.632+方法的计算量更大,会大大延长运行时间。如果使用比 .632 更好的估算器来获得估算值对您来说非常重要,即使以计算时间为代价,您也应该选择.632+方法。在所有其他情况下,.632方法应该提供良好的结果。
  • alpha的默认值是 0.05,这将导致一个
    (1-alpha) 100% = 95%
    的置信区间。
    如果您想要 99%的置信区间,请使用alpha=0.01;对于 90%的置信区间,使用alpha=0.1等等。
    *

8.这里有龙

尽管置信区间在各个领域都是常见的(甚至是强制性的),但它们也是一个主题:

  1. 经常被误解。
  2. 经常争论。

重复置信区间的优点和缺点超出了本文的范围,所以我将只简要强调几个已知的问题:

  • 频率主义者置信区间与贝叶斯可信区间。
  • 将间隔的宽度解释为与其“准确性”一致。
  • 为了置信区间而放弃使用 p 值,但仍然使用置信区间进行统计推断。
  • 有些理论性质在渐近上是正确的,有时被认为适用于每一种情况,尽管事实并非如此。

以上绝不是所有可能问题的完整列表。如果你想更好地了解它,你可以在[ [Morey et al .,2016](http://Morey, R.D., Hoekstra, R., Rouder, J.N., Lee, M.D. and Wagenmakers, E.J., 2016) ]中阅读更多信息。

克里斯托佛·马格努松的博客中的这个链接提供了一个关于置信区间的漂亮的交互式可视化,作者的评论信息丰富,写得很好。

统计推断

这篇文章没有建议使用置信区间来进行统计显著性检验,并且也没有鼓励将它们视为描述绝对的“真理”,而仅仅是一种近似。因此,上述问题不应成为主要关注点。**

但是,如果您确实计划使用置信区间来执行统计推断(例如,分析医疗数据以决定适当的治疗),尤其是在处理小样本量时,您可能希望更好地了解置信区间。
作为一个例子, Vollset,1993 比较了 13 种构造二项式比例置信区间的方法,并描述了它们的特点。

构建置信区间的方法有很多,选择“正确”的方法需要了解每种方法的特性。

代表性样品

我们总是假设我们拥有的样本(我们的数据集)恰当地、成比例地反映了真实人群的关键特征,即它是一个代表性样本。否则,使用这样的样本获得的任何估计都是不可靠的,不应该被信任(在大多数情况下)。

置信区域

本文没有讨论的另一个问题是构建同时置信区间(称为置信区域),它是多参数情况下置信区间的推广。**

我们没有讨论同时为几个参数构建置信区间的情况,这种情况保证这些区间将以概率 X,覆盖真实参数,即,为每个参数单独构建 X%置信区间是一回事,而构建 X%置信区域是另一回事,该区域将在给定置信水平 X%下同时覆盖所有参数。

摘要

我们已经相当广泛地讨论了置信区间,我希望我已经很好地传达了使用它们的好处。

我们看到了如何应用 bootstrap 方法来估计参数及其可变性,并为我们的估计构建了 bootstrap 置信区间。

我们查看了几个代码示例,这些示例展示了如何使用 bootstrap 方法获得估计值,并构建召回率、精确度、F1 分数、ROC AUC 和准确度的置信区间。

就是这样。

感谢你花时间通读这篇文章!

如果你愿意,我们非常欢迎你写一篇回应。我很想知道您的想法——欢迎各种形式的反馈!

收场白

置信区间在许多领域都是一个有价值的工具,但在我们实践数据科学时,有时会被忽略。通过忽略它们,我们含蓄地说,使用置信区间为癌症患者选择适当的治疗方法或决定一种新药是否真的降低了心脏病发作的风险是可以的,但当试图根据其他领域的数据建立模型时,置信区间是不相关的——如果我们的估计“不准确”,没有人的健康会受到威胁,因此可以安全地忽略置信区间。

绩效指标,如 F1 分数、ROC AUC 等。是随机变量 —每次我们计算它们时,它们的值都会发生变化,因为它们取决于我们选择作为测试集或验证集的样本,即不同的样本会产生不同的值。置信区间可以帮助我们估计度量标准的可变性。

构建置信区间可能(有时)会导致一些精神上的痛苦——发现我们辛苦获得的 F1 分数实际上可能低于我们想要接受的分数,这一点都不好玩。另一方面,置信区间使我们能够知道我们可以“信任”我们的测量值多少,以及它们“可能”有什么范围的值。

参考

  1. Efron,b .和 Tibshirani,r .,1997 年。交叉验证的改进:632+ bootstrap 方法。美国统计协会杂志92 (438),第 548–560 页。**
  2. 迪奇乔,T.J .和埃夫龙,b .,1996 年。自举置信区间。统计科学,第 189–212 页。**
  3. 卡彭特和比瑟尔,2000 年。 Bootstrap 置信区间:什么时候,哪个,什么?医学统计学家实用指南。医学统计学19 (9),第 1141–1164 页。**
  4. 埃夫龙,b .和蒂布拉尼,r .,1986 年。标准误差、置信区间和其他统计准确性测量的自举方法。统计科学,第 54-75 页。
  5. Efron,b .和 Tibshirani,R.J .,1995 年。 交叉验证和 bootstrap:估计一个预测规则的错误率 。斯坦福大学生物统计学系。
  6. Janerich,D.T .,Thompson,W.D .,Varela,L.R .,Greenwald,p .,Chorost,s .,Tucci,c .,Zaman,M.B .,Melamed,M.R .,Kiely,m .和 McKneally,M.F .,1990 年。肺癌和家庭中暴露于烟草烟雾。《新英格兰医学杂志》323 (10),第 632–636 页。**
  7. Efron,b .和 Tibshirani,R.J .,1994 年。 自举简介 。CRC 出版社。
  8. 埃夫龙,b,1983 年。估计预测规则的错误率:交叉验证的改进。美国统计协会杂志78 (382),第 316–331 页。**
  9. 2013 年,詹姆斯·g·威滕·d·哈斯蒂·t·蒂布希拉尼·r。(第 112 卷,第 18 页)。纽约:斯普林格。**
  10. 瑞典沃尔塞特,1993 年。二项式比例的置信区间。医学统计学12 (9),第 809–824 页。**
  11. Morey,R.D .,Hoekstra,r .,Rouder,J.N .,Lee,M.D .和 Wagenmakers,E.J .,2016。把信心放在置信区间的谬论。心理通报&回顾23 (1),第 103–123 页。**

你有可能被熊袭击吗?

原文:https://towardsdatascience.com/are-you-likely-to-be-attacked-by-a-bear-5f0ba960e0de?source=collection_archive---------27-----------------------

Photo by Photo Collections from Pexels

经过两个月的学习和项目,我来到了 Udacity 的数据可视化纳米学位项目的顶点。简而言之,这个顶点项目的目标是通过从改头换面星期一中选择一个数据集或可视化,并在此基础上进行改进,将课程的所有原则结合到一个作品中。由于我对熊的兴趣,我决定基于维基百科的数据来源制作一个关于致命熊袭击的可视化图片(尽管它们看起来毛茸茸的,令人想抱,但它们可能是致命的)。伴随可视化的故事由 Vox 的扎卡里·克罗克特撰写。

这篇文章的其余部分详细描述了我改进致命熊攻击可视化的过程,以及我为什么做出这样的设计决定。对于那些只对关键的要点和改进感兴趣的人,请查看 TL;博士部分。对于那些有几分钟空闲时间并且有兴趣和我一起完成我的过程的人,请继续阅读这篇文章的详细部分。

我的 Viz 改进之旅

下面可视化的问题陈述是“在哪个公园,什么时候,你最有可能被熊杀死?”

Data collected, prepared, and distributed by Ali Sanne on data.world | Visualization by Zachary Crockett, Vox

自然地,我期望可视化有公园的位置和一年中什么时候熊更可能攻击。当我没有找到那个信息时,我点击了源文章,通读了这个故事。以下是我创建新仪表板的过程:

  1. 下载源数据集

数据集被收录在 data.world 上,在“改头换面星期一”的源可视化旁边可以方便地找到。在查看了预览以了解包含了哪些数据后,我继续下载了该文件。

2。浏览/清理 Excel 中的数据

我做的第一件事是在 Excel 中打开数据集来查看原始数据。我首先通过滚动来熟悉列标题,看看都包括了什么。我在寻找数据中的任何不一致之处,如缺失/空白字段、单元格格式(即字段设置为常规、文本或日期格式)、额外空格和拼写错误。马上,我注意到“位置”栏下的一些单元格被写成“城市,州”,而其他单元格被写成“附近的城市,州”。我找到了所有在位置前带有“near”的单元格,并点击了 replace,没有填充任何内容(实际上删除了 near 的所有实例)。接下来,我将“日期”列改为日期格式,而不是保留它。最后,我删除了我能找到的任何多余的空格,并运行拼写检查。需要注意一些事情:

  • 有些字段是空白的,我认为这是数据收集过程中的选择偏差。似乎这些字段完全是随机缺失的。
  • “年龄”栏下的一些字段包含小数,如 0.41666 或 0.83333,这表明在处理数据时存在一些限制。(幸运的是,年龄不是回答我的问题陈述的关键因素——更多细节见下一节)
  • 位置格式没有标准化-一些字段具有国家公园的名称,其他字段具有城市名称和州名称,或者两者的变体。

3。定义问题陈述和故事大纲

在浏览完数据集后,我思考了一些问题,这些数据可能表明了一些趋势。我从数据中获得的关键信息是致命熊攻击的地点、熊的类型和攻击日期。我还参考了最初的问题陈述,因为我认为 Zachary 在 Vox 上的故事写得非常好,符合数据,但标题并没有尽可能地描述数据(上面看到的可视化没有显示公园的位置)。根据我对数据的了解和我对扎卡里故事的想法,我决定的问题陈述是“在北美你最有可能被熊袭击的地方是哪里?”

在这一点上,我已经定义了问题陈述,并且我知道主要的数据,所以我需要做的就是将它放入一个故事序列中。我从哪一年发生了多少起致命的熊袭击开始,为问题陈述奠定了基础。然后,我通过指出大多数袭击发生的地点,进入了故事的高潮。最后,我用哪种熊参与了攻击来结束这个故事。

4。连接到 Tableau 中的数据

我已经准备好连接 Tableau 中的数据,开始玩可视化游戏。然而,Tableau 反复给我一个错误,说我没有权限访问这个文件。我的快速解决方法是复制原始文件中包含数据的所有单元格,将其粘贴到新的 Excel 文件中,并以另一个名称保存。成功了。

5。创建单独的工作表和摘要图块

因为我已经在纸上定义了问题陈述和故事大纲,所以我有了一个粗略的想法,我想要创建什么样的可视化来塑造一个更好的故事。以下是我创作视觉效果的顺序:

  • 条形图:为了给我的问题陈述搭建舞台,我想展示 1900 年至 2018 年间每月发生多少起致命袭击。这类似于 Zachary 的条形图,但是为了清晰起见,我决定采用一种更简单的设计方法。
  • :清晰直观地链接回问题陈述和故事。这也类似于 Zachary 的故事中的地图,但我将其简化为突出显示熊袭击最致命的州,而不是专门突出显示公园(希望利用更多的原始数据进行定位)。
  • 堆积条形图:直观对比致命袭击中涉及的熊的种类。
  • 树状图:直观表示 1900-2018 年间每年有多少人死亡。
  • 高亮显示表格:为了更好地显示灰熊袭击最多的月份。
  • 横条图:显示最有可能被熊攻击的前 10 个地点。
  • 摘要贴:虽然我不确定是否会使用这些,但我还是为我的故事制作了一些。

6。使用列布局组装仪表板

现在我已经创建了单独的工作表,剩下的就是如何将它们放在一个仪表板中。我开始在纸上画一些布局草图,然后将所有东西拖放到 Tableau 仪表板中。我的第一个布局是典型的四象限布局。这种布局帮助我思考我的故事,但我不喜欢它显示我的视觉效果的顺序,所以我回到草图。我真的很喜欢黄金比例布局的想法,所以我开始把我的视觉效果拼凑到这个布局中,但我发现较小的“网格”更难填充。我又回去画素描,把我的故事当成叙事来思考。如果我把它放在一个幻灯片中,我将如何呈现视觉效果的顺序?我决定保持简单,采用三列布局。

这是我的速写的样子…

My quadrant layout sketch

Sketch of golden ratio layout

Final sketch — 3 column layout

7。最终产品

我创建的最终仪表板是独一无二的,因为它可以独立讲述基于数据的故事。虽然 Zachary 在 Vox 上的故事写得很好,有很好的图形可视化,但我发现很难跟上交替的文本和视觉效果。我所做的是提取文本中的信息,并将其作为可视化信息显示在仪表板上,利用图表标题来总结故事。

最终产品的截图可以在文末找到。如果你想与 Tableau 公共页面互动的话,还提供了到 Tableau 公共页面的链接。

8。关于数据的说明

当我浏览这个数据集时,我对我是否应该使用它有非常复杂的感觉,因为数据几乎是零星的。我的意思是,这些数据是由某人根据写在维基百科页面上的数据收集和组织的。根据维基百科页面的引用,看起来大多数数据是从报纸文章、出版物或其他新闻渠道收集的。选择偏差在这里起了作用,因为我们只考虑了基于某人决定写的已发表的故事的致命熊袭击。一个更准确/可靠的获得致命熊袭击的方法可能是从医院记录中获得。

我注意到的另一件事是有关于致命熊袭击的描述。对于那些涉及两个或更多人的攻击,对所有人的描述都是一样的,可能准确也可能不准确。如果我要在我的数据故事中包含对攻击的描述,我必须以某种方式对数据进行规范化。

总之,我认为数据收集过程可以改进,以减少我们处理过程中的限制和偏见。这将产生一个更准确的熊袭击致死率的数据故事。

TL;博士

我在 Vox 上找到了由 Zachary Crockett 创作的关于致命熊袭击的可视化图片,于是我踏上了改进它的旅程。我开始研究和清理数据集,因为这些数据已经不可用了。当数据准备好了,我把它连接到 Tableau。然后我开始画出潜在的图表和布局。虽然我画的大部分潜在图表都没有做成画面,但我创造了更好的视觉效果来帮助我讲述我的故事(画面的力量)。接下来,我开始绘制仪表板布局,并最终拼凑出我的故事。下面是最终结果:

Created by Vanna Quon | Made with Tableau Public

你准备好成为一名数据科学家了吗

原文:https://towardsdatascience.com/are-you-ready-to-be-a-data-scientist-af3d90770ac1?source=collection_archive---------23-----------------------

Image by Gerd Altmann from Pixabay

回到 2013 年,麦肯锡的一份报告中有一句令人担忧的话:

“美国将面临多达 19 万名受过统计和机器学习高级培训的数据科学家的短缺,以及 150 万名在统计方面足够精通以有效使用大数据的经理和分析师的短缺。”

麦肯锡报告,2013 年 7 月

不可否认,数据科学是一个快速增长的领域,正在吸引更多的关注,并且迫切需要劳动力来填补当今就业市场上的大量空缺。

虽然我们努力赶上数据科学的潮流,但这里的主要问题是:

我们准备好工作了吗?我们应该学习什么才能开始数据科学职业生涯?

也许解决上述问题的最好方法是查看招聘信息,这些信息可以直接让我们了解雇主对我们当前市场的期望。

在本文中,我将基于一个真实的工作数据集强调几个关键方面。该数据集包括美国数据科学家的职位发布(2018 年更新)。我们将采用探索性数据方法,从数据集中获得洞察力,告诉我们一些关于数据科学职业的事实。

在我们开始之前…

如果您希望在 Indeed 数据集上遵循我的数据探索性的演练,您需要做好准备:

  1. Indeed 职位发布数据集来自 ka ggle:https://www . ka ggle . com/elroyggj/Indeed-dataset-data-scientistanalystenengineer
  2. Jupyter 笔记本
  3. Python 熊猫& Seaborn 库

1.各行业的数据科学市场需求

1.1 加载数据

在 Jupyter Notebook 中,我们从使用 Python pandas 库加载 Indeed job 数据集“ indeed_job_dataset.csv ”开始,并快速查看数据。

Python scripts to load data from Indeed dataset

The first five records of Indeed dataset

数据集中总共有 5715 个作业条目。对数据的一瞥向我们展示了数据科学职位发布的详细信息,如工资、技能和行业。

1.2 绘制饼图

现在,让我们试着通过绘制一个饼状图来探索不同行业的工作需求。

Python script to create Pie Chart

Pie Chart showing data science market demand in various sectors

1.3 我们从饼图中学到了什么

如果我们抛开其他类别,对数据科学职位需求最高的是 咨询和商业 部门。然而,不应低估其他领域对数据科学的市场需求。各行业市场需求的存在标志着数据科学职位的工作机会无处不在。有必要快速了解一下数据科学如何影响不同行业的商业模式和运营。

1.3.1 咨询和商业服务

在商业领域,数据科学根据从我们的购买和网络浏览历史中收集的数据提供个性化的客户体验。例如,每当我们登录亚马逊,系统就足够智能,可以检测并推荐可能是我们最喜欢的书籍。

Amazon Page 1

此外,还通过显示购买了该商品的顾客也购买了商品的列表来交付相关商品

Amazon Page 2

简而言之,数据科学极大地促进了商业世界中的目标营销过程。

1.3.2 互联网&软件

在互联网和软件领域,由于数据科学社区的巨大市场需求,谷歌、微软、亚马逊和 IBM 等科技巨头已经推出了作为云服务的机器学习 ( MLaas )。

Amazon Machine Learning Services (Source: https://aws.amazon.com/machine-learning/#)

MLaas 能够快速启动机器学习(ML)计划,而无需投入大量时间和金钱来购买和设置高级工作机器。有了 MLaas,每个人都可以开始构建他们的第一个 ML 模型,以低成本从预测中产生有价值的见解。

MLaas 的日益流行也意味着未来的软件开发交付不再局限于“软件产品”,而是可以以数据科学服务或解决方案的形式出现。这种形式的服务交付在个体自由开发者社区中已经变得司空见惯。一个典型的例子就是 Fiverr

Fiverr Freelance Job Posting For Machine Learning (Source: https://www.fiverr.com/)

1.3.3 银行&金融

数据科学在银行和金融领域的一个典型应用是欺诈检测。机器学习能够有效检测涉及银行交易、洗钱、贷款申请以及开立新账户的欺诈活动。例如,每当有异常高的交易活动时,由机器学习算法支持的欺诈检测系统能够将其搁置,直到授权用户验证交易。

Photo by Dmitry Demidko on Unsplash

数据科学也有助于改善投资银行的风险建模。通过大数据分析,银行在进行投资或评估公司价值以创造企业融资资本时,可以获得更好的洞察力。

摩根大通等主要金融机构非常重视数据科学的潜力。

“无论这些变化的时间表如何,分析师、投资组合经理、交易员和首席信息官都需要熟悉大数据和机器学习的发展以及相关的交易策略。”

摩根大通

[## 利用机器学习和人工智能为投资决策提供信息

点击查看更多视频用于分析大数据的量化技术和新方法越来越多地被采用…

www.jpmorgan.com](https://www.jpmorgan.com/global/cib/research/investment-decisions-using-machine-learning-ai)

1.3.4 医疗保健

医疗保健领域的数据科学用例总是与可穿戴设备的大数据分析联系在一起。可穿戴设备可以捕捉和记录大量的健康数据,如心率、血压甚至我们的睡眠模式。这些可穿戴数据有助于医生预测潜在的健康问题,并提出预防措施。

Photo by Alexander Ruiz on Unsplash

此外,数据科学提供巨大前景的另一个领域是机器学习在医疗诊断中的应用。随着电子健康记录的大量存在,数据分析师可以应用机器学习技术来处理数据,并进行更快、更精确的诊断。改进的诊断使医生能够在早期检测慢性疾病的迹象,并有效地为患者确定合适的治疗方案。

Image by rawpixel from Pixabay

另一方面,数据科学也有助于在医疗保健领域引入个性化的癌症治疗。最近,一项临床研究表明,人工智能(AI)可以使用医学扫描图像和电子健康记录来产生一个治疗框架,帮助医生预测正确的治疗方法,对个体患者产生最少的副作用。

[## 使用人工智能进行个性化放射治疗

克利夫兰诊所领导的新研究表明,人工智能(AI)可以使用医疗扫描和健康记录来…

newsroom.clevelandclinic.org](https://newsroom.clevelandclinic.org/2019/06/27/using-artificial-intelligence-to-deliver-personalized-radiation-therapy/)

1.3.5 保险

与银行和金融部门类似,保险业面临的一个主要挑战是欺诈检测。这就是数据科学发挥作用的地方,它使用机器学习模型来识别可能给保险提供商带来损失的欺诈性索赔

Photo by Helloquence on Unsplash

通过使用保险数据集,如索赔细节、当事人细节、风险细节等,可以训练机器学习模型来估计欺诈索赔发生的可能性。IBM 已经为保险公司提供了类似的预测分析解决方案,帮助他们处理欺诈性索赔。

[## 保险预测分析

不要看后视镜。使用预测分析来关注未来的道路。今天的保险公司…

www.ibmbigdatahub.com](https://www.ibmbigdatahub.com/whitepaper/predictive-analytics-insurance)

此外,数据科学还通过为保险产品提供更准确的预测定价模型来改善风险管理。保险公司可以根据客户行为数据预测客户终身价值(CLV),从而评估客户对保险公司的潜在盈利能力。

2.数据科学就业市场的预期技能

从上面的章节中,我们简单了解了数据科学对不同行业运营的影响。另一方面,数据科学总是涉及全面的数据处理管道,需要无数的专业知识来处理数据。

让我们试着再看一遍真实的工作数据集,这次我们将关注雇主期望的技术技能数量。我们将绘制一个条形图,显示从招聘信息中确定的技能数量。

Python script to create a bar chart to show the number of skills expected by employers

A bar chart showing the number of skills expected by employers

有趣的是,该条形图显示了大多数数据科学职位期望求职者至少具备两种及以上技能。(我们可以善意地忽略显示“零”技能数量的招聘信息,这只是因为一些招聘信息不包括任何预期技能的细节。)

也许我们还可以快速地看一下雇主到底期望什么样的技术技能。我们尝试观察前 20 条记录,并查看实际工作数据集中的“技能”列。

Python script to view the first 20 records of “Skill” column

The first 20 records of “Skill” column

一瞥数据让我们看到了一些刺眼的关键词:“机器学习”、 AI ”、 R ”、 Python ”、 SAP ”、 SASSQL数据挖掘SPSS 等。

数据集告诉我们当前的数据科学市场需要多样化的跨学科技能。

然而,不可能在这里阐明所有的技能(因为这个列表非常长)。相反,我将挑选几个主要类别的必备技能,并逐一介绍。

2.1 编程

Image by StockSnap from Pixabay

编程是我们在数据科学领域从事许多工作所需要的基本技能,从数据争论、统计分析、可视化分析到机器学习。

在现有的数百种编程语言 PythonR 是数据科学中最受欢迎的两种语言。我们可以通过绘制一个条形图来显示就业市场对编程语言的需求,从而再次查看我们的 Indeed 数据集。

Python scripts to create a bar chart showing the market demand for Python and R

A bar chart showing the market demand for Python and R

它们受欢迎的原因如下:

  1. 他们是开源。每个人都可以简单地免费使用和重新发布它们。
  2. 用于数据分析、可视化和机器学习的丰富包和库。
  3. 丰富的学习资源(互联网上有大量的教程)

虽然争论哪种语言更好可能有点争议,但我想说我们可以选择其中一种作为启动数据科学项目的起点。作为一名数据科学探索者,这里主要关心的是通过编写一些代码来熟悉底层的数据处理管道。在这个过程中,我们会找到更好地满足我们需求的工具,并且我们总是可以在以后切换到另一个工具。

此外,我们也不应该忽视除了 Python 和 r 之外的其他语言选择。有一些替代语言,如 Java、Matlab、Julia、JavaScript、C++等可用于数据科学。他们每个人都有自己的市场需求和支持社区。

以下是一些对 Python 和 R 编程有用的学习资源:

Python 教程

  1. 【https://www.guru99.com/python-tutorials.html
  2. https://www.w3schools.com/python/default.asp
  3. https://www . coursera . org/learn/python-for-applied-data-science-ai

R 教程

  1. https://www.guru99.com/r-tutorial.html
  2. https://www.statmethods.net/r-tutorial/index.html
  3. http://www.r-tutor.com/

2.2 数据库开发

Image by Gino Crescoli from Pixabay

在许多商业环境中,数据被收集并存储在一个结构明确的关系数据库中。在任何数据科学项目中,数据都是最基本的元素,因此应该得到适当的关注,而不是以任意的方式将其放入几个平面文件中。

因此,掌握关系数据库管理系统(RDBMS) 在许多数据科学工作中是必不可少的。让我们再次探索我们的 Indeed 数据集,收集一些关于雇主期望的各种 RDBMS 技能的信息。

Python scripts to create a bar chart showing market demand for RDBMS Skills

A bar chart showing market demand for RDBMS Skills

上面的条形图显示了对任何流行的关系数据库的熟悉程度,如【MySQL】OracleDB2微软 SQL Server微软 Access ********

虽然关系数据库仍然被广泛接受,但另一种类型的数据存储, NoSQL 数据库,已经开始在各种行业中获得关注。NoSQL 数据库的存在是为了满足市场对更灵活和可扩展的数据结构的需求,以存储通常更加非结构化并以指数速度增长的大数据。

用关键字“ NoSQL ”对 Indeed 数据集进行简单的查询,将会得到 607 个肯定的命中结果。

Python script to count positive hits of “NoSQL” from Indeed dataset

Positive hits of “NoSQL” from Indeed dataset

这是值得探讨的一些变种,NoSQL 数据库管理系统,出现在确实招聘启事。

Python scripts to create a bar chart showing market demand for NoSQL DBMS Skills

A bar chart showing market demand for NoSQL DBMS Skills

DynamoDBCassandra和** HBase 是就业市场上比较流行的四种 NoSQL 数据库管理系统。随着大数据的不断增长,建设 NoSQL 数据库的市场需求必将增加。因此,掌握 NoSQL 数据库开发应该是数据科学家遗愿清单的一部分。**********

2.3 数据挖掘

Photo by Nicolas J Leclercq on Unsplash

数据挖掘从原始数据中提取知识或有用信息,是每个数据科学家的必备技能。数据挖掘的一个关键方面是从原始数据中识别趋势或新兴模式,从而形成决策过程。因此,统计数据分析可视化分析是数据挖掘过程中的两个常见例程。****

从技术上来说,数据挖掘可以使用编程方法来执行,这种编程方法使用诸如 Python 或 R 等语言。这两种语言都提供了许多有用的库,只需要几行代码就可以进行统计分析和可视化分析。因此,对于数据科学家来说,仅仅拥有一些基本的编程语法知识是不够的。相反,需要熟悉一些数据科学的库。以下链接显示了用于数据科学的前 20 个 Python 和 R 库:

  1. https://bigdata-made simple . com/top-20-python-libraries-for-data-science/
  2. https://www . kdnugges . com/2018/05/top-20-r-libraries-data-science-2018 . html

另一方面,掌握数据挖掘的软件包如TableauSPSSSAS Excel 在数据科学工作中也是可以期待的。让我们再次探索 Indeed 数据集,观察该软件的市场需求。****

Python scripts to create a bar chart showing market demand for statistical software

A bar chart showing market demand for statistical software

显然,Tableau 是行业中使用的统计软件包中的佼佼者。像 Tableau 这样的软件提供了一个非常用户友好的界面,使任何人都可以只通过添加和删除按钮控制来进行令人惊叹的数据可视化。

然而,使用软件包进行数据挖掘的缺点是软件要支付高额的许可费。这可能也是 Python 和 R 在业界接受度要好得多的原因(就拿“Python&R”Vs“统计软件包”的岗位需求统计的两个柱状图对比一下就知道了)。****

2.4 机器学习

Image by Gerd Altmann from Pixabay

机器学习可能是数据科学中最流行的“术语”。另一个简单的从真实的招聘信息中查询“机器学习”关键词会给你 2297 肯定的结果。**

Python scripts to show positive hits of “Machine Learning”

Positive hits of “Machine Learning” in Indeed dataset

在简单明了的解释中,

"机器学习是一种给计算机编程的艺术,这样它们就可以从数据中学习."

奥雷连·盖伦

在许多工作领域,机器学习对于使机器本身能够从现有数据中学习以进行大数据分析是可有可无的。目的是对复杂问题(例如银行部门的欺诈检测)做出可靠的预测。

与数据挖掘类似,机器学习在技术上可以使用 Python 或 R 编程来完成,这也解释了为什么这两种语言在行业中被广泛接受。因此,使用一些 Python 和 R 库进行机器学习的经验也是在数据科学领域获得工作的另一大优势。

在开始工作之前,也许磨练机器学习技能的最佳方式是通过实践。Parul Pandey 发表了一篇关于一些顶级数据科学竞赛平台的丰富文章,值得一读。

**** [## 除 Kaggle 之外的顶级竞争数据科学平台

学习任何东西的最好方法是实践。

towardsdatascience.com](/top-competitive-data-science-platforms-other-than-kaggle-2995e9dad93c)****

2.5 云计算

Image by 200 Degrees from Pixabay

云计算是一种相对较新的技术,在当前的就业市场上开始获得很多关注。许多企业选择云平台,而不是在本地机器上托管数据和应用程序。其中的一些原因包括:

  • 节约成本 —云计算采用按需付费模式。基本上,用户只需要为他们使用的服务付费。企业可以节省硬件采购和维护成本。
  • 弹性 —云计算能够根据当前需求自动调整计算资源。这对于那些有高峰和非高峰营业时间的电子商务网站尤为重要。
  • 安全性和可靠性 —云服务提供商负责系统和数据安全,而不是用户自己。

鉴于云计算提供的优势,许多企业期望数据科学家具备云计算技能也就不足为奇了。

的确数据集揭示了对管理 亚马逊网络服务微软 Azure 谷歌云平台 的能力的高需求。

Python scripts to create a bar chart showing market demand for Cloud Computing Skill

A bar chart showing market demand for Cloud Computing Skill

3.最终想法

严格来说,数据科学并不是 21 世纪才出现的。很早以前,在许多商业和学术环境中就发现了利用数据进行决策的方法。很多底层的统计分析方法和机器学习算法都只是几十年前积累的发现。

然而,我们不能否认,随着大数据和互联网技术的存在,如今我们的数据科学家所扮演的角色正在经历巨大的扩展。等待我们的主要挑战是时刻准备好必要的数据技能,以满足市场需求。持续学习和接触是在数据科学职业生涯中生存的关键。

参考

  1. 麦肯锡报告,2013 年 7 月。(检索自https://www . McKinsey . com/~/media/McKinsey/Featured % 20 insights/Americas/US % 20 Game % 20 changers/MGI _ Game _ changers _ US _ growth _ and _ renewal _ Full _ report . ashx)
  2. 机器学习的定义。奥雷连·盖伦(2019)。使用 Scikit-Learn、Keras 和 TensorFlow 进行机器实践学习:构建智能系统的概念、工具和技术

Github 资源

  • 本文中的所有 Python 脚本都可以在一个 Github repo 中找到。请随意下载代码供您参考。

你准备好领导数据科学项目了吗?

原文:https://towardsdatascience.com/are-you-ready-to-lead-a-data-science-project-a9d457388292?source=collection_archive---------30-----------------------

“从任何软件开发项目的角度看数据科学项目”

促使您使用数据科学解决的问题是什么?我们现在可以利用数据的力量和利用这种力量的机制。识别正确的问题或用例是第一步。目前,整个行业有多个使用案例正在受到数据科学的攻击。什么让你产生共鸣?非常清楚你的目标和项目成功的定义是垫脚石。

确定了你的用例以及项目成功的定义之后,你就可以开始更精确地关注项目了。您可能想知道数据科学项目与任何其他软件开发项目有何相似或不同之处?那么,软件工程的原则在这种情况下也没有什么不同,包括处理需求、设计和开发、测试和验证以及最终的实现。这可能看起来很普通,确实如此。不同之处在于你所说的需求类型,数据科学中设计和开发的含义,测试和部署是如何进行的。进一步了解部署后您如何支持和管理您创建的产品。简而言之,整个生命周期或所谓的 MLOps 和模型治理框架。

当然,任何数据科学项目都需要数据。收集数据、净化数据、理解数据的含义、应用适当的处理以使数据可供消费,然后最终提供给模型并对其进行测试,这可能看起来是一项非常直接和机械的任务。实际上,并非如此。在最终处理和输入模型之前,仅仅收集和准备用于分析的数据就需要做大量的工作。通常,这涉及到收集和清理数据的繁重工作,除非您已经创建了精简该过程的智能方法,即使在自动化该过程之前的开始,也需要努力创建该自动化。拥有一个包含数百个维度的数据集同样需要数据科学家完成最重要的任务,他们需要对这些数据有一个透彻的理解,同时获得领域知识,并利用工具和技术进行数据调查和可视化。如今,在数据科学家的处理中,有几种特征工程工具和技术可供利用。这一阶段可以被看作是典型软件工程过程中的需求管理阶段,因为在这一阶段,您将与领域专家一起工作,清楚地引出您需要的信息,以确保您的模型具有您想要实现的预测能力。

在模型开发中,您的数据科学家将使用这些数据来训练模型和调整超参数。这将是一个反复的过程,通过多次实验来完善模型。与典型软件项目中的开发不同,在数据科学中,您通过使用通过特征工程迭代创建的数据集来训练模型来构建。在某个时候,具有不同超参数设置集的模型是模型开发中可变性的另一部分,这些超参数设置集也可以自动化。这里的重要因素是缩小到完美的数据集和超参数设置,这将生成您正在寻找的模型。因此,数据集和模型的版本控制是开发过程的重要部分。

训练时的测试将涉及将模型暴露给看不见的数据,并让它进行预测。实现预期目标的预测和模型的准确性将使其有资格进一步测试其中的任何偏差。测试数据起着至关重要的作用。真实数据集的准确表示保证了从测试结果中得出正确的评估或结论。为了评估模型中的任何偏差,根据各种模型测试主题准备测试案例。执行这些测试用例时的测试结果被评估为模型需要满足的准确性和计划目标。一旦模型在两个方面都合格,即在训练时达到精度目标,在偏差测试时合格,模型就变得适合这个目的。

因此,一旦你的模型准备好了,它是关于它们的消费和使用它们进行预测,以及你如何将这些预测整合到更大的应用和系统中。这些模型的预测可以作为批处理生成,也可以根据它们的用途实时生成。

模型是数据的创造。因此,数据中的任何偏差都会导致模型预测的偏差。在选择和准备用于模型训练的数据集时,重要的是要注意通过训练数据集准确表示真实场景。在不同的用例及数据集中,偏差可能意味着不同的东西。在数据准备和分析阶段的早期,应计划并坚持真正理解所有这些可能的偏差,并保护数据集免受所有这些偏差的影响。这有点像在软件开发生命周期的早期检测缺陷。

来自模型的预测可能无法盲目接受。对于导致这些预测的解释的需求将因用例而异。它可能来自业务需求、监管期望等。基于端到端流程的需求和设计,通过这些流程消费预测将推动可解释性的水平,模型将被期望实现。既不是所有的模型都是黑箱,也不是所有的模型都可以是完全的白箱。一个适当级别的可解释性应该基于用例以及围绕它的所有其他期望来计划和执行。

因此,为了欣赏数据科学项目的独特性,人们常说数据科学既是艺术也是科学。艺术在于特征工程是如何完成的。这的确是一门艺术。一个画家知道如何绘画,但要求他用语言来定义它,然后其他人可以绘画,这是不可能的。你不知道具体是怎么做的,但是你做了。特征工程就是类似的东西。您获得了将输入到模型中进行训练的数据的感觉。这是最重要的阶段,你要一次又一次地回到这个阶段,以达到你的理想模型。当您领导一个项目时,确保团队理解这一点并高度关注特征工程是开发满足项目目标的高质量模型的关键。就像画家对颜色、笔触以及一切如何融合有了感觉一样,数据科学家应该对数据有感觉,了解它的意义以及它为什么重要。这将最终影响模型的有效性和预测的质量。

模型开发是一个迭代过程,但不是线性进展。为了把它做好,首先要做好做实验的准备。你的下一轮实验将会是在从之前的实验中学到东西的基础上使用新的假设。你不会轻易得到满足你期望的权利。确定哪个因素正在产生影响,以及如何修复它,这将需要许多周期。当您处理非常大的数据集时,每个实验的资源需求和成本将是巨大的。深思熟虑的计划和从每个实验中系统的学习一定会使结果朝着正确的方向发展。在整个过程中与合适的人合作将比各自为政产生更多的好处。敏捷实践中的定期站立会议,每个团队成员分享他们做了什么,进展顺利,以及他们面临的挑战,将保持团队的协同作用,正确的障碍将被及时打破。通过这样的实践,即使是一个小的收获或一个大的失败也会很容易地被发现,并得到适当程度的关注和支持,而不会浪费时间和资源。

团队使用视觉材料,以任何创造性的方式,非常定期地分享他们在成就和障碍方面的工作,这将再次非常有助于了解集体的情况和状态。任何好消息或坏消息都不是惊喜,对事情的真实感受会让团队脚踏实地,团结一致。通常情况下,个人介绍一些知识分享会议将提高团队对彼此工作的了解,从而产生对自己工作领域的主人翁感。成员充分参与的授权工作文化将带来真正的生产力和成果。

总的来说,很容易看到一个数据科学项目与任何具有某些独特性的软件开发项目并行。这是一次探索之旅,也是敏捷项目实践的一个紧密候选。

原载于https://www . seem。sg

Python 中的 ARIMA 预测

原文:https://towardsdatascience.com/arima-forecasting-in-python-90d36c2246d3?source=collection_archive---------5-----------------------

把手放在某物或者某人身上

手动和自动 ARIMA 快速启动和运行,包括对两者的简要讨论。

我将把每周的 Spotify 全球 200 强榜单作为一个时间序列,用来试验 ARIMA 模式。数据范围从 2017 年到 2019 年,整个 jupyter 笔记本在这里都有。

以下是我们进行预测的数据子集:

feature_mean.head()

Spotify weekly top 200 audio features

ARIMA 代表自回归综合移动平均线,它取决于三个关键变量 pdq 才能成功。简要如下:

p =滞后次数/AR 项顺序

d =差分顺序

q =滞后预测误差数/MA 条款顺序

米什拉写了更多关于 ARIMA 模型内部工作原理的文章,包括参数。我在这里的目标是解释如何手动和自动地在 Python 中快速启动和运行 ARIMA。我将对声音特征进行预测:

timeseries = feature_mean["acousticness"]

让我们使用扩展的 Dickey Fuller (ADF)检验来看看时间序列是否是平稳的:

from statsmodels.tsa.stattools import adfullerprint("p-value:", adfuller(timeseries.dropna())[1])

p 值:0.43

p 值大于显著性水平 0.05,因此它不是静态的,需要进行差分,即。dT42 0。

我们首先使用自相关函数找出差分的阶数 d :

from statsmodels.graphics.tsaplots import plot_acf, plot_pacffig = plt.figure(figsize=(10, 10))ax1 = fig.add_subplot(311)
fig = plot_acf(timeseries, ax=ax1,
               title="Autocorrelation on Original Series") 
ax2 = fig.add_subplot(312)
fig = plot_acf(timeseries.diff().dropna(), ax=ax2, 
               title="1st Order Differencing")
ax3 = fig.add_subplot(313)
fig = plot_acf(timeseries.diff().diff().dropna(), ax=ax3, 
               title="2nd Order Differencing")

时间序列在d = 1处静止,只有第一个滞后高于显著性水平。如果你的数列略有差异,试着增加一个额外的 AR 项,如果略有差异,也许增加一个额外的 MA 项。

知道我们应该差一次,我们继续找出 AR, p 的顺序。我们通过计算偏自相关中显著性水平以上的滞后数来得到它:

*plot_pacf(timeseries.diff().dropna(), lags=40)*

第一个滞后是唯一一个大大高于有效电平的滞后,因此 p = 1

自相关函数可以告知移除平稳序列中的自相关所需的 MA 项 q 的顺序。

*plot_acf(timeseries.diff().dropna())*

在显著性水平之上可以发现一个滞后,因此q = 1。**

**from statsmodels.tsa.arima_model import ARIMAmodel = ARIMA(timeseries, order=(1, 1, 1))
results = model.fit()
results.plot_predict(1, 210)**

Akaike 信息标准(AIC)估计给定模型丢失的相对信息量。越少越好。

**results.summary()**

模型:ARIMA(1,1,1),…,AIC: -806.848 …

我们把它放在脑后,继续测试 auto_arima :

**import pmdarima as pm**

创建模型:自动 ARIMA 使用 ADF 来测试平稳性,p 和 q 的起始值被设置为 1,并且 Spotify 数据不被假定为季节性的:

**def arimamodel(timeseries):
    automodel = pm.auto_arima(timeseries, 
                              start_p=1, 
                              start_q=1,
                              test="adf",
                              seasonal=False,
                              trace=True)
    return automodel**

我们希望像使用 statsmodel 的 plot_predict 一样简洁地绘制它,因此必须填充预测上限和下限之间的区域。

**def plotarima(n_periods, timeseries, automodel):
    # Forecast
    fc, confint = automodel.predict(n_periods=n_periods, 
                                    return_conf_int=True)
    # Weekly index
    fc_ind = pd.date_range(timeseries.index[timeseries.shape[0]-1], 
                           periods=n_periods, freq="W")
    # Forecast series
    fc_series = pd.Series(fc, index=fc_ind) # Upper and lower confidence bounds
    lower_series = pd.Series(confint[:, 0], index=fc_ind)
    upper_series = pd.Series(confint[:, 1], index=fc_ind) # Create plot
    plt.figure(figsize=(10, 6))
    plt.plot(timeseries)
    plt.plot(fc_series, color="red")
    plt.xlabel("date")
    plt.ylabel(timeseries.name)
    plt.fill_between(lower_series.index, 
                     lower_series, 
                     upper_series, 
                     color="k", 
                     alpha=0.25)
    plt.legend(("past", "forecast", "95% confidence interval"),  
               loc="upper left")
    plt.show()**

然后我们就有了拟合和绘制模型所需的所有内容:

**automodel = arimamodel(feature_mean["danceability"])
plotarima(70, feature_mean["acousticness"], automodel)**

**automodel.summary()**

模型:ARIMA(1,1,1),…,AIC: -806.848 …

这与我们手动得到的参数化结果完全相同。哇,效果很好!使用 auto_arima 获得正确的参数要容易得多,也快得多,唯一的缺点是必须从头开始绘制,以便看起来和 statsmodels 内置的一样好。

MachineLearning+网站上关于 ARIMA 模式的精疲力尽的指南功不可没。哦,你也可以试着用前面提到的笔记本把的声音改成别的,比如的舞蹈

[1]:米什拉(M. Mishra),拆箱 ARIMA 模型(2018 年 6 月 11 日),https://towardsdatascience . com/Unboxing-ARIMA-Models-1 DC 09d 2746 f 8

[2]: ARIMA 模型—Python 中时间序列预测完全指南,https://www . machine learning plus . com/Time-Series/ARIMA-Model-Time-Series-Forecasting-Python/