《Arduino家居安全系统构建实战》——2.1 挑战:构建一个垃圾邮件检测引擎

2.1 挑战:构建一个垃圾邮件检测引擎

我们将要处理的文档不是电子邮件,而是文本消息。我们的目标是使用来自英国的真实SMS(短消息服务)数据集发现垃圾短信,这些消息是我们从加州大学欧文分校机器学习知识库中找到的。

■ 附注:

UCI机器学习知识库由加州大学欧文分校的机器学习与智能系统中心于1987年启动。你可以在http://archive.ics.uci.edu/ml/中找到这个知识库,它包含将近300个干净、文档齐备的数据集,可以按照大小、特征类型等条件搜索和组织。这是一个很有趣的机器学习资源,包含了许多常常用作算法性能评估基准的“经典”数据集。

2.1.1 了解我们的数据集

在讨论使用哪个模型之前,首先来观察一下数据。数据集可以从http://1drv.ms/1uzMplL下载(这就是UCI知识库中原始文件的复制品,原始文件可以在http://archive.ics.uci.edu/ml/ datasets/SMS+Spam+Collection上找到)。它作为单个文本文件保存,名为SMSSpamCollection(没有文件扩展名),包含5574条真实的文本消息。每行是一个SMS,标记为“ham”(非垃圾短信)或者“spam”(垃圾短信)。下面是前面几行:

  ham      Go until jurong point, crazy.. Available only in bugis n great world la e buffet...Cine there got amore wat...
  ham     Ok lar... Joking wif u oni...
  spam    Free entry in 2 a wkly comp to win FA Cup final tkts 21st May 2005. Text FA to 87121 to receive entry question(std txt rate)T&C's apply 08452810075over18's
  ham     U dun say so early hor... U c already then say...
  ham     Nah I don't think he goes to usf, he lives around here though
  spam    FreeMsg Hey there darling it's been 3 week's now and no word back! I'd like some fun you up for it still? Tb ok! XxX std chgs to send, £1.50 to rcv```
第一眼的印象是,人们在文本消息中使用的语言明显不同于“标准英语”!例如“U c”这样的片段是“You see”的简写,在普通的词典中可能找不到。

考虑到这一点,我的第一步是尝试获得两组文本之间差别的“直觉”。有没有一些词语在垃圾短信或者非垃圾短信中出现得更频繁?这能够指导我们构建一个智能引擎,自动区分非垃圾短信和垃圾短信。我们首先按照类别(“ham”和“spam”)分解数据集,计算各自的词语出现频率。鉴于这一活动的探索特性,似乎很适合使用F#脚本。

■ 提示:

花点时间研究一下数据!盲目对数据集应用算法可能工作得不错,但是走不了太远。就像开发应用程序时应该花时间学习领域模型那样,对数据的更深入理解能够帮助你构建更智能的预测模型。
####2.1.2 使用可区分联合建立标签模型
数据是首要的,我们将采取和第1章相同的方式,但是有一些变化。数字识别数据集是由数字组成的(像素编码和标签都是如此),而这里的数据有一个特征(文本消息本身)和一个标签(“ham”或者“spam”)。我们应该如何表现它们?

可能的方法之一是将标签编码为布尔值,如非垃圾短信表示为“真”(true),垃圾短信表示为“假”(false)。这种标签工作得很完美,但是也有一些缺点:它不能自动说明字段的含义。例如,如果展示这样编码的一个数据记录:

True Ok lar... Joking wif u oni... ,`
你怎么可能猜出这里的“True”代表什么?另一个潜在的问题是,如果我们需要增加更多的类别(如非垃圾短信、垃圾短信和有歧义的信息),布尔值无法扩展。

机器学习的难点在于不能增加额外、不必要的复杂性。因此,我们将用F#的可区分联合(有时我也将它称作DU)表示标签。如果你之前从未见过可区分联合,可以近似地将其看作C#枚举类型。可区分联合和枚举一样,都定义一组独特的情况,但是功能强大得多。这种类比对DU不公平,但是足以帮助我们起步。

我们先使用可以在FSI中运行的例子,简单地说明DU的工作方式。定义DU和定义其他类型一样简单:

type DocType =
    | Ham
    | Spam```
在F# Interactive窗口运行上述语句(在最后添加;;触发求值),应该看到如下结果:

type DocType =

| Ham
| Spam```

上述语句定义了一个简单类型DocType,它只能取两个值:Spam或者Ham。我喜欢可区分联合的主要原因之一是它们和模式匹配配合得很好,可编写以非常清晰的风格描述业务领域的代码。例如,在我们的例子中,训练集中的每个示例都是非垃圾短信或者垃圾短信,并包含真实消息的内容。我们可以将其表示为一个元组,每个示例是一个DocType和一个字符串,按照这一路线处理消息示例,可以在F# Interactive窗口中尝试:

let identify (example:DocType*string) =
    let docType,content = example
    match docType with
    | Ham -> printfn "'%s' is ham" content
    | Spam -> printfn "'%s' is spam" content```
