diff --git a/Chapter1/1.jpg b/Chapter1/1.jpg new file mode 100644 index 0000000..8df9b1b Binary files /dev/null and b/Chapter1/1.jpg differ diff --git a/Chapter1/2.jpg b/Chapter1/2.jpg new file mode 100644 index 0000000..52a39a8 Binary files /dev/null and b/Chapter1/2.jpg differ diff --git a/Chapter1/3.jpg b/Chapter1/3.jpg new file mode 100644 index 0000000..190ee5a Binary files /dev/null and b/Chapter1/3.jpg differ diff --git a/Chapter1/4.jpg b/Chapter1/4.jpg new file mode 100644 index 0000000..74e435c Binary files /dev/null and b/Chapter1/4.jpg differ diff --git a/Chapter1/5.jpg b/Chapter1/5.jpg new file mode 100644 index 0000000..5b59222 Binary files /dev/null and b/Chapter1/5.jpg differ diff --git a/Chapter1/大数据与数据挖掘.md b/Chapter1/大数据与数据挖掘.md new file mode 100644 index 0000000..6190475 --- /dev/null +++ b/Chapter1/大数据与数据挖掘.md @@ -0,0 +1,35 @@ +# 1.1 大数据与数据挖掘 + +## 大数据没那么神秘 + +最近几年不管大小企业、国企、私企、民企到处都在说大数据,各种的以大数据为名头的会议、活动也比比皆是,你方唱罢我登台,非常热闹。例如在网上搜“大数据会议”这个关键词,能看到今年已经举办了 1000 多场次关于大数据的会议和活动,可见热度非比寻常。 + +![](3.jpg) + +虽然很多公司宣称自己是大数据公司,但实际上呢?什么样的数据叫大,是 G 级还是 T 级、 P 级、 E级、Z级,还是 B 级?这个真的不太好定义,既然无法定义,那么反复强调自己的大数据,未免滑稽。其实,在国内,除了一些一二线互联网企业,许多宣称自己是大数据公司的数据量连 T 级都不到。在业界也有这样一种调侃的说法,一块硬盘可以打包公司所有数据的公司叫硬盘公司,一个皮包可以装载公司一切的叫皮包公司。 + +那么所谓的大数据是什么呢?其实就是数据仓库与数据挖掘。而且早在美国的 90 年代就已经有了这两个概念,现在只不过把它们两合在一起变得更加新潮了而已。 + +很多人都在宣传,大数据给相关公司带来业绩上翻天覆地的变化,而实际情况呢?如果不能很好地对数据做数据挖掘的话,大数据不但不能能给相关公司带来业绩上的任何变化,反而还会因为大量冗余数据给公司运维带来麻烦。数据只是死的,如果你不能从中找出有价值的内容,再“大”也没意义。其实数据量无论大小,如果能够很好地从数据中挖掘出一些有用的知识,那么就是非常有意义的。 + +所以说,大数据并没有那么神秘。 + +## 什么是数据挖掘 + +接下来,来介绍一下什么是数据挖掘。什么是数据挖掘?为了回答这个问题,有很多数据挖掘书籍都会提到一个经典案例:"尿布与啤酒"的故事。 + +![](1.jpg) + +在一家超市里,有一个有趣的现象:尿布和啤酒赫然摆在一起出售。但是这个奇怪的举措却使尿布和啤酒的销量双双增加了。这不是一个笑话,而是发生在美国沃尔玛连锁店超市的真实案例,并一直为商家所津津乐道。沃尔玛拥有世界上最大的数据仓库系统,为了能够准确了解顾客在其门店的购买习惯,沃尔玛对其顾客的购物行为进行购物篮分析,想知道顾客经常一起购买的商品有哪些。沃尔玛数据仓库里集中了其各门店的详细原始交易数据。在这些原始交易数据的基础上,沃尔玛利用数据挖掘方法对这些数据进行分析和挖掘。一个意外的发现是:"跟尿布一起购买最多的商品竟是啤酒!经过大量实际调查和分析,揭示了一个隐藏在"尿布与啤酒"背后的美国人的一种行为模式:在美国,一些年轻的父亲下班后经常要到超市去买婴儿尿布,而他们中有 30%~40% 的人同时也为自己买一些啤酒。产生这一现象的原因是:美国的太太们常叮嘱她们的丈夫下班后为小孩买尿布,而丈夫们在买尿布后又随手带回了他们喜欢的啤酒。按常规思维,尿布与啤酒风马牛不相及,若不是借助数据挖掘技术对大量交易数据进行挖掘分析,沃尔玛是不可能发现数据内在这一有价值的规律的。 + +相信你也看出来了,这就是数据挖掘,从常人的知识外找到线索,或者从五花八门的数据中找出一些潜在规律。通俗说,数据挖掘可以做到以下几点: + +- 找到没有意识到的问题 +- 找到未来发展的趋势 +- 找到过去存在的问题 +- 把定性的问题定量化 +- 数据对象关联的规则问题 +- 找到一些隐藏的资料 + +可想而知,这几点的威力是十分巨大的。而且在我们的日常生活中无时无刻都在享受着数据挖掘为我们带来的便利。 + diff --git a/Chapter1/数据挖掘的应用场景.md b/Chapter1/数据挖掘的应用场景.md index d49907b..1409a16 100644 --- a/Chapter1/数据挖掘的应用场景.md +++ b/Chapter1/数据挖掘的应用场景.md @@ -1,38 +1,90 @@ -# 1.3 数据挖掘的应用场景 +# 1.2 无处不在的数据挖掘 -数据挖掘技术可以为决策、过程控制、信息管理和查询处理等任务提供服务,一个有趣的应用范例是“尿布与啤酒”的故事。为了分析哪些商品顾客最有可能一起购买,一家名叫 WalMart 的公司利用自动数据挖掘工具,对数据库中的大量数据进行分析后,意外发现,跟尿布一起购买最多的商品竟是啤酒。为什么两件风马牛不相及的商品会被人一起购买?原来,太太们常叮嘱她们的丈夫,下班后为小孩买尿布,而丈夫们在买尿布后又随手带回了两瓶啤酒。既然尿布与啤酒一起购买的机会最多,商店就将它们摆放在一起,结果,尿布与啤酒的销售量双双增长。这里,数字挖掘技术功不可没。一般来说,数据挖掘的应用场景有电子政务、零售业、网站等,具体如下。 +“如何分辨出垃圾邮件”、“如何判断一笔交易是否属于欺诈”、“如何判断红酒的品质和档次”、“扫描王是如何做到文字识别的”、“如何判断佚名的著作是否出自某位名家之手”、“如何判断一个细胞是否属于肿瘤细胞”等等,这些问题似乎都很专业,都不太好回答。但是,如果了解一点点数据挖掘的知识,你或许会有柳暗花明的感觉。 +的确,数据挖掘无处不在。它和生活密不可分,就像空气一样,弥漫在你的周围。但是,很多时候,你并不能意识到它。因此,它是陌生的,也是熟悉的。而且,随着信息科技的进步,数据的收集变得十分便利。各式各样(手机、信用卡、浏览网页及部落格等)的信息,从不同的数据源,涌入我们预先设计好的数据仓储。这些信息透过数据挖掘的技术组合在一起,就可快速地勾勒出每个人对生活的品味、特征,并进一步影响我们的生活。 -# 1.3.1 电子政务 +在不久的将来,我们不难想象出这样一个场景。 -建立电子化政府,推动电子政务的发展,是电子信息技术应用到政府管理的必然趋势。实践经验表明,政府部门的决策越来越依赖于对数据的科学分析。发展电子政务,建立决策支持系统,利用电子政务综合数据库中存储的大量数据,通过建立正确的决策体系和决策支持模型,可以为各级政府的决策提供科学的依据,从而提高各项政策制定的科学性和合理性,以达到提高政府办公效率、促进经济发展的目的。为此,在政府决策支持方面,需要不断吸纳新的信息处理技术,而数据挖掘正是实现政府决策支持的核心技术。以数据挖掘为依托的政府决策支持系统,将发挥重要的作用。 +![](4.jpg) -电子政务位于世界各国积极倡导的“信息高速公路”五个领域(电子政务、电子商务、远程教育、远程医疗、电子娱乐)之首,说明政府信息化是社会信息化的基础。电子政务包括政府的信息服务、电子贸易、电子化政府、政府部门重构、群众参与政府五个方面的内容。将网络数据挖掘技术引入电子政务中,可以大大提高政府信息化水平,促进整个社会的信息化。具体体现在以下几个方面: +```python -- 政府的电子贸易 在服务器以及浏览器端日志记录的数据中隐藏着模式信息,运用网络用法挖掘技术可以自动发现系统的访问模式和用户的行为模式,从而进行预测分析。例如,通过评价用户对某一信息资源浏览所花费的时间,可以判断出用户对何种资源感兴趣;对日志文件所收集到的域名数据,根据国家或类型进行分类分析;应用聚类分析来识别用户的访问动机和访问趋势等。这项技术已经有效地运用在政府电子贸易中。 +客服:「xx披萨店您好!请问有什么需要我为您服务?」 -- 网站设计 通过对网站内容的挖掘,主要是对文本内容的挖掘,可以有效地组织网站信息,如采用自动归类技术实现网站信息的层次性组织;同时可以结合对用户访问日志记录信息的挖掘,把握用户的兴趣,从而有助于开展网站信息推送服务以及个人信息的定制服务,吸引更多的用户。 +顾客:「妳好,我想要....」 -- 搜索引擎 网络数据挖掘是目前网络信息检索发展的一个关键。如通过对网页内容挖掘,可以实现对网页的聚类、分类,实现网络信息的分类浏览与检索;同时,通过对用户所使用的提问式的历史记录的分析,可以有效地进行提问扩展,提高用户的检索效果;另外,运用网络内容挖掘技术改进关键词加权算法,提高网络信息的标引准确度,从而改善检索效果。 +客服:「x先生,请先告诉我您的会员卡号码!」 -- 决策支持 为政府重大政策出台提供决策支持。如,通过对网络各种经济资源的挖掘,确定未来经济的走势,从而制定出相应的宏观经济调控政策。 +顾客:「我的会员卡号码是xxxxxxxx」 -# 1.3.2 零售业 +客服:「x先生您好,您是住在康庄路xxx,您家电话是xxxxxxxx,您的移动电话是xxxxxxxxxx。请问这些信息是否有需要更新?」 -通过条形码、编码系统、销售管理系统、客户资料管理及其它业务数据中,可以收集到关于商品销售、客户信息、货存单位及店铺信息等的信息资料。数据从各种应用系统中采集,经条件分类,放到数据仓库里,允许高级管理人员、分析人员、采购人员、市场人员和广告客户访问,利用DM工具对这些数据进行分析,为他们提供高效的科学决策工具。如对商品进行购物篮分析,分析哪些商品是顾客最有希望一起购买的。如被业界和商界传诵的经典----Wal-Mart的 “啤酒和尿布”,就是数据挖掘透过数据找出人与物间规律的典型。在零售业应用领域,利用DW、DM会在很多方面有卓越表现: +顾客:「为什么妳知道我所有的电话号码?」 -- 了解销售全局:通过分类信息——按商品种类、销售数量、商店地点、价格和日期等了解每天的运营和财政情况,对销售的每一点增长、库存的变化以及通过促销而提高的销售额都可了如指掌。零售商店在销售商品时,随时检查商品结构是否合理十分重要,如每类商品的经营比例是否大体相当。调整商品结构时需考虑季节变化导致的需求变化、同行竞争对手的商品结构调整等因素。 +客服:「这是因为我们公司的顾客关系管理系统从海量数据中挖掘出了您的信息。」 -- 商品分组布局:分析顾客的购买习惯,考虑购买者在商店里所穿行的路线、购买时间和地点、掌握不同商品一起购买的概率;通过对商品销售品种的活跃性分析和关联性分析,用主成分分析方法,建立商品设置的最佳结构和商品的最佳布局。 +顾客:「我想要一个海鲜披萨」 -- 降低库存成本:通过数据挖掘系统,将销售数据和库存数据集中起来,通过数据分析,以决定对各个商品各色货物进行增减,确保正确的库存。数据仓库系统还可以将库存信息和商品销售预测信息,通过电子数据交换(EDI)直接送到供应商那里,这样省去商业中介,而且由供应商负责定期补充库存,零售商可减少自身负担。 +客服:「x先生,海鲜披萨不适合您!」 -- 市场和趋势分析:利用数据挖掘工具和统计模型对数据仓库的数据仔细研究,以分析顾客的购买习惯、广告成功率和其它战略性信息。利用数据仓库通过检索数据库中近年来的销售数据,作分析和数据挖掘,可预测出季节性、月销售量。 +顾客:「为什么?」 -有效的商品促销:可以通过对一种厂家商品在各连锁店的市场共享分析,客户统计以及历史状况的分析,来确定销售和广告业务的有效性。通过对顾客购买偏好的分析,确定商品促销的目标客户,以此来设计各种商品促销的方案,并通过商品购买关联分析的结果,采用交叉销售和向上销售的方法,挖掘客户的购买力,实现准确的商品促销。 +客服:「根据您的医疗纪录,您有高血压和胆固醇偏高的问题」 -# 1.3.3 网站 +顾客:「那....妳们有什么可以推荐的?」 -随着Web技术的发展,各类电子商务网站风起云涌。建立一个电子商务网站并不困难,困难的是如何让您的电子商务网站有效益。要想有效益就必须吸引客户,增加能带来效益的客户忠诚度。电子商务业务的竞争比传统的业务竞争更加激烈,原因有很多方面,其中一个因素是客户从一个电子商务网站转换到竞争对手那边,只需要点击几下鼠标即可。网站的内容和层次、用词、标题、奖励方案、服务等任何一个地方都有可能成为吸引客户、同时也可能成为失去客户的因素。而同时电子商务网站每天都可能有上百万次的在线交易,生成大量的记录文件(Log files)和登记表,如何对这些数据进行分析和挖掘,充分了解客户的喜好、购买模式,甚至是客户一时的冲动,设计出满足不同客户群体需要的个性化网站,进而增加其竞争力,几乎变得势在必行。若想在竞争中生存进而获胜,就要比您的竞争对手更了解客户。 +客服:「您可以试试我们的低脂健康披萨!」 -在对网站进行数据挖掘时,所需要的数据主要来自于两个方面:一方面是客户的背景信息,此部分信息主要来自于客户的登记表;而另外一部分数据主要来自浏览者的点击流(Click-stream),此部分数据主要用于考察客户的行为表现。但有的时候,客户对自己的背景信息十分珍重,不肯把这部分信息填写在登记表上,这就会给数据分析和挖掘带来不便。在这种情况之下,就不得不从浏览者的表现数据中来推测客户的背景信息,进而再加以利用。 +顾客:「妳怎么知道我会喜欢吃这种的?」 + +客服:「喔!因为您上星期一在中央图书馆借了一本《低脂健康食谱》」 + +顾客:「好...我要一个家庭号特大披萨,要多少钱?」 + +客服:「嗯?这个足够您一家十口吃,六百九十九元!」 + +顾客:「可以刷卡吗?」 + +客服:「林先生,对不起,请您付现!因为您的信用卡已经刷爆了。您现在还欠银行十万四千八百零七元,而且还不包括房贷利息!」 + +顾客:「喔!那我先去附近的提款机领钱!」 + +客服:「林先生,根据您的记录,您已经超过今日提款机提款限额!」 + +顾客:「算了!妳们直接把披萨送来吧!我这里有现金。妳们多久会送到?」 + +客服:「大约三十分钟,如果您不想等,可以自己骑车来!」 + +顾客:「什么?」 + +客服:「根据我们公司顾客关系管理系统的记录,您有一辆摩托车,车号是x-xxxxx.」 + +顾客:「#@$%^&$%^&※!」 + +客服:「林先生,请您说话小心一点。您在20xx年x月x日用脏话侮辱警察,被判了十日拘役!」 + +顾客:「......」 + +客服:「请问还需要什么吗?」 + +顾客:「没有了!是不是有三罐可乐免费赠送?」 + +客服:「是的!不过根据记录,您有糖尿病....」 + +``` + +由以上的例子可以看到,数据挖掘所带给我们思考上的冲击。同时,这样的场景并非遥不可及,而是逐渐、逐渐的在发生。例如大超市的手推车。 + +![](5.jpg) + +传统我们到大超市(如大润发、家乐福等)购物时,因为要买的东西很多,免不了要推一辆手推车。目前手推车的运作方式是你必需先投 1 元硬币,才能取出一辆手推车。当你将手推车推至定点归还时,就会退还你原先投的那个 1 元硬币。这样的方式方便手推车的管理,不会到处都有手推车。但手推车除了装载货物外,不能有其他的用途?新一代智能型手推车的出现,改变了我们的想法? + +新一代的智能型手推车结合了无线射频识别技术、室内定位及数据挖掘技术,将手推车的功能除了购物外,还能准确地预测你对产品的喜好,适时提供相关的优惠信息给你,以提高产品的交叉销售率,并提升顾客的价值。 + +当你要使用智能型手推车时,首先你需要先插入会员卡,以便辨认你的身份。利用无线射频识别技术,当你从货架上取得产品并放入手推车后,你购物的信息便已储存在大超市的数据库中。大超市的管理人员,也可随时并轻松地掌握整个超市货物的销售量及库存量,并适时订购即将缺货的商品。当你完成购物时,仅需直接至柜台缴款,并索取购物明细,即可完成交易,大大地简化整个管理及购物的流程。 + +利用室内定位技术,大超市的管理者可随时掌握每个顾客,以及手推车的购物动向。可了解大多数顾客的购物路径,在每个区域的停留时间。哪些区域是热门区,哪些乏人问津,哪些货品摆设的位置不对,都可透过这项技术发掘出来,大大地改善整个购物体验。 + + +从上面的例子可以看出,在我们的日常生活中,数据挖掘技术是无处不在的,而且随着技术的进步,会使得我们的生活越来越便利。 \ No newline at end of file diff --git a/Chapter2/数据与特征.md b/Chapter2/数据与特征.md new file mode 100644 index 0000000..3c6cc2c --- /dev/null +++ b/Chapter2/数据与特征.md @@ -0,0 +1,27 @@ +# 2.1 数据与特征 + +正所谓知己知彼,百战不殆。数据挖掘也一样,在对数据进行挖掘之前,首先要了解数据,知道数据长什么样子,数据中有哪些特征,这些特征的分布是怎样的,等等等等。本书中所指的数据默认指结构化数据(类似于excel 表格的数据)。 + + +一般而言,一个结构化数据一般由多条记录组成,而一条记录也一般由多个属性构成。如果将一个结构化数据看成是一个表格,那么表格中的每一行表示一条记录,而表格中的每一列表示数据的一个特征。 + +如下图所示的泰坦尼克数据中有 5 条数数据,数据有 12 个特征。当然,我们通常将属性称为特征。 + +![](1.jpg) + +根据特征的特点可以将其划分成**离散特征、顺序特征、数值特征**。 + +## 离散特征 + +离散特征,顾名思义即类别特征。注意:这里的类别指的是没有顺序的类别。如泰坦尼克数据集中的`Survived`、`Sex`、`Cabin`、`Embarked`都是离散特征。因为这些特征的值都代表某种类别。如`Sex`中的`male`和`female`分别代表男性和女性,而且男性与女性之间没有顺序关系。 + +## 顺序特征 + +顺序特征和离散特征一样都代表类别特征,只不过顺序特征表示的是具有顺序属性的类别特征。如泰坦尼克数据集中的`Pclass`、`SibSp`、`Parch`属于顺序特征。例如`Pclass`表示乘客的船舱的等级,`3、2、1`分别表示三等舱、二等舱和一等舱。很明显,一等舱的高级程度是高于其他两种舱的,所以是`Pclass`是顺序特征。 + +## 数值特征 + +数值特征表示的数值型特征,这就很好理解了。只要该特征的值是数值型的,则该特征为数值特征。如`Age`、`Fare`都是数值特征。 + + + diff --git a/Chapter2/数据的基本统计指标.md b/Chapter2/数据的基本统计指标.md index 81c1660..365f8a1 100644 --- a/Chapter2/数据的基本统计指标.md +++ b/Chapter2/数据的基本统计指标.md @@ -1,6 +1,6 @@ # 2.2 数据的基本统计指标 -在进行数据挖掘之前,通常需要先了解数据集中数据的分布。所谓的分布,就是查看数据集中特征的一些统计指标。常见的统计指标有均值,中值,标准差,方差等。 +在进行数据挖掘之前,通常需要先了解数据中特征值的分布。所谓的分布,就是查看数据中特征的一些统计指标。常见的统计指标有均值,中值,标准差,方差等。 假设现在有这样的一份长沙房价数据,并接下来使用这份数据来讲解什么是均值、中值、标准差和方差。 diff --git a/Chapter3/4.jpg b/Chapter3/4.jpg new file mode 100644 index 0000000..5c3f028 Binary files /dev/null and b/Chapter3/4.jpg differ diff --git a/Chapter3/5.jpg b/Chapter3/5.jpg new file mode 100644 index 0000000..f15136f Binary files /dev/null and b/Chapter3/5.jpg differ diff --git a/Chapter3/6.jpg b/Chapter3/6.jpg new file mode 100644 index 0000000..2dbacab Binary files /dev/null and b/Chapter3/6.jpg differ diff --git a/Chapter3/7.jpg b/Chapter3/7.jpg new file mode 100644 index 0000000..bfef7c1 Binary files /dev/null and b/Chapter3/7.jpg differ diff --git a/Chapter3/8.jpg b/Chapter3/8.jpg new file mode 100644 index 0000000..565151a Binary files /dev/null and b/Chapter3/8.jpg differ diff --git a/Chapter3/为什么要数据预处理.md b/Chapter3/为什么要数据预处理.md index 93e8448..bb31986 100644 --- a/Chapter3/为什么要数据预处理.md +++ b/Chapter3/为什么要数据预处理.md @@ -1,5 +1,11 @@ -# 3.1 为什么要数据预处理 +# 3.1 数据预处理的重要性 -数据挖掘其实就是从数据中学习到规律,再将学习到的规律对未知的数据进行分析。数据的质量直接影响到模型学习的好坏,而我们最开始获取的数据其中绝大多数是“有毛病”的,不利于后期进行分析。所以我们在分析前需要进行数据的预处理。 +数据挖掘其实就是从数据中学习到规律,再将学习到的规律对未知的数据进行分析。数据的质量直接影响到模型学习的好坏,而我们最开始获取的数据其中绝大多数是“有毛病”的,不利于后期进行分析。所以我们在分析前需要进行数据的预处理。为什么这么说呢?不妨看一下下面这样一个故事情节。 -`sklearn.preprocessing`包提供了几个常用的函数和转换类型,用它们将一个原始的特征向量转化为一个更适于数据分析的表示形式。一般来说,学习算法收益于数据集的标准形式。如果数据中存在异常点,稳健的数据规范或转换是更适合的。 \ No newline at end of file +比如有一天你的 boss 找到你说:XX 听说你对数据挖掘很熟悉啊,正好我们公司有很多 xx 方面的数据,你看看能不能做一个数据挖掘的项目为我们公司提供一些决策参考。你听到这里是高兴还是悲伤,具体因人而异(要是小弟听到了,绝对会很高兴)。我这里假设你很高兴,接到 boss 的圣旨以后你就屁颠屁颠的找公司的相关数据。毕竟手持 boss 的圣旨,所以数据获取应该不是太难,拿到数据你就开始疯狂的想使用什么模型呢?kNN,决策树,线性回归等等模型,你通过“认真”思考后选择了一个模型,迫不及待的把数据往里面喂。当你信心满满的点击 run 后,你会看到下面一行,一行,一行的红色字体,大体意思是这里数字无效,那里数据为空等等,这时候你的内心可能是崩溃的。 + +虽然仅仅是我编出来的一个故事场景,但是当我们真正地做数据挖掘时,在整个工程中,数据预处理所花费的精力是最多的。就好比,你是一个堪比中华小当家一样的名厨,当你拿到上等的新鲜食材时,你肯定能不费吹灰之力地做出美味佳肴。若尼拿到的是发酸发臭,品相不好的食材,你可能费了九牛二虎之力才能勉强赶上食堂大叔的做菜水准。 + +因此,数据预处理的效果有多好,基本上就决定了你数据挖掘的效果有多好。 + +在本章中,将介绍几种数据预处理的常用技巧的意义,以及如何使用`sklearn`来实现这些常用技巧。 diff --git a/Chapter3/估算缺失值.md b/Chapter3/估算缺失值.md index 3575b95..3b81ffd 100644 --- a/Chapter3/估算缺失值.md +++ b/Chapter3/估算缺失值.md @@ -1,20 +1,45 @@ -# 3.7 估算缺失值 +# 3.6 数据预处理常用技巧---估算缺失值 ## 为什么要估算缺失值 -由于各种原因,真实世界中的许多数据集都包含缺失数据,这类数据经常被编码成空格、`NaNs`,或者是其他的占位符。但是这样的数据集并不能被`sklearn`学习算法兼容,因为大多的学习算法都默认假设数组中的元素都是数值,因而所有的元素都有自己的意义。 使用不完整的数据集的一个基本策略就是舍弃掉整行或整列包含缺失值的数据。但是这样就付出了舍弃可能有价值数据(即使是不完整的 )的代价。 处理缺失数值的一个更好的策略就是从已有的数据推断出缺失的数值。 +由于各种原因,真实世界中的许多数据集都包含缺失数据,这类数据经常被编码成空格、`NaNs`,或者是其他的占位符。但是这样的数据集并不能被数据挖掘算法兼容,因为大多的学习算法都默认假设数组中的元素都是数值,因而所有的元素都有自己的意义。 -## Imputer +使用不完整的数据集的一个基本策略就是舍弃掉整行或整列包含缺失值的数据。但是这样就付出了舍弃可能有价值数据(即使是不完整的 )的代价。例如我有这样一份数据: + +| 性别 | 工资 | +|:-:|:-:| +| 男 | | +| 女 | | +| 女 | 5000 | +| 男 | | +| 男 | 6000 | +| 女 | | + +如果我们将带有缺失值的记录全部删掉的话,那么数据中就只有一条样本可以使用了,这时你会发现,就 2 条样本我挖掘什么啊? + +因此更好的处理缺失值的策略是,想办法将缺失值给补上,虽然有点亡羊补牢的意思,但是总比破罐子破摔强。 + +## 使用sklearn来处理缺失值 + +在`sklearn`中提供了接口`Imputer`来帮助我们快速的对缺失值进行填充。使用方法如下: -`sklearn`中使用`Imputer`方法估算缺失值,使用方法如下: ```python +# 导入Imputer类 from sklearn.preprocessing import Imputer +# 定义数据,np.nan表示缺失 data = [[np.nan, 2], [6, np.nan], [7, 4],[np.nan,4]] -imp = Imputer(missing_values='NaN', strategy='mean', axis=0)#缺失值为nan,沿着每一列,使用平均值来代替缺失值 + +# 实例化Imputer对象,missing_values表示我们将什么值看成是缺失,strategy表示按照什么样的方式来填充缺失值 + +# strategy='mean'表示填充缺失值时,使用列的均值来填充 +imp = Imputer(missing_values='NaN', strategy='mean', axis=0) + +# 填充缺失值 data = imp.fit_transform(data) +# 根据数据可知,第一列的均值是6.5,第二列的均值是3.33333,所以数据中缺失的部分就是使用的均值来进行填充的 >>>data array([[6.5 , 2. ], [6. , 3.33333333], @@ -22,16 +47,11 @@ array([[6.5 , 2. ], [6.5 , 4. ]]) ``` -其中`strategy`参数用来选择代替缺失值方法: - - `mean`表示使用平均值代替缺失值 - `median`表示使用中位数代替缺失值 - `most_frequent`表示使用出现频率最多的值代替缺失值 +当然,`Imputer`的填充策略不止`mean`这一种,还有两种策略如下: -`missing_values`参数表示何为缺失值: +- `median`表示使用中位数代替缺失值。 +- `most_frequent`表示使用出现频率最多的值代替缺失值。 - `NaN`表示`np.nan`为缺失值 - `0`表示`0`为缺失值 diff --git a/Chapter3/归一化.md b/Chapter3/归一化.md index fa0c094..d50d63a 100644 --- a/Chapter3/归一化.md +++ b/Chapter3/归一化.md @@ -1,54 +1,77 @@ -# 3.4 归一化 +# 3.3 数据预处理常用技巧---归一化 +## 归一化与标准化 -## 为什么使用归一化 +归一化是缩放**单个样本**以具有**单位范数**的过程。也就是说,上一节中提到的标准化是对数据中的每一列进行计算,而本节中提到的归一化则是对数据中的每一行进行计算。 + +一般来说,当我们想要计算两个样本之间的相似度之前,可以尝试一下使用归一化来作为计算相似度之前的预处理,因为有可能会使得相似度计算地更加准确。 + +在实践中,用的最多的是**L1范式归一化**和**L2范式归一化**,下面来详细看看这两种归一化是怎样计算的。 -归一化是缩放**单个样本**以具有**单位范数**的过程。归一化实质是一种线性变换,线性变换有很多良好的性质,这些性质决定了对数据改变后不会造成“失效”,反而能提高数据的表现,这些性质是归一化的前提。归一化能够**加快模型训练速度**,**统一特征量纲**,**避免数值太大**。值得注意的是,归一化是对每一个样本做转换,所以是**对数据的每一行进行变换**。而之前我们讲过的方法是对数据的每一列做变换。 ## L1范式归一化 + `L1`范式定义如下: + $$ ||x||_1=\sum_{i=1}^n|x_i| $$ -表示向量`x`中每个元素的绝对值之和。 -`L1`范式归一化就是将样本中每个特征**除以**特征的`L1`范式。 +表示数据`x`中每个特征值`xi`的绝对值之和。 + +因此,`L1`范式归一化就是将样本中每个特征的特征值**除以**`L1`范式。虽然这个功能实现起来简单,但我们也不必重新造轮子。在`sklearn`中已经提供了该功能,即`normalize`函数,用法如下: + -在`sklearn`中使用`normalize`方法实现,用法如下: ```python +# 导入normalize函数 from sklearn.preprocessing import normalize +# 定义数据,数据中有3条样本,每条样本中有3个特征 data = np.array([[-1,0,1], [1,0,1], [1,2,3]]) + +# 使用normalize函数进行L1范式归一化 +# data即想要归一化的数据, l1即表示想要使用L1范式归一化来进行归一化处理 data = normalize(data,'l1') +# 可以分析一下:第一行的L1范数是不是2,在归一化完了之后,第一行第一列的值是不是-0.5 >>>data array([[-0.5 , 0. , 0.5 ], [ 0.5 , 0. , 0.5 ], [ 0.167, 0.333, 0.5 ]]) ``` + + ## L2范式归一化 + + `L2`范式定义如下: + $$ ||x||_2=\sqrt{\sum_{i=1}^nx_i^2} $$ +表示数据`x`中每个特征值`xi`计算平方和再开跟。 -表示向量元素的平方和再开平方根。 -`L2`范式归一化就是将样本中每个特征**除以**特征的`L2`范式。 +因此,`L2`范式归一化就是将样本中每个特征**除以**特征的`L2`范式。在`sklearn`中已经提供了该功能,即`normalize`函数,用法如下: -在`sklearn`中使用`normalize`方法实现,用法如下: ```python +# 导入normalize函数 from sklearn.preprocessing import normalize +# 定义数据,数据中有3条样本,每条样本中有3个特征 data = np.array([[-1,0,1], [1,0,1], [1,2,3]]) + +# 使用normalize函数进行L2范式归一化 +# data即想要归一化的数据, l2即表示想要使用L2范式归一化来进行归一化处理 data = normalize(data,'l2') +# 可以分析一下:第一行的L1范数是不是根号2,在归一化完了之后,第一行第一列的值是不是-0.707 >>>data array([[-0.707, 0. , 0.707], [ 0.707, 0. , 0.707], diff --git a/Chapter3/标准化.md b/Chapter3/标准化.md index 93d10ed..17d1dfa 100644 --- a/Chapter3/标准化.md +++ b/Chapter3/标准化.md @@ -1,67 +1,95 @@ -# 3.2 标准化 +# 3.2 数据预处理常用技巧---标准化 ## 为什么要进行标准化 -对于大多数数据挖掘算法来说,数据集的标准化是基本要求。这是因为,如果特征不服从或者近似服从标准正态分布(即,零均值、单位标准差的正态分布)的话,算法的表现会大打折扣。实际上,我们经常忽略数据的分布形状,而仅仅做零均值、单位标准差的处理。在一个机器学习算法的目标函数里的很多元素所有特征都近似零均值,方差具有相同的阶。如果某个特征的方差的数量级大于其它的特征,那么,这个特征可能在目标函数中占主导地位,这使得模型不能从其它特征有效地学习。 +对于大多数数据挖掘算法来说,数据集的标准化是基本要求。这是因为有些数据挖掘算法中需要计算距离或梯度等信息,而这些信息需要数据中的特征处于同一量纲内才会有比较好的效果。 +比如现在问你个问题,是 1000 克的棉花重,还是 1 公斤的铁重?你肯定能不假思索的回答:一样重!但是,有些数据挖掘算法会觉得 1000 克的棉花重,因为它并不会看 1000 后面的单位是克还是公斤。所以如果想要使用这类算法来进行数据挖掘,那么首先要做的事情就是对数据进行标准化,因为标准化能够解决特征量纲不一致的问题。 ## Z-score标准化 -这种方法基于原始数据的均值`mean`和标准差`standard deviation`进行数据的标准化。对特征`A`的原始值`x`使用`z-score`标准化,将其值标准化为到`x’`。`z-score`标准化方法适用于特征`A`的最大值和最小值未知的情况,或有超出取值范围的离群数据的情况。将数据按其特征(按列进行)减去其均值,然后除以其方差。最后得到的结果是,对每个特征/每列来说所有数据都聚集在`0`附近,方差值为`1`。数学公式如下: +这种方法基于原始数据的均值和标准差进行数据的标准化。对特征`A`的原始值`x`使用`z-score`标准化,将其值标准化为到`x’`。`z-score`标准化方法适用于特征`A`的最大值和最小值未知的情况,或有超出取值范围的离群数据的情况。将数据按其特征(按列进行)减去其均值,然后除以其方差。最后得到的结果是,对每个特征/每列来说所有数据都聚集在`0`附近,方差值为`1`。数学公式如下: $$ x^,=\frac{x-x_{mean}}{x_{std}} $$ -函数`scale`为数组形状的数据集的标准化提供了一个快捷实现: +`sklearn`的`preprocessing`模块中的函数`scale`实现了`Z-score`标准化的功能。实例代码如下: + ```python +# 导入preprocessing模块 from sklearn import preprocessing +# 导入numpy库 import numpy as np + +# 定义数据,该数据中有3条记录,每条记录有3个特征 X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) + +# 对数据进行z-score标准化,并将结果保存至X_scaled X_scaled = preprocessing.scale(X_train) +# z-score标准化的结果 >>>X_scaled array([[ 0. ..., -1.22..., 1.33...], [ 1.22..., 0. ..., -0.26...], [-1.22..., 1.22..., -1.06...]]) ``` -经过缩放后的数据具有零均值以及标准方差: + +从结果上看,可以看出`scale`函数好像起了作用,为了验证标准化是否正确,我们可以检查一下`X_scaled`的均值和方差。代码如下: + ```python +# 计算X_scaled中每个特征的均值,发现全是0 >>> X_scaled.mean(axis=0) array([ 0., 0., 0.]) +# 计算X_scaled中每个特征的方差,发现全是1 >>> X_scaled.std(axis=0) array([ 1., 1., 1.]) ``` +嗯,不错,`scale`成功地对数据进行了标准化。 + ## Min-max标准化 `Min-max`标准化方法是对原始数据进行线性变换。设`minA`和`maxA`分别为特征`A`的最小值和最大值,将`A`的一个原始值`x`通过`min-max`标准化映射成在区间`[0,1]`中的值`x'`,其公式为: $$ -x^, = \frac{x-x_{min}}{x_{max}-x{min}} +x^, = \frac{x-x_{min}}{x_{max}-x_{min}} $$ -可以使用`MinMaxScaler`实现,以下是一个将简单的数据矩阵缩放到`[0, 1]`的例子: + +`sklearn`的`preprocessing`模块中的`MinMaxScaler`类的`fit_transform`函数实现了`Min-max`标准化的功能。实例代码如下: + ```python +# 导入preprocessing模块 +from sklearn import preprocessing +# 导入numpy库 +import numpy as np + +# 定义数据,该数据中有3条记录,每条记录有3个特征 X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) +# 实例化MinMaxScaler对象 min_max_scaler = preprocessing.MinMaxScaler() +# 对数据进行Min-max标准化,并将结果保存至X_train_minmax X_train_minmax = min_max_scaler.fit_transform(X_train) +# Min-max标准化的结果 >>> X_train_minmax array([[ 0.5 , 0. , 1. ], [ 1. , 0.5 , 0.33333333], [ 0. , 1. , 0. ]]) ``` +可以看出,经过`Min-max`标准化后,数据中的所有特征值都缩放到了`[0, 1]`的区间内。 + ## MaxAbs标准化 @@ -71,19 +99,30 @@ $$ x^, = \frac{x}{x_{max}} $$ -以下是使用上例中数据,并对其进行`MaxAbs`标准化的例子: +`sklearn`的`preprocessing`模块中的`MaxAbsScaler`类的`fit_transform`函数实现了`MaxAbs`标准化的功能。实例代码如下: ```python +# 导入preprocessing模块 +from sklearn import preprocessing +# 导入numpy库 +import numpy as np + +# 定义数据,该数据中有3条记录,每条记录有3个特征 X_train = np.array([[ 1., -1., 2.], [ 2., 0., 0.], [ 0., 1., -1.]]) +# 实例化MaxAbsScaler对象 max_abs_scaler = preprocessing.MaxAbsScaler() +# 对数据进行MaxAbs标准化,并将结果保存至X_train_maxabs X_train_maxabs = max_abs_scaler.fit_transform(X_train) +# MaxAbs标准化的结果 >>> X_train_maxabs array([[ 0.5, -1. , 1. ], [ 1. , 0. , 0. ], [ 0. , 1. , -0.5]]) ``` +可以看出,经过`MaxAbs`标准化后,数据中的所有特征值都缩放到了`[-1, 1]`的区间内。 + diff --git a/Chapter3/生成多项式特征.md b/Chapter3/生成多项式特征.md index cae58e8..33cbe38 100644 --- a/Chapter3/生成多项式特征.md +++ b/Chapter3/生成多项式特征.md @@ -1,44 +1,84 @@ -# 3.6 生成多项式特征 +# 3.5 数据预处理常用技巧---生成多项式特征 -## 为什么需要多项式特征 +## 引例 -在数据挖掘中,获取数据的代价经常是非常高昂的。所以有时就需要人为的制造一些特征,并且有的特征之间是有关联的。生成多项式特征可以轻松的为我们获取更多的数据,并获得特征的更高维度和互相间关系的项且引入了特征之间的非线性关系,可以有效的增加模型的复杂度。 +假设现在给了你一份数据,数据的分布如下图所示(其中横轴代表神秘特征`X`的值,纵轴代表与`X`所对应的目标值`Y`,也就是说纵轴的值可以根据`X`以及一种映射关系计算出来): + +![](6.jpg) + + +我想让你根据`X`来将`Y`算出来,此时,你观察数据的分布,认为数据的分布有点像一条直线,所以你可能会使用一条直线来来表示这些数据的分布,如下图中红色的直线: + +![](7.jpg) + +但是你会发现,红色的直线好像并不能很好的表示数据的分布,毕竟数据的分布像是一个弯弯的勾号,如果能根据特征`X`,使得这条直线能“打勾”就好了。如下图所示: + +![](8.jpg) + +这个时候,我们就可以试试生成多项式特征了。即将原来的“直线”给“掰弯”。 + + +## 使用sklearn来生成多项式特征 + +在`sklearn`中通过`PolynomialFeatures`来生成多项式特征,使用方法如下: -## PolynomialFeatures -在`sklearn`中通过`PolynomialFeatures`方法来生成多项式特征,使用方法如下: ```python import numpy as np +# 导入PolynomialFeatures类 from sklearn.preprocessing import PolynomialFeatures +# 定义数据: +# [[0, 1] +# [2, 3] +# [4, 5]] data = np.arange(6).reshape(3, 2) -poly = PolynomialFeatures(2)#生成二项式特征 + +# 实例化PolynomialFeatures的对象,多项式的阶为2阶 +poly = PolynomialFeatures(degree=2) + +# 添加多项式特征 data = poly.fit_transform(data) +# 添加之后的结果 >>>data array([[ 1., 0., 1., 0., 0., 1.], [ 1., 2., 3., 4., 6., 9.], [ 1., 4., 5., 16., 20., 25.]]) ``` -特征转换情况如下: + +你会看到原始数据中只有 2 个特征,而添加完多项式特征之后,特征数量增加到了 6 个。这是因为在生成多项式特征时会将原始的两个特征$$(x_1, x_2)$$,先扩展成$$(1, x_1, x_2)$$,记为 X ,然后将两个 X 中的元素两两相乘,相乘后会得到$$1, x_1, x_2, x_1x_2, x_1^2, x_2^2$$,即转换过程如下图所示: ![](2.jpg) -在一些情况下,只需要特征间的交互项,这可以通过设置 `interaction_only=True`来得到: +所以特征数量会增加到 6 个。但是在一些情况下,我们只需要特征间的交互项,这可以通过设置 `interaction_only=True`来得到: + ```python import numpy as np +# 导入PolynomialFeatures类 from sklearn.preprocessing import PolynomialFeatures +# 定义数据: +# [[0, 1] +# [2, 3] +# [4, 5]] data = np.arange(6).reshape(3, 2) -poly = PolynomialFeatures(degree=2, interaction_only=True)#degree=n表示生成n项式特征,只需要特征之间交互 + +# 实例化PolynomialFeatures的对象,多项式的阶为2阶,并只保留交叉项 +poly = PolynomialFeatures(degree=2, interaction_only=True) + +# 添加多项式特征 data = poly.fit_transform(data) +# 添加之后的结果 >>>data array([[ 1., 0., 1., 0.], [ 1., 2., 3., 6.], [ 1., 4., 5., 20.]]) ``` + 特征转换情况如下: ![](3.jpg) +所以`interaction_only`为`True`时,特征的数量只增加到了 4 。 diff --git a/Chapter3/离散值编码.md b/Chapter3/离散值编码.md index e0793ce..c735d7a 100644 --- a/Chapter3/离散值编码.md +++ b/Chapter3/离散值编码.md @@ -1,64 +1,107 @@ -# 3.5 离散值编码 +# 3.4 数据预处理常用技巧---离散值编码 + +## 离散值编码的目的 + +想要知道离散值编码的目的,那么首先需要知道什么是离散值。离散值的概念其实你并不陌生,因为早在第 2 章第 1 节中你就已经接触到了离散值的概念,没错!就是离散特征! + +要知道,不管是数据挖掘还是机器学习算法,它们都只认识数字,一到碰到诸如字符串之类的数据时就会向你抱怨:我太难了! + +![](5.jpg) + +所以当我们碰到带有离散值的数据时,我们就要想办法来把这些离散值进行转换,转换成算法所认识的数字。 + +在进行离散值编码时,通常会尝试使用如下两种方法,`LabelEncoder`和`OneHotEncoder`。下面,我们会试图使用这两种编码方法来解决数据中的离散值编码问题。 ## LabelEncoder -在数据挖掘中,特征经常不是数值型的而是分类型的。举个例子,一个人可能有`["male", "female"]`,`["from Europe", "from US", "from Asia"]`,`["uses Firefox", "uses Chrome", "uses Safari", "uses Internet Explorer"]`等分类的特征。这些特征能够被有效地编码成整数,比如`["male", "from US", "uses Internet Explorer"]`可以被表示为`[0, 1, 3]`,`["female", "from Asia", "uses Chrome"]`表示为`[1, 2, 1]`。 +这种方法会对特征中所出现的离散值建立一种映射关系。这种映射关系很简单,例如数据中有`Sex`这一特征,并且该特征中的值的值要么是`male`,要么是`female`。如果我们对`Sex`特征使用`LabelEncoder`方法进行离散值编码的话,可能会得到一个映射关系:`{'male':0, 'female':1}`,即当看到`'male'`时就将其改成`0`,看到`'female'`时将其改成`1`。 + +因此进行编码后的结果为: + +| Sex | +|:-:| +| 0 | +| 1 | +| 1 | +| 1 | +| 0 | + +这样,就成功地将字符串类型的特征值转换成了数值类型的特征值。 + +当然,`sklearn`已经为我们提供了实现该功能的接口:`LabelEncoder`,使用案例如下: -在`sklearn`中,通过`LabelEncoder`来实现: ```python + +# 导入LabelEncoder类 from sklearn.preprocessing import LabelEncoder +# 定义数据 label = ['male','female'] + +# 实例化LabelEncoder对象 int_label = LabelEncoder() + +# 进行离散值编码 label = int_label.fit_transform(label) +# 成功将male转换成0,将female转换成1 >>>label -array([1, 0]) +array([0, 1]) ``` ## OneHotEncoder -这种整数特征表示并不能在`sklearn`的估计器中直接使用,因为这样的连续输入,估计器会认为类别之间是有序的,但实际却是无序的。如将`male,female`,转换为`1,0`。`1`比`0`要大,机器就会把这个关系考虑进去,而`male,female`之间是没有这样的关系的。所以我们需要使用另外一种编码方式,`OneHot`编码。 +虽然`LabelEncoder`能将代表不同意义的字符串转换成数字,但是在转换之后很可能会带入顺序信息。比如将`‘male’`映射成`0`,`'female'`映射成`1`时,有可能会使得数据挖掘算法认为`'female'`更重要,或者`‘male’`和`'female'`之间存在着一定的大小关系。 -`OneHot`编码其实非常简单,就是在将原来的特征展开成一个二进制列,假设`sex`这个特征有两种取值,分别为:`male`和`female`。数据如下: +我们知道,现在是男女平等的时代,不应该出现男权或者女权的现象。那应该怎样避免将特征值分成三六九等呢?我们可以使用`OneHotEncoder`方法来进行离散值编码。 -| id | sex | -|:-:|:-:| -| 1 | male | -| 2 | male | -| 3 | female | -| 4 | male | -| 5 | female | -那么经过`OneHot`编码之后,数据会变成如下形式(原来数据中`sex`为`male`的在编码后`sex_male`的值为`1`,`sex`为`female`的在编码后`sex_female`的值为`1`): +`OneHotEncoder`其实非常简单,就是在将原来的特征展开成一个二进制列,假设`sex`这个特征有两种取值,分别为:`male`和`female`。数据如下: +| sex | +|:-:| +| male | +| male | +| female | +| male | +| female | -| id | sex_male | sex_female| -|:-:|:-:|:-:| -| 1 | 1 | 0 | -| 2 | 1 | 0 | -| 3 | 0 | 1 | -| 4 | 1 | 0 | -| 5 | 0 | 1 | +那么经过`OneHotEncoder`编码之后,数据会变成如下形式(原来数据中`sex`为`male`的在编码后`sex_male`的值为`1`,`sex`为`female`的在编码后`sex_female`的值为`1`): + + +| sex_male | sex_female| +|:-:|:-:| +| 1 | 0 | +| 1 | 0 | +| 0 | 1 | +| 1 | 0 | +| 0 | 1 | -你会发现,经过`OneHot`编码后,`sex`特征变成了无序的二进制特征。当然,在`sklearn`中已经为我们提供了`OneHot`编码的接口。可以通过`OneHotEncoder`来实现,使用方法如下: +你会发现,经过`OneHotEncoder`编码后,`sex`特征变成了无序的二进制特征。而且能够轻松的看出第一条样本的性别是`male`,第三条样本的性别是`female`。 + +当然,`sklearn`已经为我们提供了实现该功能的接口:`OneHotEncoder`,使用案例如下: ```python import numpy as np +# 导入OneHotEncoder类 from sklearn.preprocessing import OneHotEncoder -label = np.array([1,0]) -label = np.array(label).reshape(len(label),1)#先将X组织成(sample,feature)的格式 + +# 定义数据 +label = ['male','female'] + # 实例化OneHotEncoder对象 onehot_label = OneHotEncoder() + # 对数据进行编码 -label = onehot_label.fit_transform(label).toarray() +label = onehot_label.fit_transform(label) +# 样本的特征变成了2个,分别表示male和female >>>label -array([[0., 1.], - [1., 0.]]) +array([[1, 0], + [0, 1]]) ``` diff --git a/Chapter4/1.jpg b/Chapter4/1.jpg new file mode 100644 index 0000000..50a7c88 Binary files /dev/null and b/Chapter4/1.jpg differ diff --git a/Chapter4/k-近邻算法原理.md b/Chapter4/k-近邻算法原理.md index fb3ff8f..750ed27 100644 --- a/Chapter4/k-近邻算法原理.md +++ b/Chapter4/k-近邻算法原理.md @@ -1,6 +1,19 @@ -# 4.2 k-近邻算法原理 +# 4.2 k近邻算法原理 -我们已经知道,如何判别一个样本属于哪个类型,主要是看离它最近的几个样本中哪个类型的数量最多,则该样本属于数量最多的类型。这里,存在两个问题: +古人云:“近朱者赤,近墨者黑”。意思是说如果一个人身边的朋友中坏人比较多,那么这个人很可能也是坏人,如果身边的朋友中好人比较多,那么他很可能也是个好人。其实k近邻算法的核心思想就是这一句古话。 + +![](knn1.jpg) + +如上图,当`k=3`时离绿色的圆最近的三个样本中,有两个红色的三角形,一个蓝色的正方形,则此时绿色的圆应该分为红色的三角形这一类。 + +也就是说,如果三角形是好人,正方形是坏人,那么绿色的圆就是好人,因为与绿色的圆关系最紧密的三个人中有两个是好人。 + +而当`k=5`时,离绿色的圆最近的五个样本中,有两个红色的三角形,三个蓝色的正方形,则此时绿色的圆应该分为蓝色的正方形这一类。 + +同样,如果三角形是好人,正方形是坏人,那么绿色的圆就是坏人,因为与绿色的圆关系最紧密的五个人中有三个是坏人。 + + +OK,现在我们已经知道,如何判别一个样本属于哪个类型,主要是看离它最近的几个样本中哪个类型的数量最多,则该样本属于数量最多的类型。这里,存在两个问题: - 何为最近 - 如果有两个类型的样本数一样且最多,那么最终该样本应该属于哪个类型 @@ -43,7 +56,7 @@ $$ ### 加权投票 -`knn`算法最后决定样本属于哪个类别,其实好比就是在投票,哪个类别票数多,则该样本属于哪个类别。而如果出现票数相同的情况,我们可以给每一票加上一个权重,用来表示每一票的重要性,这样就可以解决票数相同的问题了。很明显,距离越近的样本所投的一票应该越重要,此时我们可以将距离的倒数作为权重赋予每一票。 +k近邻算法最后决定样本属于哪个类别,其实好比就是在投票,哪个类别票数多,则该样本属于哪个类别。而如果出现票数相同的情况,我们可以给每一票加上一个权重,用来表示每一票的重要性,这样就可以解决票数相同的问题了。很明显,距离越近的样本所投的一票应该越重要,此时我们可以将距离的倒数作为权重赋予每一票。 ![](knn7.jpg) diff --git a/Chapter4/动手实现k-近邻.md b/Chapter4/动手实现k-近邻.md index a1947d2..6265e49 100644 --- a/Chapter4/动手实现k-近邻.md +++ b/Chapter4/动手实现k-近邻.md @@ -1,6 +1,6 @@ -# 4.4 动手实现k-近邻 +# 4.3 动手实现k近邻 -`knn`算法实现`python`代码如下: +k近邻算法非常简单,可以很方便的使用`python`实现,实现代码如下: ```python #encoding=utf8 diff --git a/Chapter4/品鉴红酒.md b/Chapter4/品鉴红酒.md new file mode 100644 index 0000000..6b5b6e8 --- /dev/null +++ b/Chapter4/品鉴红酒.md @@ -0,0 +1,38 @@ +# 4.5 检测红酒品质 + +## 数据预处理 + +在使用k近邻算法进行检测之前,我们可以先查看一下各个特征的均值和标准差。 + +```python +[1.30006180e+01 2.33634831e+00 2.36651685e+00 1.94949438e+01 9.97415730e+01 2.29511236e+00 2.02926966e+00 3.61853933e-01 1.59089888e+00 5.05808988e+00 9.57449438e-01 2.61168539e+00 7.46893258e+02] + +[8.09542915e-01 1.11400363e+00 2.73572294e-01 3.33016976e+00 1.42423077e+01 6.24090564e-01 9.96048950e-01 1.24103260e-01 5.70748849e-01 2.31176466e+00 2.27928607e-01 7.07993265e-01 3.14021657e+02] +``` + +从打印结果可以看出,有的特征的均值和标准差都比较大,例如如最后一个特征。如果现在用k近邻算法来对这样的数据进行分类的话,k近邻算法会认为最后一个特征比较重要。因为假设有两个样本的最后一个特征值分别为`1`和`100`,那么这两个样本之间的距离可能就被这最后一个特征决定了。这样就很有可能会影响k近邻算法的准确度。为了解决这种问题,我们可以对数据进行标准化。标准化的知识,以及如何实现标准化在第三章已经向你介绍过了,相信你对这些知识已经很熟悉了,在这里就不多赘述了。 + + +## 检测品质 + +接下来就只需要调用之前实现的`knn_clf`方法就可以对测试集中的红数据进行品质检测了: + +```python +predict = knn_clf(3,train_feature,train_label,test_feature) +predict +>>>array([6, 5, 4, 7, 4, 3, 6, 4, 5, 4, 9, 2, 7, 8, 4, 6, 9, 5, 7, 4, 7, 5, + 8, 6, 0, 9, 6, 4, 5, 7, 5, 9, 8, 6, 4, 8, 8, 5, 5, 6, 7, 9, 4, 6, + 8, 7, 6, 7, 4, 5, 4, 5, 4, 2, 4, 7, 0, 5, 5, 5, 4, 6, 7, 8, 5, 6, + 8, 5, 5, 4, 6, 3, 7, 4, 3, 4, 6, 9, 7, 7, 8, 5, 6, 5, 6, 5, 5, 4, + 9, 7, 7, 6, 8, 8, 6, 8, 5, 7, 4, 6, 8, 8, 5, 4, 6, 5, 6, 9, 9, 5]) +``` + +再根据测试集标签即真实分类结果,计算出正确率: + +```python +acc = np.mean(predict==test_label) +acc +>>>0.994 +``` + +可以看到,使用k近邻算法检测红酒品质,正确率能达到`99%`以上。此时此刻,我相信,红酒鉴定师的烦恼要从活太多干不完,转变成以后可能没活干了。 \ No newline at end of file diff --git a/Chapter4/问题的本质.md b/Chapter4/问题的本质.md new file mode 100644 index 0000000..dece304 --- /dev/null +++ b/Chapter4/问题的本质.md @@ -0,0 +1,20 @@ +# 4.1 问题的本质 + +## 红酒鉴定家的烦恼 + +身为一为红酒鉴定师,每天打交道打得最多的肯定就是红酒啦。一为合格的红酒鉴定师能根据红酒的颜色、气味、口感、酿造时间、木桶的材质等一系列信息准确的推测出该红酒的品质。 + +但是人总是喜欢偷懒,当需要在短时间内鉴定大量红酒的品质时,就算是久经沙场的红酒鉴定师,也会觉得心有余而力不足。 + +如果我们能够使用一种方法,该方法能够根据红酒品质的历史数据来推测出现在需要鉴定的红酒的品质的话,那么红酒鉴定师就可以悠闲地坐在沙发上喝咖啡了。 + +下面是红酒鉴定师收藏多年的红酒数据中的冰山一角,数据中包含了红酒的颜色,酸碱度,酒精度等信息。其中`quality`表示红酒的品质(该特征是离散特征),数字的值越大,表示红酒的品质越高。 + +![](1.jpg) + +## 抓住主要矛盾 + +现在我们想要得到一种算法,自动的能根据红酒的颜色、酸碱度、酒精度等信息来推算出该红酒的品质。而品质这一属性是一种离散值。假设红酒的品质分为 1 到 9 ,9 个等级。那么我们的算法要的事情就是输出 1 到 9 之间的一个数字即可。像这种需要输出离散值的算法,我们通常称之为**分类**算法。(如果将 9 个等级看成是 9 种类别,可以思考一下算法的输出是不是相当于在做分类的事情。) + +作为正式接触数据挖掘算法的第一章,本章的算法应该尽量简单,有效。所以本章将使用k近邻算法来完成红酒品质检测的功能。因为k近邻算法的思想是众多数据挖掘算法中最简单的,非常适合入门。如果你准备好了,请继续往下看。 + diff --git a/SUMMARY.md b/SUMMARY.md index a4ae31c..06f148e 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -2,27 +2,24 @@ * [前言](README.md) * [第一章 绪论](Chapter1/README.md) - * [1.1 为什么要数据挖掘](Chapter1/数据挖掘简介.md) - * [1.2 什么是数据挖掘](Chapter1/数据挖掘所用到的技术.md) - * [1.3 数据挖掘主要任务](Chapter1/数据挖掘的应用场景.md) + * [1.1 大数据与数据挖掘](Chapter1/大数据与数据挖掘.md) + * [1.2 无处不在的数据挖掘](Chapter1/无处不在的数据挖掘.md) * [第二章 认识数据](Chapter2/README.md) * [2.1 数据与属性](Chapter2/数据与属性.md) * [2.2 数据的基本统计指标](Chapter2/数据的基本统计指标.md) * [2.3 数据可视化](Chapter2/数据可视化.md) * [第三章 数据预处理](Chapter3/README.md) * [3.1 为什么要数据预处理](Chapter3/为什么要数据预处理.md) - * [3.2 标准化](Chapter3/标准化.md) - * [3.3 非线性变换](Chapter3/非线性变换.md) - * [3.4 归一化](Chapter3/归一化.md) - * [3.5 离散值编码](Chapter3/离散值编码.md) - * [3.6 生成多项式特征](Chapter3/生成多项式特征.md) - * [3.7 估算缺失值](Chapter3/估算缺失值.md) -* [第四章 k-近邻](Chapter4/README.md) - * [4.1 k-近邻算法思想](Chapter4/k-近邻算法思想.md) - * [4.2 k-近邻算法原理](Chapter4/k-近邻算法原理.md) - * [4.3 k-近邻算法流程](Chapter4/k-近邻算法流程.md) - * [4.4 动手实现k-近邻](Chapter4/动手实现k-近邻.md) - * [4.5 实战案例](Chapter4/实战案例.md) + * [3.2 数据预处理常用技巧---标准化](Chapter3/标准化.md) + * [3.3 数据预处理常用技巧---归一化](Chapter3/归一化.md) + * [3.4 数据预处理常用技巧---离散值编码](Chapter3/离散值编码.md) + * [3.5 数据预处理常用技巧---生成多项式特征](Chapter3/生成多项式特征.md) + * [3.6 数据预处理常用技巧---估算缺失值](Chapter3/估算缺失值.md) +* [第四章 使用k近邻算法检测红酒品质](Chapter4/README.md) + * [4.1 问题的本质](Chapter4/问题的本质.md) + * [4.2 k近邻算法原理](Chapter4/k-近邻算法原理.md) + * [4.3 动手实现k近邻算法](Chapter4/动手实现k-近邻.md) + * [4.4 检测红酒品质](Chapter4/品鉴红酒.md) * [第五章 线性回归](Chapter5/README.md) * [5.1 线性回归算法思想](Chapter5/线性回归算法思想.md) * [5.2 线性回归算法原理](Chapter5/线性回归算法原理.md)