中怎么样成功再三再四时间段的拆分,数据解析案例

前几日在职业中际遇了二个很实际的难点,客户在OA接口的职员和工人间休息假中间表中提供了延续时间段的休假记录,例如:
张3,201八-1二-一 ~201捌-1二-31,病假,31天。那样拉动的标题是,假如自身索要总计张三从五月一号到二月一五号的假期天数,单从这一整条连接记录是无能为力计算的。这时候就须要大家将一条长记录实行拆分。

转载http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html


 Hash表(那篇小说转载,认为还集聚,但是很不完全,有代码,凑合着看)

此间记录下自个儿要好的思路:

Hash表也称散列表,也有一贯译作哈希表,Hash表是一种至极的数据结构,它同数组、链表以及贰叉排序树等相比较有很精通的界别,它亦可高效牢固到想要查找的笔录,而不是与表中存在的记录的重大字展开相比较来展开检索。那几个来自Hash表设计的特殊性,它使用了函数映射的思索将记录的积攒地方与记录的严重性字关联起来,从而能够很迅猛地张开查找。
一.Hash表的统一策画观念
  对于一般的线性表,比方链表,借使要存款和储蓄联系人新闻: 
张三 13980593357李四 15828662334王五 13409821234张帅 13890583472

第二章 筹算干活
第二章
Python语法基础,IPython和Jupyter
第二章
Python的数据结构、函数和文书
第肆章
NumPy基础:数组和矢量总结
第5章 pandas入门
第五章
数据加载、存款和储蓄与文件格式
第7章 数据清洗和希图
第7章
数据整理:聚合、合并和重塑
第10章 绘图和可视化
第九章 数据聚合与分组运算
第三一章 时间系列
第2二章 pandas高端应用
第三3章 Python建立模型库介绍
第34章 数据解析案例
附录A NumPy高等应用
附录B
越来越多关于IPython的内容(完)

  Hash表也称散列表,也有直接译作哈希表,Hash表是1种卓殊的数据结构,它同数组、链表以及二叉排序树等相比较有很明确的分别,它亦可高效牢固到想要查找的记录,而不是与表中存在的笔录的要紧字张开相比来展开检索。这几个源于Hash表设计的特殊性,它使用了函数映射的观念将记录的仓库储存地点与记录的机要字关联起来,从而能够很迅猛地开始展览搜寻。

一:利用系统表得到0-2047的行列 ,204捌*204100000万10足了呢

那么或者会计统计一企图二个结构体包涵姓名,手提式有线电话机号码这一个新闻,然后把七个挂钩人的消息存到一张链表中。当要找出”李41582866233四“那条记下是不是在那张链表中要么想要获得李四的手提式有线电话机号码时,可能会从链表的头结点开始遍历,依次将各样结点中的姓名同”李4“举行相比,直到查找成功依然失利告终,那种做法的小运复杂度为O(n)。纵然使用2叉排序树举办仓库储存,也最多为O(logn)。假如能够通过”李四“那几个音信平昔拿走到该记录在表中的贮存地方,就会省掉中间关键字相比较的那些环节,复杂度直接降到O(一)。Hash表就能够达到如此的意义。
  Hash表选择四个映射函数 f : key —> address
将器重字映射到该记录在表中的存款和储蓄地点,从而在想要查找该记录时,能够平素依照首要字和照耀关系总结出该记录在表中的囤积位置,平日境况下,那种映射关系称作为Hash函数,而通过Hash函数和首要字总结出来的蕴藏地方(注意这里的储存地方只是表中的贮存地点,并不是实在的大要地址)称作为Hash地址。比方上述例子中,若是联系人消息运用Hash表存款和储蓄,则当想要找到“李4”的音信时,直接依据“李4”和Hash函数总结出Hash地址就能够。上面斟酌一下Hash表设计中的多少个关键难题。


1.Hash表的设计观念

SELECT sv.number AS n FROM MASTER.dbo.spt_values AS sv WHERE sv.[type]='P'
  1. Hash函数的安排
      Hash函数设计的优劣直接影响到对Hash表的操作效用。上面比如表明:
      假若对上述的调换人新闻进行仓库储存时,采纳的Hash函数为:姓名的每一种字的拼音开首大写字母的ASCII码之和。
      因此address(张三)=ASCII(Z)+ASCII(S)=90+83=173;
        address(李四)=ASCII(L)+ASCII(S)=76+83=159;
        address(王五)=ASCII(W)+ASCII(W)=87+87=174;
        address(张帅)=ASCII(Z)+ASCII(S)=90+83=173;
      要是唯有那五个挂钩人消息供给展展开货仓储,这一个Hash函数设计的很不好。首先,它浪费了汪洋的存储空间,借使选取char型数组存储联系人音讯的话,则至少须要开辟17四1二字节的空中,空间利用率唯有4/174,不到5%;其余,依据Hash函数总结结果以后,address(张叁)和address(李4)具备同样的地点,那种光景称作争执,对于17二个存款和储蓄空间中只供给仓库储存四条记下就生出了争持,那样的Hash函数设计是很不创设的。所以在布局Hash函数时应尽只怕考虑重视字的分布特点来统筹函数使得Hash地址随机均匀地布满在全路地址空间在那之中。日常有以下两种结构Hash函数的章程:
      一)直接定址法
      取关键字照旧保护字的某些线性函数为Hash地址,即address(key)=a
    key+b;如知道学生的学号从3000起来,最大为五千,则足以将address(key)=key-3000作为Hash地址。
      二)平方取中国和法国
      对第1字张开平方运算,然后取结果的中等4个人作为Hash地址。假使有以下器重字类别{4二一,42叁,43陆},平方之后的结果为{177二四一,17892玖,一玖零二九六},那么可以取{72,8玖,00}作为Hash地址。
      3)折叠法
      将重大字拆分成几有的,然后将这几局地组成在一起,以特定的点子开始展览转账产生Hash地址。借使知道图书的ISBN号为890三-贰4一-二叁,能够将address(key)=8玖+0三+二肆+12+三用作Hash地址。
      四)除留取余法
      若是驾驭Hash表的最大尺寸为m,能够取比比较小于m的最大质数p,然后对首要字张开取余运算,address(key)=key%p。
      在这里p的抉择异常重要,p采取的好的话,能够最大程度地回落争论,p一般取一点都不大于m的最大质数。
    二.Hash表大小的规定
      Hash表大小的规定也尤其关键,假若Hash表的半空中国远洋运输总公司远大于最终实际上存款和储蓄的笔录个数,则导致了十分的大的上空浪费,假若采纳小了的话,则轻松导致争论。在实质上情况中,一般须求依据最终记录存款和储蓄个数和主要字的分布特征来鲜明Hash表的大小。还有壹种情状时只怕事先不领悟最终要求仓库储存的记录个数,则必要动态维护Hash表的容积,此时大概必要重新总结Hash地址。
    三.龃龉的化解
      在上述例子中,爆发了争持现象,由此必要艺术来缓和,不然记录不恐怕进行科学的贮存。平日境况下有2种化解办法:
      一)开放定址法
      即当多少个爱抚字和另1个器重字产生争辩时,使用某种探测才干在Hash表中产生3个探测连串,然后沿着那几个探测体系依次查找下去,当遇到3个空的单元时,则插入个中。相比较常用的探测方法有线性探测法,举个例子有一组第二字{1二,一3,二五,2三,3捌,34,陆,8四,玖一},Hash表长为1四,Hash函数为address(key)=key%1一,当插入12,壹三,二5时得以直接插入,而当插入二三时,地址一被占用了,因而沿着地址壹依次往向下探底测(探测步长能够依附气象而定),直到探测到地点四,发掘为空,则将二三插入个中。
      二)链地址法
      选用数组和链表相结合的主意,将Hash地址同样的笔录存款和储蓄在一张线性表中,而每张表的表头的序号即为总计获得的Hash地址。如上述例子中,选拔链地址法产生的Hash表存款和储蓄表示为:

    997755.com澳门葡京 1

本书正文的尾声1章,大家来看某个真实世界的数额集。对于每一种数据集,大家会用之前介绍的办法,从原始数据中提取有意义的始末。浮现的主意适用于别的数据集,也包蕴你的。本章包涵了有的丰富多彩的案例数据集,能够用来练习。

  对于一般的线性表,比方链表,假如要存款和储蓄联系人音讯: 

结果如图:

  虽然能够采用一些办法去减少冲突,但是冲突是无法完全避免的。因此需要根据实际情况选取解决冲突的办法。  
4.Hash表的平均查找长度  
  Hash表的平均查找长度包括查找成功时的平均查找长度和查找失败时的平均查找长度。  
  查找成功时的平均查找长度=表中每个元素查找成功时的比较次数之和/表中元素个数;  
  查找不成功时的平均查找长度相当于在表中查找元素不成功时的平均比较次数,可以理解为向表中插入某个元素,该元素在每个位置都有可能,然后计算出在每个位置能够插入时需要比较的次数,再除以表长即为查找不成功时的平均查找长度。  
  下面举个例子:  
  有一组关键字{23,12,14,2,3,5},表长为14,Hash函数为key%11,则关键字在表中的存储如下:  
  地址 0 1 2 3 4 5 6 7 8 9 10 11 12 13  
  关键字 23 12 14 2 3 5  
 比较次数 1 2 1 3 3 2  
  因此查找成功时的平均查找长度为(1+2+1+3+3+2)/6=11/6;  
  查找失败时的平均查找长度为(1+7+6+5+4+3+2+1+1+1+1+1+1+1)/14=38/14;  
  这里有一个概念装填因子=表中的记录数/哈希表的长度,如果装填因子越小,表明表中还有很多的空单元,则发生冲突的可能性越小;而装填因子越大,则发生冲突的可能性就越大,在查找时所耗费的时间就越多。因此,Hash表的平均查找长度和装填因子有关。有相关文献证明当装填因子在0.5左右的时候,Hash的性能能够达到最优。因此,一般情况下,装填因子取经验值0.5。  
5.Hash表的优缺点  
  Hash表存在的优点显而易见,能够在常数级的时间复杂度上进行查找,并且插入数据和删除数据比较容易。但是它也有某些缺点,比如不支持排序,一般比用线性表存储需要更多的空间,并且记录的关键字不能重复。

案例数据集能够在Github酒馆找到,见第2章。

张三 13980593357
李四 15828662334
王五 13409821234
张帅 13890583472

997755.com澳门葡京 2

代码达成:

14.1 来自Bitly的USA.gov数据

201一年,U景逸SUVL缩小服务Bitly跟美国政坛网址USA.gov合营,提供了一份从生成.gov或.mil短链接的用户这里采访来的无名数据。在201一年,除实时数据之外,还足以下载文件文件格局的每小时快速照相。写作此书时(20一柒年),那项劳动一度倒闭,但大家保留1份数据用于本书的案例。

以每小时快速照相为例,文件中各行的格式为JSON(即JavaScript Object
Notation,那是壹种常用的Web数据格式)。譬喻,借使大家只读取有个别文件中的第3行,那么所看到的结果应当是上边那样:

In [5]: path = 'datasets/bitly_usagov/example.txt'

In [6]: open(path).readline()
Out[6]: '{ "a": "Mozilla\\/5.0 (Windows NT 6.1; WOW64) AppleWebKit\\/535.11
(KHTML, like Gecko) Chrome\\/17.0.963.78 Safari\\/535.11", "c": "US", "nk": 1,
"tz": "America\\/New_York", "gr": "MA", "g": "A6qOVH", "h": "wfLQtf", "l":
"orofrog", "al": "en-US,en;q=0.8", "hh": "1.usa.gov", "r":
"http:\\/\\/www.facebook.com\\/l\\/7AQEFzjSi\\/1.usa.gov\\/wfLQtf", "u":
"http:\\/\\/www.ncbi.nlm.nih.gov\\/pubmed\\/22415991", "t": 1331923247, "hc":
1331822918, "cy": "Danvers", "ll": [ 42.576698, -70.954903 ] }\n'