这个例子只是为了示意目的,但是指出了以后将要遵循的模式。在这个例子中,我们创建了一个小函数,取得一个消息示例并打印其内容以及所属类别。我们首先通过元组模式匹配将消息示例分为两部分(DocType和内容),然后在DocType的两种可能情况上使用模式匹配,在单独“分支”中处理两种情况。在FSI中输入:

identify (Ham,"good message");;`
你应该看到如下结果:

'good message' is ham```
在能够更好地决定如何处理真实SMS内容之前,这就是我们的数据模型。下面从加载数据集入手!

####2.1.3 读取数据集
和第1章一样,我们将把大部分时间花在探究数据集,从脚本环境中积极构建和改进模型上。打开Visual Studio创建一个新的F#库项目,将其命名为HamOrSpam。为了方便起见,我们还从Visual Studio之外使用文件系统,在解决方案中添加一个名为Data的文件夹,将数据文件SMSSpamCollection拖入其中(从前面提到的链接中下载,没有文件扩展名)。参见图2-1。

<div style="text-align: center"><img src="https://yqfile.alicdn.com/3d808bd20e5c9608fd298713670641641f250c8d.png" width="" height="">
</div>

这就使我们可以使用一个小技巧,用比第1章更清晰的方式访问数据文件。F#有两个方便的内建常量__SOURCE_DIRECTORY__和__SOURCE_FILE__,大大简化了脚本中文件的处理,我们可以引用数据文件位置,而无须硬编码一个取决于本地机器的路径。从这些常量的名称你可能已经猜到,第一个常量求得包含文件本身的目录完整路径,第二个返回到文件本身的完整路径,包括文件名。

现在可以进行脚本的编写了。和数字识别器使用的数据集之间主要的差别是,这个数据集没有文件头,只有两列,不使用逗号而使用制表符分隔。其他方面大部分相同:我们有一个包含示例的文件,希望将其提取到一个数组中。果不其然,解决方案看起来非常相似:读取文件并向每一行应用一个函数,将其解析为标签和内容,根据制表符“\t”拆分。

我们直接进入项目中的Script.fsx文件,删除默认的代码并粘贴如下代码:

程序清单2-1 从文件中读取SMS数据集

open System.IO

type DocType =

| Ham
| Spam

let parseDocType (label:string) =

match label with
| "ham" -> Ham
| "spam" -> Spam
| _ -> failwith "Unknown label"

let parseLine (line:string) =

let split = line.Split('\t')
let label = split.[0] |> parseDocType
let message = split.[1]
(label, message)

let fileName = "SMSSpamCollection"
let path = SOURCE_DIRECTORY + @"....Data" + fileName

let dataset =

File.ReadAllLines path
|> Array.map parseLine```

此时,你应该可以选择脚本中刚刚编写的所有代码,在F# Interactive窗口中执行,产生如下结果:

val dataset : (DocType * string) [] =
  [|(Ham,
     "Go until jurong point, crazy.. Available only in bugis n grea"+[50 chars]);
  (Ham, "Ok lar... Joking wif u oni...");
  (Spam,
   "Free entry in 2 a wkly comp to win FA Cup final tkts 21st May"+[94 chars]);
  // Snipped for brevity
  (Ham,
   "Hi. Wk been ok - on hols now! Yes on for a bit of a run. Forg"+[117 chars]);
  (Ham, "I see a cup of coffee animation"); ...|]```
现在我们有了一个示例数据集,每个都标记为垃圾短信或者非垃圾短信。我们可以开始解决真正感兴趣的问题了:可使用哪些特征区分垃圾短信和非垃圾短信?

■ 提示:

时间: 2024-11-13 06:53:48

《Arduino家居安全系统构建实战》——2.1 挑战:构建一个垃圾邮件检测引擎的相关文章

《Arduino家居安全系统构建实战》——导读

前言 机器学习项目开发实战 如果你手里拿着这本书,我就可以认定你是对机器学习感兴趣的.NET开发人员了.你可能对编写C#应用程序很熟悉,开发的很有可能是业务线应用程序.以前你可能遇到过F#,也可能没有.而且,你很有可能对机器学习感到好奇.这一主题每天都见诸报端,因为它和软件工程有着很紧密的联系,但是使用的是不熟悉.看似有些抽象的数学概念.简而言之,机器学习看上去是有趣的主题.值得学习的实用技能,但是从哪里入手难以说清. 本书的意图是作为开发人员的机器学习入门书.我的主要目标是使熟悉代码编写的读者

《Arduino家居安全系统构建实战》——第1章 家居安全系统的入门知识

第1章 家居安全系统的入门知识 Arduino家居安全系统构建实战在这一章中,我们将会介绍如下的内容: 什么是家居安全基础设施它是如何工作的部署这样一个系统都需要些什么在当前条件下为安全系统所做的准备有线安全系统和无线安全系统传统系统与现代化家居安全系统为了紧紧跟随硬件的发展趋势,本书介绍了随处可见且价格极为低廉的平台--Arduino.今时今日,我们可以在各种各样的公共场所如中小学校.高等院校.小型企业或者公共机构见到这个小电路板的身影. Arduino平台因其众多的优势而著名,例如低廉的成本