Python有停放或第3方模块能够将JSON字符串调换到Python字典对象。这里,作者将动用json模块及其loads函数逐行加载已经下载好的数据文件:

import json
path = 'datasets/bitly_usagov/example.txt'
records = [json.loads(line) for line in open(path)]

现行反革命,records对象就形成1组Python字典了:

In [18]: records[0]
Out[18]:
{'a': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko)
Chrome/17.0.963.78 Safari/535.11',
 'al': 'en-US,en;q=0.8',
 'c': 'US',
 'cy': 'Danvers',
 'g': 'A6qOVH',
 'gr': 'MA',
 'h': 'wfLQtf',
 'hc': 1331822918,
 'hh': '1.usa.gov',
 'l': 'orofrog',
 'll': [42.576698, -70.954903],
 'nk': 1,
 'r': 'http://www.facebook.com/l/7AQEFzjSi/1.usa.gov/wfLQtf',
 't': 1331923247,
 'tz': 'America/New_York',
 'u': 'http://www.ncbi.nlm.nih.gov/pubmed/22415991'}

中怎么样成功再三再四时间段的拆分,数据解析案例。  那么或许会规划1个结构体包罗姓名,手提式有线电话机号码那一个音讯,然后把陆个挂钩人的音信存到一张链表中。当要搜索”李415828662334“那条记下是还是不是在那张链表中要么想要拿到李四的手提式无线电话机号码时,大概会从链表的头结点开头遍历,依次将各样结点中的姓名同”李4“进行比较,直到查找成功依旧战败告终,那种做法的小时复杂度为O(n)。即便使用二叉排序树进行仓库储存,也最多为O(logn)。假诺能够通过”李四“这些音信平素获得到该记录在表中的储存地点,就能够省掉中间关键字相比较的这么些环节,复杂度直接降到O(一)。Hash表就能够实现如此的意义。

2:利用CROSS APPLY  获得最后连串(从1开首,最终1行是204八*997755.com澳门葡京,2048)

997755.com澳门葡京 3

用纯Python代码对时区实行计数

纵然大家想要知道该数量集中最常出现的是哪位时区(即tz字段),获得答案的点子有大多。首先,我们用列表推导式抽出壹组时区:

In [12]: time_zones = [rec['tz'] for rec in records]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-12-db4fbd348da9> in <module>()
----> 1 time_zones = [rec['tz'] for rec in records]
<ipython-input-12-db4fbd348da9> in <listcomp>(.0)
----> 1 time_zones = [rec['tz'] for rec in records]
KeyError: 'tz'

晕!原来并不是兼具记录都有时区字段。这么些好办,只需在列表推导式末尾加上二个if
‘tz’in rec剖断就能够:

In [13]: time_zones = [rec['tz'] for rec in records if 'tz' in rec]

In [14]: time_zones[:10]
Out[14]: 
['America/New_York',
 'America/Denver',
 'America/New_York',
 'America/Sao_Paulo',
 'America/New_York',
 'America/New_York',
 'Europe/Warsaw',
 '',
 '',
 '']

只看前十三个时区,我们发掘有点是雾里看花的(即空的)。固然能够将它们过滤掉,但现行反革命一时先留着。接下来,为了对时区实行计数,这里介绍五个点子:三个较难(只利用专门的职业Python库),另二个较简单(使用pandas)。计数的法子之1是在遍历时区的进程大校计数值保存在字典中:

def get_counts(sequence):
    counts = {}
    for x in sequence:
        if x in counts:
            counts[x] += 1
        else:
            counts[x] = 1
    return counts

假使使用Python规范库的更加尖端工具,那么你可能会将代码写得更轻便一些:

from collections import defaultdict

def get_counts2(sequence):
    counts = defaultdict(int) # values will initialize to 0
    for x in sequence:
        counts[x] += 1
    return counts

本人将逻辑写到函数中是为了获得越来越高的复用性。要用它对时区进行管理,只需将time_zones传入就能够:

In [17]: counts = get_counts(time_zones)

In [18]: counts['America/New_York']
Out[18]: 1251

In [19]: len(time_zones)
Out[19]: 3440

万一想要获得前拾人的时区及其计数值,大家须要运用一些关于字典的拍卖技能:

def top_counts(count_dict, n=10):
    value_key_pairs = [(count, tz) for tz, count in count_dict.items()]
    value_key_pairs.sort()
    return value_key_pairs[-n:]

然后有:

In [21]: top_counts(counts)
Out[21]: 
[(33, 'America/Sao_Paulo'),
 (35, 'Europe/Madrid'),
(36, 'Pacific/Honolulu'),
 (37, 'Asia/Tokyo'),
 (74, 'Europe/London'),
 (191, 'America/Denver'),
 (382, 'America/Los_Angeles'),
 (400, 'America/Chicago'),
 (521, ''),
 (1251, 'America/New_York')]

设若您搜索Python的规范库,你能找到collections.Counter类,它能够使那项专门的学业更简单:

In [22]: from collections import Counter

In [23]: counts = Counter(time_zones)

In [24]: counts.most_common(10)
Out[24]: 
[('America/New_York', 1251),
 ('', 521),
 ('America/Chicago', 400),
 ('America/Los_Angeles', 382),
 ('America/Denver', 191),
 ('Europe/London', 74),
 ('Asia/Tokyo', 37),
 ('Pacific/Honolulu', 36),
 ('Europe/Madrid', 35),
 ('America/Sao_Paulo', 33)]

  Hash表采取一个映射函数 f : key —> address
将重要字映射到该记录在表中的囤积地方,从而在想要查找该记录时,能够直接依照重要字和照耀关系总括出该记录在表中的积累地点,平时状态下,那种映射关系称作为Hash函数,而透过Hash函数和根本字计算出来的囤积地方(注意这里的仓库储存位置只是表中的存储地方,并不是实际上的大要地址)称作为Hash地址。比方上述例子中,即使联系人新闻运用Hash表存款和储蓄,则当想要找到“李四”的音讯时,直接根据“李肆”和Hash函数计算出Hash地址就可以。上边研商一下Hash表设计中的多少个关键难题。

WITH
 t1 AS (SELECT sv.number AS n FROM MASTER.dbo.spt_values AS sv WHERE sv.[type]='P'),
 t2 AS ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rid  FROM t1 AS a CROSS APPLY t1 AS b)
----------------- 
SELECT *FROM t2 

复制代码

用pandas对时区实行计数

从原始记录的会合创立DateFrame,与将记录列表传递到pandas.DataFrame一样轻易:

In [25]: import pandas as pd

In [26]: frame = pd.DataFrame(records)

In [27]: frame.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3560 entries, 0 to 3559
Data columns (total 18 columns):
_heartbeat_    120 non-null float64
a              3440 non-null object
al             3094 non-null object
c              2919 non-null object
cy             2919 non-null object
g              3440 non-null object
gr             2919 non-null object
h              3440 non-null object
hc             3440 non-null float64
hh             3440 non-null object
kw             93 non-null object
l              3440 non-null object
ll             2919 non-null object
nk             3440 non-null float64
r              3440 non-null object
t              3440 non-null float64
tz             3440 non-null object
u              3440 non-null object
dtypes: float64(4), object(14)
memory usage: 500.7+ KB

In [28]: frame['tz'][:10]
Out[28]: 
0     America/New_York
1       America/Denver
2     America/New_York
3    America/Sao_Paulo
4     America/New_York
5     America/New_York
6        Europe/Warsaw
7                     
8                     
9                     
Name: tz, dtype: object

此间frame的出口方式是摘要视图(summary
view),首要用于十分大的DataFrame对象。我们接下来可以对Series使用value_counts方法:

In [29]: tz_counts = frame['tz'].value_counts()

In [30]: tz_counts[:10]
Out[30]: 
America/New_York       1251
                        521
America/Chicago         400
America/Los_Angeles     382
America/Denver          191
Europe/London            74
Asia/Tokyo               37
Pacific/Honolulu         36
Europe/Madrid            35
America/Sao_Paulo        33
Name: tz, dtype: int64

我们得以用matplotlib可视化这几个数额。为此,大家先给记录中未知或缺点和失误的时区填上二个代替值。fillna函数能够轮换缺点和失误值(NA),而未知值(空字符串)则足以通过布尔型数组索引加以替换:

In [31]: clean_tz = frame['tz'].fillna('Missing')

In [32]: clean_tz[clean_tz == ''] = 'Unknown'

In [33]: tz_counts = clean_tz.value_counts()

In [34]: tz_counts[:10]
Out[34]: 
America/New_York       1251
Unknown                 521
America/Chicago         400
America/Los_Angeles     382
America/Denver          191
Missing                 120
Europe/London            74
Asia/Tokyo               37
Pacific/Honolulu         36
Europe/Madrid            35
Name: tz, dtype: int64

此刻,大家能够用seaborn包创设水平柱状图(结果见图1四-一):

In [36]: import seaborn as sns

In [37]: subset = tz_counts[:10]

In [38]: sns.barplot(y=subset.index, x=subset.values)

997755.com澳门葡京 4

图1肆-一 usa.gov演示数据中最常出现的时区

a字段含有施行U智跑L短缩操作的浏览器、设备、应用程序的连锁消息:

In [39]: frame['a'][1]
Out[39]: 'GoogleMaps/RochesterNY'

In [40]: frame['a'][50]
Out[40]: 'Mozilla/5.0 (Windows NT 5.1; rv:10.0.2)
Gecko/20100101 Firefox/10.0.2'

In [41]: frame['a'][51][:50]  # long line
Out[41]: 'Mozilla/5.0 (Linux; U; Android 2.2.2; en-us; LG-P9'

将那一个”agent”字符串中的全体音讯都分析出来是一件挺郁闷的做事。一种政策是将那种字符串的首先节(与浏览器大约对应)分离出来并得到其它一份用户作为摘要:

In [42]: results = pd.Series([x.split()[0] for x in frame.a.dropna()])

In [43]: results[:5]
Out[43]: 
0               Mozilla/5.0
1    GoogleMaps/RochesterNY
2               Mozilla/4.0
3               Mozilla/5.0
4               Mozilla/5.0
dtype: object

In [44]: results.value_counts()[:8]
Out[44]: 
Mozilla/5.0                 2594
Mozilla/4.0                  601
GoogleMaps/RochesterNY       121
Opera/9.80                    34
TEST_INTERNET_AGENT           24
GoogleProducer                21
Mozilla/6.0                    5
BlackBerry8520/5.0.0.681       4
dtype: int64

现行反革命,假令你想按Windows和非Windows用户对时区总计信息进行表明。为了简单起见,我们只要只要agent字符串中蕴涵”Windows”就感到该用户为Windows用户。由于有的agent缺点和失误,所以率先将它们从数量中移除:

In [45]: cframe = frame[frame.a.notnull()]

接下来总括出各行是或不是含有Windows的值:

In [47]: cframe['os'] = np.where(cframe['a'].str.contains('Windows'),
   ....:                         'Windows', 'Not Windows')

In [48]: cframe['os'][:5]
Out[48]: 
0        Windows
1    Not Windows
2        Windows
3    Not Windows
4        Windows
Name: os, dtype: object

接下去就能够依据时区和新收获的操作系统列表对数码进行分组了:

In [49]: by_tz_os = cframe.groupby(['tz', 'os'])

分组计数,类似于value_counts函数,可以用size来计量。并应用unstack对计数结果举行重塑:

In [50]: agg_counts = by_tz_os.size().unstack().fillna(0)

In [51]: agg_counts[:10]
Out[51]: 
os                              Not Windows  Windows
tz                                                  
                                      245.0    276.0
Africa/Cairo                            0.0      3.0
Africa/Casablanca                       0.0      1.0
Africa/Ceuta                            0.0      2.0
Africa/Johannesburg                     0.0      1.0
Africa/Lusaka                           0.0      1.0
America/Anchorage                       4.0      1.0
America/Argentina/Buenos_Aires          1.0      0.0
America/Argentina/Cordoba               0.0      1.0
America/Argentina/Mendoza               0.0      1.0

最终,我们来摘取最常出现的时区。为了达到那些目标,小编根据agg_counts中的行数构造了三个直接索引数组:

# Use to sort in ascending order
In [52]: indexer = agg_counts.sum(1).argsort()

In [53]: indexer[:10]
Out[53]: 
tz
                                  24
Africa/Cairo                      20
Africa/Casablanca                 21
Africa/Ceuta                      92
Africa/Johannesburg               87
Africa/Lusaka                     53
America/Anchorage                 54
America/Argentina/Buenos_Aires    57
America/Argentina/Cordoba         26
America/Argentina/Mendoza         55
dtype: int64

下一场自个儿经过take依照那些顺序截取了最后拾行最大值:

In [54]: count_subset = agg_counts.take(indexer[-10:])

In [55]: count_subset
Out[55]: 
os                   Not Windows  Windows
tz                                       
America/Sao_Paulo           13.0     20.0
Europe/Madrid               16.0     19.0
Pacific/Honolulu             0.0     36.0
Asia/Tokyo                   2.0     35.0
Europe/London               43.0     31.0
America/Denver             132.0     59.0
America/Los_Angeles        130.0    252.0
America/Chicago            115.0    285.0
                           245.0    276.0
America/New_York           339.0    912.0

pandas有三个便捷方法nlargest,可以做同样的专门的学问:

In [56]: agg_counts.sum(1).nlargest(10)
Out[56]: 
tz
America/New_York       1251.0
                        521.0
America/Chicago         400.0
America/Los_Angeles     382.0
America/Denver          191.0
Europe/London            74.0
Asia/Tokyo               37.0
Pacific/Honolulu         36.0
Europe/Madrid            35.0
America/Sao_Paulo        33.0
dtype: float64

然后,如那段代码所示,能够用柱状图表示。小编传递多少个卓绝参数到seaborn的barpolt函数,来画2个堆集条形图(见图14-二):

# Rearrange the data for plotting
In [58]: count_subset = count_subset.stack()

In [59]: count_subset.name = 'total'

In [60]: count_subset = count_subset.reset_index()

In [61]: count_subset[:10]
Out[61]: 
                  tz           os  total
0  America/Sao_Paulo  Not Windows   13.0
1  America/Sao_Paulo      Windows   20.0
2      Europe/Madrid  Not Windows   16.0
3      Europe/Madrid      Windows   19.0
4   Pacific/Honolulu  Not Windows    0.0
5   Pacific/Honolulu      Windows   36.0
6         Asia/Tokyo  Not Windows    2.0
7         Asia/Tokyo      Windows   35.0
8      Europe/London  Not Windows   43.0
9      Europe/London      Windows   31.0

In [62]: sns.barplot(x='total', y='tz', hue='os',  data=count_subset)

997755.com澳门葡京 5

图1四-贰 最常出现时区的Windows和非Windows用户

那张图不轻便看到Windows用户在小分组中的相比较例,由此原则分组百分比之和为壹:

def norm_total(group):
    group['normed_total'] = group.total / group.total.sum()
    return group

results = count_subset.groupby('tz').apply(norm_total)

重新画图,见图1四-三:

In [65]: sns.barplot(x='normed_total', y='tz', hue='os',  data=results)

997755.com澳门葡京 6

图14-叁 最常出现时区的Windows和非Windows用户的百分比

笔者们还足以用groupby的transform方法,越来越快捷的计量规范器械的和:

In [66]: g = count_subset.groupby('tz')

In [67]: results2 = count_subset.total / g.total.transform('sum')
  1. Hash函数的布置

结果如图

/Hash表,接纳数组达成,2013.玖.2八/ #include<stdio.h>#define
DataType int#define M 30 typedef struct HashNode { DataType data;
//存储值 int isNull; //标识该位置是还是不是已被填充 }HashTable;HashTable
hashTable[M];void initHashTable() //对hash表举行开始化 { int i; for(i
= 0; i<M; i++) { hashTable[i].isNull = 一; //开始状态为空 }}int
getHashAddress(DataType key) //Hash函数 { return key % 2九; //Hash函数为
key%2九 }int insert(DataType key) //向hash表中插入元素 { int address =
getHashAddress(key); if(hashTable[address].isNull == 1) //未有发生争执{ hashTable[address].data = key; hashTable[address].isNull = 0; }
else //当产生冲突的时候 { while(hashTable[address].isNull == 0 &&
address<M) { address++; //采取线性探测法,步长为壹 } if(address == M)
//Hash表发生溢出 return -一; hashTable[address].data = key;
hashTable[address].isNull = 0; } return 0;}int find(DataType key)
//进行搜索 { int address = getHashAddress(key); while(
!(hashTable[address].isNull == 0 && hashTable[address].data == key
&& address<M)) { address++; } if( address == M) address = -1; return
address;}int main(int argc, char *argv[]){ int
key[]={123,456,7000,8,1,13,11,555,425,393,212,546,2,99,196}; int i;
initHashTable(); for(i = 0; i<15; i++) { insert(key[i]); } for(i =
0; i<15; i++) { int address; address = find(key[i]); printf(“%d
%d\n”, key[i],address); } return 0;}

14.2 MovieLens 1M数据集