《Arduino家居安全系统构建实战》——1.2 工作原理

1.2 工作原理 之前讨论了家居安全系统基本的组成部分,但是这些要素都是什么,它们是如何工作的呢?通过对它们进行分类,我们可以将一个安全系统分成两个部分. 1.2.1 硬件部分 一个基础设施的硬件要素必须能够胜任软件的所有技术需求.可以将它们进一步细分为3个不同的子类别.这种分类方式不应该被理解为具有排斥性,因为一个要素经常可以被分到多个子类别中,这种分类方式反而有助于你理解系统所执行的功能. 传感器:传感器将作为系统的感觉器官,其作用就如同人类的身体感官.它们的功能就是从环境中搜集信息,并将这

《Arduino家居安全系统构建实战》——1.3 部署安全系统的先决条件

1.3 部署安全系统的先决条件 如果你正在考虑部署一个安全系统,那么最有可能的原因就是你有这方面的关键需求.因此,在这里最重要的事情就是要准确地确定这种需求.如果做不到这一点,我们最终会步入歧途并造成损失或者导致半途而废. 如果并没有这种需求,你只是拥有着一颗对现代科技勇于探索的心,那么你可能是出于学习和娱乐的目的来设计这个系统,或者试图将自己的家打造成一个现代化的场所.你可以浏览一下这个行业的先进企业的网站以获得参考. 我们可以看到,大多数企业的系统是类似的,只是在某些部分存在一些差异,而这些

《Arduino家居安全系统构建实战》——1.6 传统系统与现代化的家居安全系统的比较

1.6 传统系统与现代化的家居安全系统的比较 最后,我们将给出一个传统系统与现代化系统之间的比较,值得指出的是,在面对不同需求的时候,它们各自都有着特定的用处,这些需求例如减少模型的复杂性,提高系统的可靠性,增加系统可用性以及向开发者提供丰富的信息. 以前,如果综合考虑到多种因素,例如价格.技术的成熟度以及现有的基础设施(连接)等,以一个较低的成本来实现一个可以实时管理的系统几乎是不可能的. 而在智能手机和平板电脑已经普及的今天,这些设备有足够的能力来将硬件收集的数据即时进行发送和接收,并实现这

《Arduino家居安全系统构建实战》——2.5 训练第一个分类器

2.5 训练第一个分类器 实现通用算法之后,我们最终可以回到手上的问题--识别哪些消息是非垃圾短信,哪些是垃圾短信.Train函数的签名提供了目标的清晰概况:要获得分类器,需要一个示例训练集.一个标记化程序和选用的标记.我们已经得到了训练集,现在的目标是使用交叉验证指导分析,确定标记化程序和标记的最佳组合. 2.5.1 实现第一个标记化程序 考虑到上述情况,我们先完成可行的最简单工作,首先是标记化.我们所要做的是取得一个字符串,将其分解为单词,忽略大小写. 这项工作需要正则表达式:\w+模式匹配

《Arduino家居安全系统构建实战》——2.2 根据一个单词决定

2.2 根据一个单词决定 有了数据,我们就可以开始分析了.我们的最终目标是区分垃圾短信和非垃圾短信,但是和数字识别器的情况不同,我们还没有一组清晰的特征,唯一的材料是原始文本块--SMS本身.与此同时,人们会猜测文本中有许多信息可供利用.我们只需要找到一个途径,将这些字符串转换成可以使用的特征即可. 2.2.1 以单词作为线索 如果你仔细观察刚刚加载的数据集,就可能会注意到垃圾短信看起来和非垃圾短信有些不同.浏览这些短信,你的眼睛很容易找出某些值得警惕的线索,暗示着某一条短信可能是垃圾短信.举个

《Arduino家居安全系统构建实战》——第1章 256级灰度

第1章 256级灰度 机器学习项目开发实战 构建自动识别数字图像的程序 如果你打算建立一个当前技术热点的列表,机器学习当然会名列前茅.然而,虽然这个术语到处出现,但是它的真实含义往往含混不清.它是和"大数据"或者"数据科学"一样的东西吗?它和统计学有何不同之处?表面上,机器学习似乎是一种奇特.令人畏惧的专业,使用令人眼花缭乱的数学知识和算法,和软件工程师的日常活动没有多少共同之处. 在本章以及本书余下的部分中,我的目标是和大家一起完成实际项目,以此阐明机器学习的原理

《Arduino家居安全系统构建实战》——1.2 经典的机器学习问题:图像分类

1.2 经典的机器学习问题:图像分类 图像(特别是笔迹)识别是机器学习的一个经典问题.首先,这个问题有极其有益的应用.通过自动识别书信上的地址或者邮政编码,邮局就可以有效地分拣信件,免于人工进行这一乏味的工作:ATM机器如果能够识别金额,就可以在机器上存款,加快资金入账的速度,减少在银行排队的需求.想象一下,如果所有人类手写的文档都能够数字化,搜索和研究信息该有多么容易!其次,这个问题很难:人类的笔迹(即使是印刷体)有各种各样的变化(大小.形状.倾斜),人们可以毫无问题地识别不同人写的字母和数字