GroupLens
Research(http://www.grouplens.org/node/73)搜集了1组从20世纪90年末到二壹世纪初由MovieLens用户提供的影视评分数据。这个数据中归纳电影评分、电影元数据(风格类型和年间)以及关于用户的人数总括学数据(年龄、邮政编码、性别和专门的学问等)。基于机器学习算法的引入系统一般都会对该类数据感兴趣。固然笔者不会在本书中详尽介绍机器学习本事,但作者会告诉您什么样对那种数量实行切开切成条以满意实际需求。

MovieLens
1M数据集带有来自5000名用户对陆仟部影片的100万条评分数据。它分成四个表:评分、用户音信和电影消息。将该数量从zip文件中解压出来之后,能够透过pandas.read_table将顺序表分别读到三个pandas
DataFrame对象中:

import pandas as pd

# Make display smaller
pd.options.display.max_rows = 10

unames = ['user_id', 'gender', 'age', 'occupation', 'zip']
users = pd.read_table('datasets/movielens/users.dat', sep='::',
                      header=None, names=unames)

rnames = ['user_id', 'movie_id', 'rating', 'timestamp']
ratings = pd.read_table('datasets/movielens/ratings.dat', sep='::',
                        header=None, names=rnames)
mnames = ['movie_id', 'title', 'genres']
movies = pd.read_table('datasets/movielens/movies.dat', sep='::',
                       header=None, names=mnames)

运用Python的切成条语法,通过查阅种种DataFrame的前几行就可以验证数据加载职业是还是不是1切顺遂:

In [69]: users[:5]
Out[69]: 
   user_id gender  age  occupation    zip
0        1      F    1          10  48067
1        2      M   56          16  70072
2        3      M   25          15  55117
3        4      M   45           7  02460
4        5      M   25          20  55455

In [70]: ratings[:5]
Out[70]: 
   user_id  movie_id  rating  timestamp
0        1      1193       5  978300760
1        1       661       3  978302109
2        1       914       3  978301968
3        1      3408       4  978300275
4        1      2355       5  978824291

In [71]: movies[:5]
Out[71]: 
   movie_id                               title                        genres
0         1                    Toy Story (1995)   Animation|Children's|Comedy
1         2                      Jumanji (1995)  Adventure|Children's|Fantasy
2         3             Grumpier Old Men (1995)                Comedy|Romance
3         4            Waiting to Exhale (1995)                  Comedy|Drama
4         5  Father of the Bride Part II (1995)                        Comedy

In [72]: ratings
Out[72]: 
         user_id  movie_id  rating  timestamp
0              1      1193       5  978300760
1              1       661       3  978302109
2              1       914       3  978301968
3              1      3408       4  978300275
4              1      2355       5  978824291
...          ...       ...     ...        ...
1000204     6040      1091       1  956716541
1000205     6040      1094       5  956704887
1000206     6040       562       5  956704746
1000207     6040      1096       4  956715648
1000208     6040      1097       4  956715569
[1000209 rows x 4 columns]

小心,在这之中的年华和生意是以编码方式提交的,它们的求实意思请参见该数据集的README文件。分析传布在多个表中的数据可不是一件轻易的业务。假诺我们想要依据性别和年龄总计某部电影的平分得分,就算将有着数据都统一到2个表中的话难题就大约多了。大家先用pandas的merge函数将ratings跟users合并到1块,然后再将movies也联合进去。pandas会依据列名的重叠情状测算出什么列是统一(或延续)键:

In [73]: data = pd.merge(pd.merge(ratings, users), movies)

In [74]: data
Out[74]: 
         user_id  movie_id  rating  timestamp gender  age  occupation    zip  \
0              1      1193       5  978300760      F    1          10  48067   
1              2      1193       5  978298413      M   56          16  70072   
2             12      1193       4  978220179      M   25          12  32793   
3             15      1193       4  978199279      M   25           7  22903   
4             17      1193       5  978158471      M   50           1  95350   
...          ...       ...     ...        ...    ...  ...         ...    ...   
1000204     5949      2198       5  958846401      M   18          17  47901
1000205     5675      2703       3  976029116      M   35          14  30030   
1000206     5780      2845       1  958153068      M   18          17  92886   
1000207     5851      3607       5  957756608      F   18          20  55410   
1000208     5938      2909       4  957273353      M   25           1  35401   
                                               title                genres  
0             One Flew Over the Cuckoo's Nest (1975)                 Drama  
1             One Flew Over the Cuckoo's Nest (1975)                 Drama  
2             One Flew Over the Cuckoo's Nest (1975)                 Drama  
3             One Flew Over the Cuckoo's Nest (1975)                 Drama  
4             One Flew Over the Cuckoo's Nest (1975)                 Drama  
...                                              ...                   ...  
1000204                           Modulations (1998)           Documentary  
1000205                        Broken Vessels (1998)                 Drama  
1000206                            White Boys (1999)                 Drama  
1000207                     One Little Indian (1973)  Comedy|Drama|Western  
1000208  Five Wives, Three Secretaries and Me (1998)           Documentary  
[1000209 rows x 10 columns]

In [75]: data.iloc[0]
Out[75]: 
user_id                                            1
movie_id                                        1193
rating                                             5
timestamp                                  978300760
gender                                             F
age                                                1
occupation                                        10
zip                                            48067
title         One Flew Over the Cuckoo's Nest (1975)
genres                                         Drama
Name: 0, dtype: object

为了按性别总括每部电影的平均得分,大家能够使用pivot_table方法:

In [76]: mean_ratings = data.pivot_table('rating', index='title',
   ....:                                 columns='gender', aggfunc='mean')

In [77]: mean_ratings[:5]
Out[77]: 
gender                                F         M
title                                            
$1,000,000 Duck (1971)         3.375000  2.761905
'Night Mother (1986)           3.388889  3.352941
'Til There Was You (1997)      2.675676  2.733333
'burbs, The (1989)             2.793478  2.962085
...And Justice for All (1979)  3.828571  3.689024

该操作产生了另三个DataFrame,其剧情为电影平均得分,行标为影片名称(索引),列标为性别。以往,作者计划过滤掉评分数据不够250条的电影和电视(随意选的三个数字)。为了达成这些目标,作者先对title进行分组,然后使用size()获得二个饱含各电影分组大小的Series对象:

In [78]: ratings_by_title = data.groupby('title').size()

In [79]: ratings_by_title[:10]
Out[79]: 
title
$1,000,000 Duck (1971)                37
'Night Mother (1986)                  70
'Til There Was You (1997)             52
'burbs, The (1989)                   303
...And Justice for All (1979)        199
1-900 (1994)                           2
10 Things I Hate About You (1999)    700
101 Dalmatians (1961)                565
101 Dalmatians (1996)                364
12 Angry Men (1957)                  616
dtype: int64

In [80]: active_titles = ratings_by_title.index[ratings_by_title >= 250]

In [81]: active_titles
Out[81]: 
Index([''burbs, The (1989)', '10 Things I Hate About You (1999)',
       '101 Dalmatians (1961)', '101 Dalmatians (1996)', '12 Angry Men (1957)',
       '13th Warrior, The (1999)', '2 Days in the Valley (1996)',
       '20,000 Leagues Under the Sea (1954)', '2001: A Space Odyssey (1968)',
       '2010 (1984)',
       ...
'X-Men (2000)', 'Year of Living Dangerously (1982)',
       'Yellow Submarine (1968)', 'You've Got Mail (1998)',
       'Young Frankenstein (1974)', 'Young Guns (1988)',
       'Young Guns II (1990)', 'Young Sherlock Holmes (1985)',
       'Zero Effect (1998)', 'eXistenZ (1999)'],
      dtype='object', name='title', length=1216)

标题索引中蕴藏评分数据赶上250条的电影名称,然后我们就足以就此从后边的mean_ratings中精选所需的行了:

# Select rows on the index
In [82]: mean_ratings = mean_ratings.loc[active_titles]

In [83]: mean_ratings
Out[83]: 
gender                                    F         M
title                                                
'burbs, The (1989)                 2.793478  2.962085
10 Things I Hate About You (1999)  3.646552  3.311966
101 Dalmatians (1961)              3.791444  3.500000
101 Dalmatians (1996)              3.240000  2.911215
12 Angry Men (1957)                4.184397  4.328421
...                                     ...       ...
Young Guns (1988)                  3.371795  3.425620
Young Guns II (1990)               2.934783  2.904025
Young Sherlock Holmes (1985)       3.514706  3.363344
Zero Effect (1998)                 3.864407  3.723140
eXistenZ (1999)                    3.098592  3.289086
[1216 rows x 2 columns]

为了掌握女人客官最喜爱的电影,我们得以对F列降序排列:

In [85]: top_female_ratings = mean_ratings.sort_values(by='F', ascending=False)

In [86]: top_female_ratings[:10]
Out[86]: 
gender                                                     F         M
title                                                                 
Close Shave, A (1995)                               4.644444  4.473795
Wrong Trousers, The (1993)                          4.588235  4.478261
Sunset Blvd. (a.k.a. Sunset Boulevard) (1950)       4.572650  4.464589
Wallace & Gromit: The Best of Aardman Animation...  4.563107  4.385075
Schindler's List (1993)                             4.562602  4.491415
Shawshank Redemption, The (1994)                    4.539075  4.560625
Grand Day Out, A (1992)                             4.537879  4.293255
To Kill a Mockingbird (1962)                        4.536667  4.372611
Creature Comforts (1990)                            4.513889  4.272277
Usual Suspects, The (1995)                          4.513317  4.518248

  Hash函数设计的好坏直接影响到对Hash表的操作效能。上面举例表达:

997755.com澳门葡京 7

997755.com澳门葡京 8

算算评分差别

如若大家想要寻找男人和女人观众差异最大的影片。叁个措施是给mean_ratings加上1个用以存放平均得分之差的列,并对其举办排序:

In [87]: mean_ratings['diff'] = mean_ratings['M'] - mean_ratings['F']

按”diff”排序就可以获得不一样最大且女子客官更爱好的影视:

In [88]: sorted_by_diff = mean_ratings.sort_values(by='diff')

In [89]: sorted_by_diff[:10]
Out[89]: 
gender                                        F         M      diff
title                                                              
Dirty Dancing (1987)                   3.790378  2.959596 -0.830782
Jumpin' Jack Flash (1986)              3.254717  2.578358 -0.676359
Grease (1978)                          3.975265  3.367041 -0.608224
Little Women (1994)                    3.870588  3.321739 -0.548849
Steel Magnolias (1989)                 3.901734  3.365957 -0.535777
Anastasia (1997)                       3.800000  3.281609 -0.518391
Rocky Horror Picture Show, The (1975)  3.673016  3.160131 -0.512885
Color Purple, The (1985)               4.158192  3.659341 -0.498851
Age of Innocence, The (1993)           3.827068  3.339506 -0.487561
Free Willy (1993)                      2.921348  2.438776 -0.482573

对排序结果反序并抽取前十行,获得的则是男性观众更欣赏的影视:

# Reverse order of rows, take first 10 rows
In [90]: sorted_by_diff[::-1][:10]
Out[90]: 
gender                                         F         M      diff
title                                                               
Good, The Bad and The Ugly, The (1966)  3.494949  4.221300  0.726351
Kentucky Fried Movie, The (1977)        2.878788  3.555147  0.676359
Dumb & Dumber (1994)                    2.697987  3.336595  0.638608
Longest Day, The (1962)                 3.411765  4.031447  0.619682
Cable Guy, The (1996)                   2.250000  2.863787  0.613787
Evil Dead II (Dead By Dawn) (1987)      3.297297  3.909283  0.611985
Hidden, The (1987)                      3.137931  3.745098  0.607167
Rocky III (1982)                        2.361702  2.943503  0.581801
Caddyshack (1980)                       3.396135  3.969737  0.573602
For a Few Dollars More (1965)           3.409091  3.953795  0.544704

纵然只是想要找寻争执最大的电影(不思量性别因素),则足以计算得分多少的方差或标准差:

# Standard deviation of rating grouped by title
In [91]: rating_std_by_title = data.groupby('title')['rating'].std()

# Filter down to active_titles
In [92]: rating_std_by_title = rating_std_by_title.loc[active_titles]

# Order Series by value in descending order
In [93]: rating_std_by_title.sort_values(ascending=False)[:10]
Out[93]: 
title
Dumb & Dumber (1994)                     1.321333
Blair Witch Project, The (1999)          1.316368
Natural Born Killers (1994)              1.307198
Tank Girl (1995)                         1.277695
Rocky Horror Picture Show, The (1975)    1.260177
Eyes Wide Shut (1999)                    1.259624
Evita (1996)                             1.253631
Billy Madison (1995)                     1.249970
Fear and Loathing in Las Vegas (1998)    1.246408
Bicentennial Man (1999)                  1.245533
Name: rating, dtype: float64

想必您曾经注意到了,电影分类是以竖线(|)分隔的字符串格局提交的。假如想对影片分类开始展览剖析的话,就要求先将其转变来更使得的花样才行。

  假若对上述的关系人音信进行仓库储存时,采取的Hash函数为:姓名的各样字的拼音发轫大写字母的ASCII码之和。

你千万别告诉作者400多万都不够你拆的哎,小心小编揍你

复制代码

1四.三 1880-2010年间全美婴孩姓名

美利坚合众国社会保证总署(SSA)提供了一份从1880年到现行反革命的婴孩名字频率数据。Hadley
Wickham(多数风行Highlander包的作者)平时用那份数据来演示本田UR-V的多寡管理功能。

小编们要做一些数据整理才干加载那几个数据集,这么做就可以发出三个之类的DataFrame:

In [4]: names.head(10)
Out[4]:
        name sex  births  year
0       Mary   F    7065  1880
1       Anna   F    2604  1880
2       Emma   F    2003  1880
3  Elizabeth   F    1939  1880
4     Minnie   F    1746  1880
5   Margaret   F    1578  1880
6        Ida   F    1472  1880
7      Alice   F    1414  1880
8     Bertha   F    1320  1880
9      Sarah   F    1288  1880

你能够用这一个数据集做好些个事,举个例子:

  • 总括钦点名字(能够是您自个儿的,也足以是人家的)的年份比例。
  • 测算有个别名字的对峙排名。
  • 算算各年度最盛行的名字,以及抓好或调整和收缩最快的名字。
  • 分析名字趋势:元音、辅音、长度、总体三种性、拼写变化、首尾字母等。
  • 解析外源性趋势:圣经中的名字、名家、人口布局变迁等。

动用后边介绍过的这多少个工具,这么些分析职业都能很自在地成功,作者会讲明在那之中的有的。

到编辑本书时停止,美利哥社会保证总署将该数据库按年度制成了三个数据文件,在那之中付出了各特性别/名字组合的降生总的数量。这几个文件的原始档案能够在此处得到:http://www.ssa.gov/oact/babynames/limits.html。

一旦您在阅读本书的时候这么些页面已经突然不见了了,也足以用寻找引擎找找。

下载”National
data”文件names.zip,解压后的目录中带有一组文件(如yob1880.txt)。作者用UNIX的head命令查看了内部3个文件的前十行(在Windows上,你能够用more命令,或直接在文书编辑器中开采):

In [94]: !head -n 10 datasets/babynames/yob1880.txt
Mary,F,7065
Anna,F,2604
Emma,F,2003
Elizabeth,F,1939
Minnie,F,1746
Margaret,F,1578
Ida,F,1472
Alice,F,1414
Bertha,F,1320
Sarah,F,1288

鉴于那是三个丰裕典型的以逗号隔开分离的格式,所以能够用pandas.read_csv将其加载到DataFrame中:

In [95]: import pandas as pd

In [96]: names1880 =
pd.read_csv('datasets/babynames/yob1880.txt',
   ....:                         names=['name', 'sex', 'births'])

In [97]: names1880
Out[97]: 
           name sex  births
0          Mary   F    7065
1          Anna   F    2604
2          Emma   F    2003
3     Elizabeth   F    1939
4        Minnie   F    1746
...         ...  ..     ...
1995     Woodie   M       5
1996     Worthy   M       5
1997     Wright   M       5
1998       York   M       5
1999  Zachariah   M       5
[2000 rows x 3 columns]

那几个文件中仅蕴含当年出现超越4回的名字。为了简单起见,我们得以用births列的sex分组小计表示该年度的births总结:

In [98]: names1880.groupby('sex').births.sum()
Out[98]: 
sex
F     90993
M    110493
Name: births, dtype: int64

鉴于该数据集按年度被分隔成了多少个文本,所以率先件事情就是要将富有数据都创立到贰个DataFrame里面,并加上三个year字段。使用pandas.concat就可以达到那么些目标:

years = range(1880, 2011)

pieces = []
columns = ['name', 'sex', 'births']

for year in years:
    path = 'datasets/babynames/yob%d.txt' % year
    frame = pd.read_csv(path, names=columns)

    frame['year'] = year
    pieces.append(frame)

# Concatenate everything into a single DataFrame
names = pd.concat(pieces, ignore_index=True)

这里需求留意几件业务。第一,concat暗中同意是按行将多少个DataFrame组合到手拉手的;第①,必须钦定ignore_index=True,因为大家不期待保留read_csv所再次来到的原来行号。未来大家收获了二个可怜大的DataFrame,它蕴涵全体的名字数据:

In [100]: names
Out[100]: 
              name sex  births  year
0             Mary   F    7065  1880
1             Anna   F    2604  1880
2             Emma   F    2003  1880
3        Elizabeth   F    1939  1880
4           Minnie   F    1746  1880
...            ...  ..     ...   ...
1690779    Zymaire   M       5  2010
1690780     Zyonne   M       5  2010
1690781  Zyquarius   M       5  2010
1690782      Zyran   M       5  2010
1690783      Zzyzx   M       5  2010
[1690784 rows x 4 columns]

有了那一个数据今后,大家就能够采取groupby或pivot_table在year和sex等第上对其张开联谊了,如图1肆-四所示:

In [101]: total_births = names.pivot_table('births', index='year',
   .....:                                  columns='sex', aggfunc=sum)

In [102]: total_births.tail()
Out[102]: 
sex         F        M
year                  
2006  1896468  2050234
2007  1916888  2069242
2008  1883645  2032310
2009  1827643  1973359
2010  1759010  1898382

In [103]: total_births.plot(title='Total births by sex and year')

997755.com澳门葡京 9

图14-四 按性别和年份总括的总出生数

上面大家来插入多少个prop列,用于存放钦命名字的婴儿数相对于总出生数的比例。prop值为0.0贰意味着每100名婴儿中有二名取了近年来以此名字。因而,我们先按year和sex分组,然后再将新列加到各种分组上:

def add_prop(group):
    group['prop'] = group.births / group.births.sum()
    return group
names = names.groupby(['year', 'sex']).apply(add_prop)

今日,完整的数目集就有了上边那些列:

In [105]: names
Out[105]: 
              name sex  births  year      prop
0             Mary   F    7065  1880  0.077643
1             Anna   F    2604  1880  0.028618
2             Emma   F    2003  1880  0.022013
3        Elizabeth   F    1939  1880  0.021309
4           Minnie   F    1746  1880  0.019188
...            ...  ..     ...   ...       ...
1690779    Zymaire   M       5  2010  0.000003
1690780     Zyonne   M       5  2010  0.000003
1690781  Zyquarius   M       5  2010  0.000003
1690782      Zyran   M       5  2010  0.000003
1690783      Zzyzx   M       5  2010  0.000003
[1690784 rows x 5 columns]

在施行那样的分组管理时,一般都应有做一些卓有功能检查,比如验证全部分组的prop的总额是或不是为一:

In [106]: names.groupby(['year', 'sex']).prop.sum()
Out[106]: 
year  sex
1880  F      1.0
      M      1.0
1881  F      1.0
      M      1.0
1882  F      1.0
            ... 
2008  M      1.0
2009  F      1.0
      M      1.0
2010  F      1.0
      M      1.0
Name: prop, Length: 262, dtype: float64

做事成就。为了方便落到实处更进一步的辨析,笔者索要收取该数据的一个子集:每对sex/year组合的前一千个名字。那又是1个分组操作:

def get_top1000(group):
    return group.sort_values(by='births', ascending=False)[:1000]
grouped = names.groupby(['year', 'sex'])
top1000 = grouped.apply(get_top1000)
# Drop the group index, not needed
top1000.reset_index(inplace=True, drop=True)

假令你兴奋DIY的话,也得以这么:

pieces = []
for year, group in names.groupby(['year', 'sex']):
    pieces.append(group.sort_values(by='births', ascending=False)[:1000])
top1000 = pd.concat(pieces, ignore_index=True)

当今的结果数据集就小多了:

In [108]: top1000
Out[108]: 
             name sex  births  year      prop
0            Mary   F    7065  1880  0.077643
1            Anna   F    2604  1880  0.028618
2            Emma   F    2003  1880  0.022013
3       Elizabeth   F    1939  1880  0.021309
4          Minnie   F    1746  1880  0.019188
...           ...  ..     ...   ...       ...
261872     Camilo   M     194  2010  0.000102
261873     Destin   M     194  2010  0.000102
261874     Jaquan   M     194  2010  0.000102
261875     Jaydan   M     194  2010  0.000102
261876     Maxton   M     193  2010  0.000102
[261877 rows x 5 columns]

接下去的数码解析专门的工作就本着那么些top1000数据集了。

  因此address(张三)=ASCII(Z)+ASCII(S)=90+83=173;

三:奉上完整代码

作者:海子
    出处:http://www.cnblogs.com/dolphin0520/
    本博客中未申明转载的篇章归作者海子和天涯论坛共有,接待转发,但未经小编同意必须保留此段证明,且在篇章页面显著地方给出原版的书文连接,否则保留追究法律义务的义务。
关于找寻不成功
http://blog.csdn.net/jiary5201314/article/details/51142600

解析命名趋势

有了完整的数据集和刚刚生成的top一千数据集,大家就能够开首分析各样命名趋势了。首先将前1000个名字分为男女七个部分:

In [109]: boys = top1000[top1000.sex == 'M']

In [110]: girls = top1000[top1000.sex == 'F']

那是八个轻易的年月类别,只需稍作整理就可以绘制出相应的图样(例如每年叫做John和玛丽的婴儿数)。大家先生成一张按year和name总结的总出生数透视表:

In [111]: total_births = top1000.pivot_table('births', index='year',
   .....:                                    columns='name',
   .....:                                    aggfunc=sum)

当今,大家用DataFrame的plot方法绘制多少个名字的曲线图(见图1四-5):

In [112]: total_births.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 131 entries, 1880 to 2010
Columns: 6868 entries, Aaden to Zuri
dtypes: float64(6868)
memory usage: 6.9 MB

In [113]: subset = total_births[['John', 'Harry', 'Mary', 'Marilyn']]

In [114]: subset.plot(subplots=True, figsize=(12, 10), grid=False,
   .....:             title="Number of births per year")

997755.com澳门葡京 10

图1四-5 多少个男孩和女孩名字随时间变化的使用数据

从图中得以观察,那多少个名字在United States公民的心目中早就风光不再了。但事实并非如此轻易,大家在下1节中就能够领悟是怎么一回事了。

    address(李四)=ASCII(L)+ASCII(S)=76+83=159;

 

评估命名八种性的拉长

1种解释是大人愿意给娃娃起广大的名字越来越少。这么些只要能够从数量中获得认证。一个办法是测算最盛行的1000个名字所占的比重,小编按year和sex实行聚合并绘图(见图14-陆):

In [116]: table = top1000.pivot_table('prop', index='year',
   .....:                             columns='sex', aggfunc=sum)

In [117]: table.plot(title='Sum of table1000.prop by year and sex',
   .....:            yticks=np.linspace(0, 1.2, 13), xticks=range(1880, 2020, 10)
)

997755.com澳门葡京 11

图1肆-六 分性别计算的前一千个名字在总出生人数中的比例

从图中能够看出,名字的七种性确实出现了加强(前1000项的百分比下跌)。另1个方法是精打细算占总出生人数前3/六的例外名字的数量,这几个数字不太好计算。大家只怀念20拾年男孩的名字:

In [118]: df = boys[boys.year == 2010]

In [119]: df
Out[119]: 
           name sex  births  year      prop
260877    Jacob   M   21875  2010  0.011523
260878    Ethan   M   17866  2010  0.009411
260879  Michael   M   17133  2010  0.009025
260880   Jayden   M   17030  2010  0.008971
260881  William   M   16870  2010  0.008887
...         ...  ..     ...   ...       ...
261872   Camilo   M     194  2010  0.000102
261873   Destin   M     194  2010  0.000102
261874   Jaquan   M     194  2010  0.000102
261875   Jaydan   M     194  2010  0.000102
261876   Maxton   M     193  2010  0.000102
[1000 rows x 5 columns]

在对prop降序排列之后,大家想掌握前边几个名字的人头加起来才够一半。即使编写一个for循环确实也能达到规定的标准目的,但NumPy有1种更智慧的矢量情势。先总结prop的共计和cumsum,然后再通过searchsorted方法寻找0.5应有被插入在哪个岗位技艺确定保障不损坏顺序:

In [120]: prop_cumsum = df.sort_values(by='prop', ascending=False).prop.cumsum()

In [121]: prop_cumsum[:10]
Out[121]: 
260877    0.011523
260878    0.020934
260879    0.029959
260880    0.038930
260881    0.047817
260882    0.056579
260883    0.065155
260884    0.073414
260885    0.081528
260886    0.089621
Name: prop, dtype: float64

In [122]: prop_cumsum.values.searchsorted(0.5)
Out[122]: 116

出于数组索引是从0早先的,因而大家要给那么些结果加一,即最后结出为11七。拿一9〇伍年的数额来做个相比,那么些数字要小得多:

In [123]: df = boys[boys.year == 1900]

In [124]: in1900 = df.sort_values(by='prop', ascending=False).prop.cumsum()

In [125]: in1900.values.searchsorted(0.5) + 1
Out[125]: 25

明天就能够对全数year/sex组合试行这些总结了。按那多少个字段举办groupby管理,然后用1个函数总括各分组的那一个值:

def get_quantile_count(group, q=0.5):
    group = group.sort_values(by='prop', ascending=False)
    return group.prop.cumsum().values.searchsorted(q) + 1

diversity = top1000.groupby(['year', 'sex']).apply(get_quantile_count)
diversity = diversity.unstack('sex')

今昔,diversity那么些DataFrame具有七个时辰种类(每性格别各叁个,按年度索引)。通过IPython,你能够查阅其内容,还足以像在此以前那么绘制图表(如图14-7所示):

In [128]: diversity.head()
Out[128]: 
sex    F   M
year        
1880  38  14
1881  38  14
1882  38  15
1883  39  15
1884  39  16

In [129]: diversity.plot(title="Number of popular names in top 50%")

997755.com澳门葡京 12

图14-七 按年度计算的密度表

从图中能够见见,女孩名字的两种性总是比男孩的高,而且还在变得尤为高。读者们得以和煦分析一下切实可行是什么在使得那么些多样性(比方拼写情势的变通)。

    address(王五)=ASCII(W)+ASCII(W)=87+87=174;

DECLARE @begindate DATE =CAST('2017-12-1' AS date)
DECLARE @enddate DATE =CAST('2017-12-31' AS date)
BEGIN 

WITH
 t1 AS (SELECT sv.number AS n FROM MASTER.dbo.spt_values AS sv WHERE sv.[type]='P'),
 t2 AS ( SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rid  FROM t1 AS a CROSS APPLY t1 AS b)
----------------- 
--SELECT *FROM t2 

SELECT 
DATEADD(DAY,t2.rid-1,@begindate) as date
FROM t2 
WHERE t2.rid BETWEEN -1 AND (DATEDIFF(DAY,@begindate,@enddate)+1)
END 

“最终三个字母”的革命

200柒年,一名婴孩姓名钻探人口Laura沃特tenberg在她要好的网站上提议(http://www.babynamewizard.com):近百多年来,男孩名字在结尾二个字母上的分布发生了强烈的变动。为了驾驭具体的场合,笔者先是将全体出生数量在寒暑、性别以及末字母上实行了聚众:

# extract last letter from name column
get_last_letter = lambda x: x[-1]
last_letters = names.name.map(get_last_letter)
last_letters.name = 'last_letter'

table = names.pivot_table('births', index=last_letters,
                          columns=['sex', 'year'], aggfunc=sum)

接下来,小编选出具备自然代表性的三年,并出口前面几行:

In [131]: subtable = table.reindex(columns=[1910, 1960, 2010], level='year')

In [132]: subtable.head()
Out[132]: 
sex                 F                            M                    
year             1910      1960      2010     1910      1960      2010
last_letter                                                           
a            108376.0  691247.0  670605.0    977.0    5204.0   28438.0
b                 NaN     694.0     450.0    411.0    3912.0   38859.0
c                 5.0      49.0     946.0    482.0   15476.0   23125.0
d              6750.0    3729.0    2607.0  22111.0  262112.0   44398.0
e            133569.0  435013.0  313833.0  28655.0  178823.0  129012.0

接下去大家要求按总出生数对该表进行规范化管理,以便总结出各性别各末字母占总出生人数的比重:

In [133]: subtable.sum()
Out[133]: 
sex  year
F    1910     396416.0
     1960    2022062.0
     2010    1759010.0
M    1910     194198.0
     1960    2132588.0
2010    1898382.0
dtype: float64

In [134]: letter_prop = subtable / subtable.sum()

In [135]: letter_prop
Out[135]: 
sex                 F                             M                    
year             1910      1960      2010      1910      1960      2010
last_letter                                                            
a            0.273390  0.341853  0.381240  0.005031  0.002440  0.014980
b                 NaN  0.000343  0.000256  0.002116  0.001834  0.020470
c            0.000013  0.000024  0.000538  0.002482  0.007257  0.012181
d            0.017028  0.001844  0.001482  0.113858  0.122908  0.023387
e            0.336941  0.215133  0.178415  0.147556  0.083853  0.067959
...               ...       ...       ...       ...       ...       ...
v                 NaN  0.000060  0.000117  0.000113
0.000037  0.001434
w            0.000020  0.000031  0.001182  0.006329  0.007711  0.016148
x            0.000015  0.000037  0.000727  0.003965  0.001851  0.008614
y            0.110972  0.152569  0.116828  0.077349  0.160987  0.058168
z            0.002439  0.000659  0.000704  0.000170  0.000184  0.001831
[26 rows x 6 columns]

有了这一个字母比例数据之后,就能够生成一张各年度各性其余线形图了,如图1四-八所示:

import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 1, figsize=(10, 8))
letter_prop['M'].plot(kind='bar', rot=0, ax=axes[0], title='Male')
letter_prop['F'].plot(kind='bar', rot=0, ax=axes[1], title='Female',
                      legend=False)

997755.com澳门葡京 13

图1肆-8 男孩女孩名字中逐一末字母的比重

能够见见,从20世纪60年间初步,以字母”n”结尾的男孩名字出现了斐然的抓牢。回到从前创制的这一个完整表,按年度和性别对其开展标准化管理,并在男孩名字中精选多少个假名,最后进行转置以便将种种列做成二个光阴种类:

In [138]: letter_prop = table / table.sum()

In [139]: dny_ts = letter_prop.loc[['d', 'n', 'y'], 'M'].T

In [140]: dny_ts.head()
Out[140]: 
last_letter         d         n         y
year                                     
1880         0.083055  0.153213  0.075760
1881         0.083247  0.153214  0.077451
1882         0.085340  0.149560  0.077537
1883         0.084066  0.151646  0.079144
1884         0.086120  0.149915  0.080405

有了那些时间连串的DataFrame之后,就足以经过其plot方法绘制出一张趋势图了(如图1四-玖所示):

In [143]: dny_ts.plot()

997755.com澳门葡京 14

图1肆-九 各年出生的男孩中名字以d/n/y结尾的人口比例

    address(张帅)=ASCII(Z)+ASCII(S)=90+83=173;

 PS:因为体系从1早先,用Dateadd函数小编必要从0天初始加起(作为第三天),由此注意下上述代码的-1和+一的效率。

改为女孩名字的男孩名字(以及相反的事态)

另二个有意思的趋势是,早年流行于男孩的名字近期“变性了”,举例Lesley或Leslie。回到top1000数据集,寻觅里面以”lesl”伊始的一组名字:

In [144]: all_names = pd.Series(top1000.name.unique())

In [145]: lesley_like = all_names[all_names.str.lower().str.contains('lesl')]

In [146]: lesley_like
Out[146]: 
632     Leslie
2294    Lesley
4262    Leslee
4728     Lesli
6103     Lesly
dtype: object

下一场使用那些结果过滤其余的名字,并按名字分组总计出生数以查看绝对频率:

In [147]: filtered = top1000[top1000.name.isin(lesley_like)]

In [148]: filtered.groupby('name').births.sum()
Out[148]: 
name
Leslee      1082
Lesley     35022
Lesli        929
Leslie    370429
Lesly      10067
Name: births, dtype: int64

接下去,我们按性别和年份进行联谊,并按年度举办标准化管理:

In [149]: table = filtered.pivot_table('births', index='year',
   .....:                              columns='sex', aggfunc='sum')

In [150]: table = table.div(table.sum(1), axis=0)

In [151]: table.tail()
Out[151]: 
sex     F   M
year         
2006  1.0 NaN
2007  1.0 NaN
2008  1.0 NaN
2009  1.0 NaN
2010  1.0 NaN

末尾,就能够轻易绘制一张分性其余年度曲线图了(如图二-拾所示):

In [153]: table.plot(style={'M': 'k-', 'F': 'k--'})

997755.com澳门葡京 15

图1四-10 各年度使用“Lesley型”名字的男女比例

  倘若唯有这伍个关系人新闻须要展张开酒馆储,那几个Hash函数设计的很不好。首先,它浪费了大气的仓库储存空间,即使选拔char型数组存款和储蓄联系人音信的话,则最少须求开发17四*1二字节的长空,空间利用率唯有4/174,不到伍%;其它,依据Hash函数总结结果随后,address(张叁)和address(李4)具备一样的地方,那种现象称作争辨,对于1七10三个存款和储蓄空间中只供给仓库储存4条记下就生出了争辨,这样的Hash函数设计是很不客观的。所以在组织Hash函数时应竭尽思量入眼字的遍及特征来布署函数使得Hash地址随机均匀地遍及在全方位地址空间个中。经常有以下三种结构Hash函数的章程:

功用如图:

14.4 USDA食物数据库

美利坚联邦合众国农业部门(USDA)制作了1份有关食物血红蛋白音信的数据库。Ashley威廉姆斯制作了该数量的JSON版(http://ashleyw.co.uk/project/food-nutrient-database)。在那之中的笔录如下所示:

{
  "id": 21441,
  "description": "KENTUCKY FRIED CHICKEN, Fried Chicken, EXTRA CRISPY,
Wing, meat and skin with breading",
  "tags": ["KFC"],
  "manufacturer": "Kentucky Fried Chicken",
"group": "Fast Foods",
  "portions": [
    {
      "amount": 1,
      "unit": "wing, with skin",
      "grams": 68.0
    },

    ...
  ],
  "nutrients": [
    {
      "value": 20.8,
      "units": "g",
      "description": "Protein",
      "group": "Composition"
    },

    ...
  ]
}

每一个食品都包罗若干标志性属性以及三个有关营养成分和分量的列表。那种样式的数据不是很吻合分析专业,由此大家必要做一些规整化以使其具有更加好用的款型。

从地点列举的不胜网站下载并解压数据今后,你能够用别的喜欢的JSON库将其加载到Python中。笔者用的是Python内置的json模块:

In [154]: import json

In [155]: db = json.load(open('datasets/usda_food/database.json'))

In [156]: len(db)
Out[156]: 6636

db中的每种条款都以二个含有某种食品全部数量的字典。nutrients字段是2个字典列表,当中的种种字典对应一种淀粉成分:

In [157]: db[0].keys()
Out[157]: dict_keys(['id', 'description', 'tags', 'manufacturer', 'group', 'porti
ons', 'nutrients'])

In [158]: db[0]['nutrients'][0]
Out[158]: 
{'description': 'Protein',
 'group': 'Composition',
 'units': 'g',
 'value': 25.18}

In [159]: nutrients = pd.DataFrame(db[0]['nutrients'])

In [160]: nutrients[:7]
Out[160]: 
                   description        group units    value
0                      Protein  Composition     g    25.18
1            Total lipid (fat)  Composition     g    29.20
2  Carbohydrate, by difference  Composition     g     3.06
3                          Ash        Other     g     3.28
4                       Energy       Energy  kcal   376.00
5                        Water  Composition     g    39.28
6                       Energy       Energy    kJ  1573.00

在将字典列表转变为DataFrame时,可以只抽出个中的一有些字段。这里,我们将收取食品的名目、分类、编号以及创建商等新闻:

In [161]: info_keys = ['description', 'group', 'id', 'manufacturer']

In [162]: info = pd.DataFrame(db, columns=info_keys)

In [163]: info[:5]
Out[163]: 
                          description                   group    id  \
0                     Cheese, caraway  Dairy and Egg Products  1008   
1                     Cheese, cheddar  Dairy and Egg Products  1009
2                        Cheese, edam  Dairy and Egg Products  1018   
3                        Cheese, feta  Dairy and Egg Products  1019   
4  Cheese, mozzarella, part skim milk  Dairy and Egg Products  1028   
  manufacturer  
0               
1               
2               
3               
4               

In [164]: info.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6636 entries, 0 to 6635
Data columns (total 4 columns):
description     6636 non-null object
group           6636 non-null object
id              6636 non-null int64
manufacturer    5195 non-null object
dtypes: int64(1), object(3)
memory usage: 207.5+ KB

通过value_counts,你能够查看食品类别的布满情形:

In [165]: pd.value_counts(info.group)[:10]
Out[165]: 
Vegetables and Vegetable Products    812
Beef Products                        618
Baked Products                       496
Breakfast Cereals                    403
Fast Foods                           365
Legumes and Legume Products          365
Lamb, Veal, and Game Products        345
Sweets                               341
Pork Products                        328
Fruits and Fruit Juices              328
Name: group, dtype: int64

近年来,为了对全体三磷酸腺苷数据做一些解析,最简单易行的方法是将全部食品的营养成分整合到二个大表中。我们分多少个步骤来促成该目标。首先,将各食物的甲状腺素成分列表转变为一个DataFrame,并充分2个表示编号的列,然后将该DataFrame增添到二个列表中。最终通过concat将那么些东西连接起来就足以了:

顺手的话,nutrients的结果是:

In [167]: nutrients
Out[167]: 
                               description        group units    value     id
0                                  Protein  Composition     g   25.180   1008
1                        Total lipid (fat)  Composition     g   29.200   1008
2              Carbohydrate, by difference  Composition     g    3.060   1008
3                                      Ash        Other     g    3.280   1008
4                                   Energy       Energy  kcal  376.000   1008
...                                    ...          ...
...      ...    ...
389350                 Vitamin B-12, added     Vitamins   mcg    0.000  43546
389351                         Cholesterol        Other    mg    0.000  43546
389352        Fatty acids, total saturated        Other     g    0.072  43546
389353  Fatty acids, total monounsaturated        Other     g    0.028  43546
389354  Fatty acids, total polyunsaturated        Other     g    0.041  43546
[389355 rows x 5 columns]

小编意识那个DataFrame中无论怎么样都会有部分再度项,所以一贯丢掉就足以了:

In [168]: nutrients.duplicated().sum()  # number of duplicates
Out[168]: 14179

In [169]: nutrients = nutrients.drop_duplicates()

由于四个DataFrame对象中都有”group”和”description”,所感觉了明显到底哪个人是何人,大家须求对它们举办重命名:

In [170]: col_mapping = {'description' : 'food',
   .....:                'group'       : 'fgroup'}

In [171]: info = info.rename(columns=col_mapping, copy=False)

In [172]: info.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 6636 entries, 0 to 6635
Data columns (total 4 columns):
food            6636 non-null object
fgroup          6636 non-null object
id              6636 non-null int64
manufacturer    5195 non-null object
dtypes: int64(1), object(3)
memory usage: 207.5+ KB

In [173]: col_mapping = {'description' : 'nutrient',
   .....:                'group' : 'nutgroup'}
In [174]: nutrients = nutrients.rename(columns=col_mapping, copy=False)

In [175]: nutrients
Out[175]: 
                                  nutrient     nutgroup units    value     id
0                                  Protein  Composition     g   25.180   1008
1                        Total lipid (fat)  Composition     g   29.200   1008
2              Carbohydrate, by difference  Composition     g    3.060   1008
3                                      Ash        Other     g    3.280   1008
4                                   Energy       Energy  kcal  376.000   1008
...                                    ...          ...   ...      ...    ...
389350                 Vitamin B-12, added     Vitamins   mcg    0.000  43546
389351                         Cholesterol        Other    mg    0.000  43546
389352        Fatty acids, total saturated        Other     g    0.072  43546
389353  Fatty acids, total monounsaturated        Other     g    0.028  43546
389354  Fatty acids, total polyunsaturated        Other     g    0.041  43546
[375176 rows x 5 columns]

做完那么些,就足以将info跟nutrients合并起来:

In [176]: ndata = pd.merge(nutrients, info, on='id', how='outer')

In [177]: ndata.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 375176 entries, 0 to 375175
Data columns (total 8 columns):
nutrient        375176 non-null object
nutgroup        375176 non-null object
units           375176 non-null object
value           375176 non-null float64
id              375176 non-null int64
food            375176 non-null object
fgroup          375176 non-null object
manufacturer    293054 non-null object
dtypes: float64(1), int64(1), object(6)
memory usage: 25.8+ MB

In [178]: ndata.iloc[30000]
Out[178]: 
nutrient                                       Glycine
nutgroup                                   Amino Acids
units                                                g
value                                             0.04
id                                                6158
food            Soup, tomato bisque, canned, condensed
fgroup                      Soups, Sauces, and Gravies
manufacturer                                          
Name: 30000, dtype: object

大家以往得以依靠食物分类和果胶类型画出一张中位值图(如图1四-1一所示):

In [180]: result = ndata.groupby(['nutrient', 'fgroup'])['value'].quantile(0.5)

In [181]: result['Zinc, Zn'].sort_values().plot(kind='barh')

997755.com澳门葡京 16

图表14-1一 依照纤维素分类得出的锌中位值

万1稍微动一动脑子,就能够开采各胡萝卜素元素最为丰富的食物是怎样了:

by_nutrient = ndata.groupby(['nutgroup', 'nutrient'])

get_maximum = lambda x: x.loc[x.value.idxmax()]
get_minimum = lambda x: x.loc[x.value.idxmin()]

max_foods = by_nutrient.apply(get_maximum)[['value', 'food']]

# make the food a little smaller
max_foods.food = max_foods.food.str[:50]

出于获得的DataFrame相当的大,所以不便于在书里面整套打字与印刷出来。这里只交付”Amino
Acids”三磷酸腺苷分组:

In [183]: max_foods.loc['Amino Acids']['food']
Out[183]: 
nutrient
Alanine                          Gelatins, dry powder, unsweetened
Arginine                              Seeds, sesame flour, low-fat
Aspartic acid                                  Soy protein isolate
Cystine               Seeds, cottonseed flour, low fat (glandless)
Glutamic acid                                  Soy protein isolate
                                       ...                        
Serine           Soy protein isolate, PROTEIN TECHNOLOGIES INTE...
Threonine        Soy protein isolate, PROTEIN TECHNOLOGIES INTE...
Tryptophan        Sea lion, Steller, meat with fat (Alaska Native)
Tyrosine         Soy protein isolate, PROTEIN TECHNOLOGIES INTE...
Valine           Soy protein isolate, PROTEIN TECHNOLOGIES INTE...
Name: food, Length: 19, dtype: object

  一)直接定址法

997755.com澳门葡京 17

1四.伍 二零一一联邦选委会数据库

美利坚同盟国际联盟邦选委会发布了关于政治公投赞助方面包车型客车数码。在那之中囊括赞助者的真名、专门的学问、雇主、地址以及出资额等新闻。我们对二〇一二年美总统大选的数据集相比较感兴趣(http://www.fec.gov/disclosurep/PDownload.do)。作者在二零一三年六月下载的数据集是3个150MB的CSV文件(P00000001-ALL.csv),咱们先用pandas.read_csv将其加载进来:

In [184]: fec = pd.read_csv('datasets/fec/P00000001-ALL.csv')

In [185]: fec.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1001731 entries, 0 to 1001730
Data columns (total 16 columns):
cmte_id              1001731 non-null object
cand_id              1001731 non-null object
cand_nm              1001731 non-null object
contbr_nm            1001731 non-null object
contbr_city          1001712 non-null object
contbr_st            1001727 non-null object
contbr_zip           1001620 non-null object
contbr_employer      988002 non-null object
contbr_occupation    993301 non-null object
contb_receipt_amt    1001731 non-null float64
contb_receipt_dt     1001731 non-null object
receipt_desc         14166 non-null object
memo_cd              92482 non-null object
memo_text            97770 non-null object
form_tp              1001731 non-null object
file_num             1001731 non-null int64
dtypes: float64(1), int64(1), object(14)
memory usage: 122.3+ MB

该DataFrame中的记录如下所示:

In [186]: fec.iloc[123456]
Out[186]: 
cmte_id             C00431445
cand_id             P80003338
cand_nm         Obama, Barack
contbr_nm         ELLMAN, IRA
contbr_city             TEMPE
                    ...      
receipt_desc              NaN
memo_cd                   NaN
memo_text                 NaN
form_tp                 SA17A
file_num               772372
Name: 123456, Length: 16, dtype: object

你恐怕已经想出了大多情势从那么些大选赞助数据中抽出有关赞助人和声援方式的总计新闻。作者就要接下去的情节中牵线三种不一致的分析专门的学业(运用到近日截至已经学到的主意)。

简单看出,该数量中一贯不党派消息,由此最佳把它加进去。通过unique,你能够收获全体的候选人名单:

In [187]: unique_cands = fec.cand_nm.unique()

In [188]: unique_cands
Out[188]: 
array(['Bachmann, Michelle', 'Romney, Mitt', 'Obama, Barack',
       "Roemer, Charles E. 'Buddy' III", 'Pawlenty, Timothy',
       'Johnson, Gary Earl', 'Paul, Ron', 'Santorum, Rick', 'Cain, Herman',
       'Gingrich, Newt', 'McCotter, Thaddeus G', 'Huntsman, Jon',
       'Perry, Rick'], dtype=object)

In [189]: unique_cands[2]
Out[189]: 'Obama, Barack'

指明党派消息的法子之壹是采取字典:

parties = {'Bachmann, Michelle': 'Republican',
           'Cain, Herman': 'Republican',
           'Gingrich, Newt': 'Republican',
           'Huntsman, Jon': 'Republican',
           'Johnson, Gary Earl': 'Republican',
           'McCotter, Thaddeus G': 'Republican',
           'Obama, Barack': 'Democrat',
           'Paul, Ron': 'Republican',
           'Pawlenty, Timothy': 'Republican',
           'Perry, Rick': 'Republican',
           "Roemer, Charles E. 'Buddy' III": 'Republican',
           'Romney, Mitt': 'Republican',
           'Santorum, Rick': 'Republican'}

当今,通过这几个映射以及Series对象的map方法,你能够依照候选人姓名获得一组党派音讯:

In [191]: fec.cand_nm[123456:123461]
Out[191]: 
123456    Obama, Barack
123457    Obama, Barack
123458    Obama, Barack
123459    Obama, Barack
123460    Obama, Barack
Name: cand_nm, dtype: object

In [192]: fec.cand_nm[123456:123461].map(parties)
Out[192]: 
123456    Democrat
123457    Democrat
123458    Democrat
123459    Democrat
123460    Democrat
Name: cand_nm, dtype: object

# Add it as a column
In [193]: fec['party'] = fec.cand_nm.map(parties)

In [194]: fec['party'].value_counts()
Out[194]: 
Democrat      593746
Republican    407985
Name: party, dtype: int64

此间有三个必要小心的地方。第贰,该数据既包括扶持也席卷退款(负的出资额):

In [195]: (fec.contb_receipt_amt > 0).value_counts()
Out[195]: 
True     991475
False     10256
Name: contb_receipt_amt, dtype: int64

为了简化分析进度,作者限定该数据集只好有正的出资额:

In [196]: fec = fec[fec.contb_receipt_amt > 0]

出于Barack 奥巴马三保Mitt
Romney是最重大的两名候选人,所以本身还专程准备了三个子集,只含有针对他们多人的大选活动的帮忙音信:

In [197]: fec_mrbo = fec[fec.cand_nm.isin(['Obama, Barack','Romney, Mitt'])]

  取关键字依旧重大字的某部线性函数为Hash地址,即address(key)=a*key+b;如知道学生的学号从三千方始,最大为5000,则能够将address(key)=key-两千作为Hash地址。

最后:

凭借职业和雇主总计赞助信息

依据专业的鼎力相助音讯总计是另一种平时被研商的总括任务。举个例子,律师们更赞成于扶助民主党,而市肆主则更赞成于帮忙共和党。你能够不信任自个儿,本人看那3个数据就驾驭了。首先,按照职业总括出资总额,那一点也不细略:

In [198]: fec.contbr_occupation.value_counts()[:10]
Out[198]: 
RETIRED                                   233990
INFORMATION REQUESTED                      35107
ATTORNEY                                   34286
HOMEMAKER                                  29931
PHYSICIAN                                  23432
INFORMATION REQUESTED PER BEST EFFORTS     21138
ENGINEER                                   14334
TEACHER                                    13990
CONSULTANT                                 13273
PROFESSOR                                  12555
Name: contbr_occupation, dtype: int64

轻松看出,大多生意都关涉一样的主干事业项目,大概同同样东西有八种变体。上面包车型地铁代码片段能够清理一些这么的多少(将二个职业音信映射到另3个)。注意,这里玄妙地行使了dict.get,它同意尚未映射关系的差事也能“通过”:

occ_mapping = {
   'INFORMATION REQUESTED PER BEST EFFORTS' : 'NOT PROVIDED',
   'INFORMATION REQUESTED' : 'NOT PROVIDED',
   'INFORMATION REQUESTED (BEST EFFORTS)' : 'NOT PROVIDED',
   'C.E.O.': 'CEO'
}

# If no mapping provided, return x
f = lambda x: occ_mapping.get(x, x)
fec.contbr_occupation = fec.contbr_occupation.map(f)

本人对雇主消息也开始展览了同一的拍卖:

emp_mapping = {
   'INFORMATION REQUESTED PER BEST EFFORTS' : 'NOT PROVIDED',
   'INFORMATION REQUESTED' : 'NOT PROVIDED',
   'SELF' : 'SELF-EMPLOYED',
   'SELF EMPLOYED' : 'SELF-EMPLOYED',
}

# If no mapping provided, return x
f = lambda x: emp_mapping.get(x, x)
fec.contbr_employer = fec.contbr_employer.map(f)

近期,你能够经过pivot_table遵照党派和生意对数码进行联谊,然后过滤掉总出资额不足200万法郎的数额:

In [201]: by_occupation = fec.pivot_table('contb_receipt_amt',
   .....:                                 index='contbr_occupation',
   .....:                                 columns='party', aggfunc='sum')

In [202]: over_2mm = by_occupation[by_occupation.sum(1) > 2000000]

In [203]: over_2mm
Out[203]: 
party                 Democrat    Republican
contbr_occupation                           
ATTORNEY           11141982.97  7.477194e+06
CEO                 2074974.79  4.211041e+06
CONSULTANT          2459912.71  2.544725e+06
ENGINEER             951525.55  1.818374e+06
EXECUTIVE           1355161.05  4.138850e+06
...                        ...           ...
PRESIDENT           1878509.95  4.720924e+06
PROFESSOR           2165071.08  2.967027e+05
REAL ESTATE          528902.09  1.625902e+06
RETIRED            25305116.38  2.356124e+07
SELF-EMPLOYED        672393.40  1.640253e+06
[17 rows x 2 columns]

把这个数量做成柱状图看起来会愈加透亮(’barh’代表水平柱状图,如图1四-1贰所示):

In [205]: over_2mm.plot(kind='barh')

997755.com澳门葡京 18

图1四-1二 对各党派总出资额最高的事情

您只怕还想领悟一下对奥巴马三保Romney总出资额最高的工作和商号。为此,大家先对候选人实行分组,然后利用本章前边介绍的类似top的办法:

def get_top_amounts(group, key, n=5):
    totals = group.groupby(key)['contb_receipt_amt'].sum()
    return totals.nlargest(n)

然后依据职业和雇主张开联谊:

In [207]: grouped = fec_mrbo.groupby('cand_nm')

In [208]: grouped.apply(get_top_amounts, 'contbr_occupation', n=7)
Out[208]: 
cand_nm        contbr_occupation    
Obama, Barack  RETIRED                  25305116.38
               ATTORNEY                 11141982.97
               INFORMATION REQUESTED     4866973.96
               HOMEMAKER                 4248875.80
               PHYSICIAN                 3735124.94
                                           ...     
Romney, Mitt   HOMEMAKER                 8147446.22
               ATTORNEY                  5364718.82
               PRESIDENT                 2491244.89
               EXECUTIVE                 2300947.03
               C.E.O.                    1968386.11
Name: contb_receipt_amt, Length: 14, dtype: float64

In [209]: grouped.apply(get_top_amounts, 'contbr_employer', n=10)
Out[209]: 
cand_nm        contbr_employer      
Obama, Barack  RETIRED                  22694358.85
               SELF-EMPLOYED            17080985.96
               NOT EMPLOYED              8586308.70
               INFORMATION REQUESTED     5053480.37
               HOMEMAKER                 2605408.54
                                           ...     
Romney, Mitt   CREDIT SUISSE              281150.00
               MORGAN STANLEY             267266.00
               GOLDMAN SACH & CO.         238250.00
               BARCLAYS CAPITAL           162750.00
               H.I.G. CAPITAL             139500.00
Name: contb_receipt_amt, Length: 20, dtype: float64

  二)平方取中国和法国

  关于With
关键字、row_nunber()over()开窗函数 以及cross
apply请您自行脑补学习,避防管中窥豹

对出资额分组

还是能对该数量做另壹种极度实用的辨析:利用cut函数依照出资额的大小将数据离散化到多少个面元中:

In [210]: bins = np.array([0, 1, 10, 100, 1000, 10000,
   .....:                  100000, 1000000, 10000000])

In [211]: labels = pd.cut(fec_mrbo.contb_receipt_amt, bins)

In [212]: labels
Out[212]: 
411         (10, 100]
412       (100, 1000]
413       (100, 1000]
414         (10, 100]
415         (10, 100]
             ...     
701381      (10, 100]
701382    (100, 1000]
701383        (1, 10]
701384      (10, 100]
701385    (100, 1000]
Name: contb_receipt_amt, Length: 694282, dtype: category
Categories (8, interval[int64]): [(0, 1] < (1, 10] < (10, 100] < (100, 1000] < (1
000, 10000] <
                                  (10000, 100000] < (100000, 1000000] < (1000000,
 10000000]]

明天得以依附候选人姓名以及面元标签对奥巴马和罗姆尼数据实行分组,以得到三个柱状图:

In [213]: grouped = fec_mrbo.groupby(['cand_nm', labels])

In [214]: grouped.size().unstack(0)
Out[214]: 
cand_nm              Obama, Barack  Romney, Mitt
contb_receipt_amt                               
(0, 1]                       493.0          77.0
(1, 10]                    40070.0        3681.0
(10, 100]                 372280.0       31853.0
(100, 1000]               153991.0       43357.0
(1000, 10000]              22284.0       26186.0
(10000, 100000]                2.0           1.0
(100000, 1000000]              3.0           NaN
(1000000, 10000000]            4.0           NaN

从这一个数据中得以见见,在小额赞助方面,奥巴马获得的数量比Romney多得多。你还足以对出资额求和并在面元内规格化,以便图形化彰显两位候选人各类帮扶额度的比重(见图1四-一三):

In [216]: bucket_sums = grouped.contb_receipt_amt.sum().unstack(0)

In [217]: normed_sums = bucket_sums.div(bucket_sums.sum(axis=1), axis=0)

In [218]: normed_sums
Out[218]: 
cand_nm              Obama, Barack  Romney, Mitt
contb_receipt_amt                               
(0, 1]                    0.805182      0.194818
(1, 10]                   0.918767      0.081233
(10, 100]                 0.910769      0.089231
(100, 1000]               0.710176      0.289824
(1000, 10000]             0.447326      0.552674
(10000, 100000]           0.823120      0.176880
(100000, 1000000]         1.000000           NaN
(1000000, 10000000]       1.000000           NaN

In [219]: normed_sums[:-2].plot(kind='barh')

997755.com澳门葡京 19

图1四-一三 两位候选人收到的各类馈赠额度的总额比例

本身清除了八个最大的面元,因为这几个不是由个体捐献的。

还足以对该分析进度做过多的提炼和改正。举个例子说,能够依附赞助人的全名和邮政编码对数据举行联谊,以便寻找哪个人开始展览了频仍小额捐款,哪些人又拓展了1次或频仍大数额捐款。小编强烈建议你下载这几个数量并友好寻觅一下。

  对首要字张开平方运算,然后取结果的中游3位作为Hash地址。假使有以下器重字体系{4二一,4二叁,436},平方之后的结果为{177二四1,17892玖,1903玖陆},那么能够取{7二,8玖,00}作为Hash地址。

 

依照州计算赞助音信

听别人说候选人和州对数码进行联谊是例行操作:

In [220]: grouped = fec_mrbo.groupby(['cand_nm', 'contbr_st'])

In [221]: totals = grouped.contb_receipt_amt.sum().unstack(0).fillna(0)

In [222]: totals = totals[totals.sum(1) > 100000]

In [223]: totals[:10]
Out[223]: 
cand_nm    Obama, Barack  Romney, Mitt
contbr_st                             
AK             281840.15      86204.24
AL             543123.48     527303.51
AR             359247.28     105556.00
AZ            1506476.98    1888436.23
CA           23824984.24   11237636.60
CO            2132429.49    1506714.12
CT            2068291.26    3499475.45
DC            4373538.80    1025137.50
DE             336669.14      82712.00
FL            7318178.58    8338458.81

倘使对各行除以总赞助额,就能够拿走各候选人在全州的总赞助额比例:

In [224]: percent = totals.div(totals.sum(1), axis=0)

In [225]: percent[:10]
Out[225]: 
cand_nm    Obama, Barack  Romney, Mitt
contbr_st                             
AK              0.765778      0.234222
AL              0.507390      0.492610
AR              0.772902      0.227098
AZ              0.443745      0.556255
CA              0.679498      0.320502
CO              0.585970      0.414030
CT              0.371476      0.628524
DC              0.810113      0.189887
DE              0.802776      0.197224
FL              0.467417      0.532583

  3)折叠法

14.6 总结

咱俩早就完成了本文的最终1章。附录中有一部分额外的内容,可能对您有用。

本书第二版问世已经有伍年了,Python已经变为了1个风靡的、分布采取的数码解析语言。你从本书中学到的办法,在一定长的一段时间都是可用的。作者愿意本书介绍的工具和库对你的工作有用。


第三章 妄图干活
第二章
Python语法基础,IPython和Jupyter
第一章
Python的数据结构、函数和文件
第5章
NumPy基础:数组和矢量计算
第5章 pandas入门
第5章
数据加载、存款和储蓄与文件格式
第10章 数据清洗和筹算
第十章
数据整理:聚合、合并和重塑
第七章 绘图和可视化
第九章 数据聚合与分组运算
第3一章 时间类别
第二二章 pandas高端应用
第叁三章 Python建立模型库介绍
第二四章 数据解析案例
附录A NumPy高等应用
附录B
更加多关于IPython的内容(完)


  将首要字拆分成几片段,然后将这几部分构成在共同,以特定的不二等秘书籍举办转载产生Hash地址。要是知道图书的ISBN号为890③-二四一-二三,能够将address(key)=8玖+0三+二四+1二+叁用作Hash地址。

  四)除留取余法

  要是理解Hash表的最大尺寸为m,能够取一点都不大于m的最大质数p,然后对根本字张开取余运算,address(key)=key%p。

  在这里p的选取分外关键,p选取的好的话,能够最大程度地缩减冲突,p一般取相当小于m的最大质数。

二.Hash表大小的规定

  Hash表大小的鲜明也充足首要,假使Hash表的空间远远大于最终实际存款和储蓄的笔录个数,则导致了一点都不小的长空浪费,假如选取小了的话,则轻便产生争执。在实情中,一般必要基于最终记录存款和储蓄个数和根本字的布满特点来鲜明Hash表的高低。还有一种境况时只怕事先不精晓最终供给仓库储存的笔录个数,则供给动态维护Hash表的容积,此时或者供给重新总括Hash地址。

三.抵触的减轻

  在上述例子中,发生了争辨现象,因而需求艺术来消除,不然记录不可能进行科学的囤积。平常状态下有二种消除办法:

  1)开放定址法

  即当三个注重字和另一个根本字发生争执时,使用某种探测技能在Hash表中形成2个探测类别,然后沿着这么些探测体系依次查找下去,当遭逢1个空的单元时,则插入当中。相比较常用的探测方法有线性探测法,比如有壹组第三字{12,13,二5,2三,3八,3四,陆,8四,九一},Hash表长为1四,Hash函数为address(key)=key%1一,当插入1二,一3,25时能够直接插入,而当插入贰三时,地址一被占用了,由此沿着地址1所有人家往向下探底测(探测步长能够依附事态而定),直到探测到地点四,发掘为空,则将贰三插入在那之中。

  二)链地址法

   选用数组和链表相结合的措施,将Hash地址同样的笔录存款和储蓄在一张线性表中,而每张表的表头的序号即为计算获得的Hash地址。如上述例子中,选拔链地址法产生的Hash表存款和储蓄表示为: 
 

997755.com澳门葡京 20

   纵然能够运用部分方法去收缩争论,不过争执是心有余而力不足完全制止的。由此需求基于实际景况采取化解争持的章程。

四.Hash表的平均查找长度

  Hash表的平分查找长度包括查找成功时的平均查找长度和查找未果时的平分查找长度。

  查找成功时的平均查找长度=表中各个成分查找成功时的相比较次数之和/表七月素个数;

  查找不成事时的平均查找长度也正是在表中找寻成分不成功时的平均相比较次数,能够知晓为向表中插入某个成分,该因素在各种岗位都有一点都不小或然,然后总括出在每个地方能够插入时供给相比较的次数,再除以表长即为查找不成事时的平均查找长度。

  下边举个例证:

  有壹组第2字{2三,1贰,1四,二,3,伍},表长为1四,Hash函数为key%1一,则器重字在表中的存款和储蓄如下:

  地址     0     1     2     3      4     5    6   7   8    9  10   11
  12    13

  关键字        12    23   14     2     3    5

 相比较次数         一      1     一     3     叁     二

  因而查找成功时的平均查找长度为(壹+一+一+三+三+二)/陆=1陆分之一;

  查找未果时的平均查找长度为(1+七+六+伍+4+叁+二+一+1+1+1+一+一+一)/1四=38/1四;

  这里有3个定义装填因子=表中的记录数/哈希表的尺寸,假诺装填因子越小,注脚表中还有为数不少的空单元,则发生争执的可能性越小;而堵塞因子越大,则发生争论的大概就越大,在查找时所花费的光阴就越来越多。因而,Hash表的平均查找长度和回填因子有关。

5.Hash表的得失

  Hash表存在的长处总来讲之,可以在常数级的时日复杂度上开始展览检索,并且插入数据和删除数据相比易于。然而它也有几许缺点,比如不帮助排序,一般比用线性表存款和储蓄必要越来越多的空中,并且记录的根本字无法再度。

 

代码完结(这一个是应用线性探测法,步长为一):

997755.com澳门葡京 21😉

/*Hash表,采用数组实现,2012.9.28*/ 

#include<stdio.h>
#define DataType int
#define M 30

typedef struct HashNode    
{
    DataType data;    //存储值 
    int isNull;           //标志该位置是否已被填充 
}HashTable;

HashTable hashTable[M];

void initHashTable()     //对hash表进行初始化 
{
    int i;
    for(i = 0; i<M; i++)
    {
        hashTable[i].isNull = 1;    //初始状态为空 
    }
}

int getHashAddress(DataType key)    //Hash函数 
{
    return key % 29;     //Hash函数为 key%29 
}

int insert(DataType key)    //向hash表中插入元素 
{
    int address = getHashAddress(key);       
    if(hashTable[address].isNull == 1)  //没有发生冲突 
    {
        hashTable[address].data = key;
        hashTable[address].isNull = 0;
    }
    else    //当发生冲突的时候 
    {
        while(hashTable[address].isNull == 0 && address<M)
        {
            address++;     //采用线性探测法,步长为1 
        }
        if(address == M)    //Hash表发生溢出 
            return -1;
        hashTable[address].data = key;
        hashTable[address].isNull = 0;
    }
    return 0;
}

int find(DataType key)      //进行查找 
{
    int address = getHashAddress(key);
    while( !(hashTable[address].isNull == 0 && hashTable[address].data == key && address<M))
    {
        address++;
    } 
    if( address == M)
        address = -1;
    return address;
}


int main(int argc, char *argv[])
{
    int key[]={123,456,7000,8,1,13,11,555,425,393,212,546,2,99,196};
    int i;
    initHashTable();
    for(i = 0; i<15; i++)
    {
        insert(key[i]);
    }

    for(i = 0; i<15; i++)
    {
        int address;
        address = find(key[i]);
        printf("%d %d\n", key[i],address);
    }
    return 0;
}

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website