利用Python进行数据分析——python数据分析初窥

本文将要向你介绍的是用于高效处理数据的Python工具。虽然读者各自工作的最终目的千差万别,但基本都需要完成以下几个大类的任务:

  • 与外界进行交互
    读写各种各样的文件格式和数据库。
  • 准备
    对数据进行清理、修整、整合、规范化、重塑、切片切块、变形等处理以便进行分析。
  • 转换
    对数据集做一些数学和统计运算以产生新的数据集。比如说,根据分组变量对一个大表进行聚合。
  • 建模和计算
    将数据跟统计模型、机器学习算法或其他计算工具联系起来。
  • 展示
    创建交互式的或静态的图片或文字摘要。

我将在本章中给出一些范例数据集,并讲解我们能对其做些什么。这些例子仅仅是为了提起你的兴趣,因此只会在一个比较高的层次进行讲解。即使你从来没用过这些东西也没关系,本书后续的章节将会对此进行非常详细的讲解。

在这些代码示例中,你可以看到诸如In [15]:之类的输入输出提示符,它们来自IPython shell。

来自bit.ly的1.usa.gov数据

2011年,URL缩短服务bit.ly跟美国政府网站usa.gov合作,提供了一份从生成.gov或.mil短链接的用户那里收集来的匿名数据。
以每小时快照为例,文件中各行的格式为JSON(即JavaScript Object Notation,这是一种常用的Web数据格式)。例如,如果我们只读取某个文件中的第一行,那么你所看到的结果应该是下面这样:

In [15]: path = 'ch02/usagov_bitly_data2012-03-16-1331923249.txt'
In [16]: open(path).readline()
Out[16]: '{ "a": "Mozilla\\/5.0 (Windows NT 6.1; WOW64) AppleWebKit\\/535.11 (KHTML, like US,en;q=0.8", "hh": "1.usa.gov", "r": "http:\\/\\/www.facebook.com\\/l\\/7AQEFzjSi

Python有许多内置或第三方模块可以将JSON字符串转换成Python字典对象。这里,我将使用json模块及其loads函数逐行加载已经下载好的数据文件:

import json
path = 'ch02/usagov_bitly_data2012-03-16-1331923249.txt'
records = [json.loads(line) for line in open(path)]

现在,records对象就成为一组Python字典了:

{
'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]
}

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

假设我们想要知道该数据集中最常出现的是哪个时区(即tz字段),得到答案的办法有很多。首先,我们用列表推导式取出一组时区:

import json
path='pydata-book-master/ch02/usagov_bitly_data2012-03-16-1331923249.txt'
records=[json.loads(line) for line in open(path)]
time_zones=[rec['tz'] for rec in records if 'tz' in rec]
print(time_zones)

结果为:

['America/New_York', 'America/Denver', 'America/New_York', 'America/Sao_Paulo', 'America/New_York', 'America/New_York', 'Europe/Warsaw', '', '', '', 'America/Los_Angeles', 'America/New_York', 'America/New_York', 'America/New_York', 'Asia/Hong_Kong', 'Asia/Hong_Kong', 'America/New_York', 'America/Denver', 'Europe/Rome', 'Africa/Ceuta', 'America/New_York', 'America/New_York', 'America/New_York', 'Europe/Madrid', 'Asia/Kuala_Lumpur', 'Asia/Nicosia', 'America/Sao_Paulo', '', '', 'Europe/London', 'America/New_York', 'Pacific/Honolulu', 'America/Chicago', '', '', 'Pacific/Honolulu', '',

我们可以看到有些是未知的(即空的)。虽然可以将它们过滤掉,但现在暂时先留着。接下来,为了对时区进行计数,这里介绍两个办法:一个较难(只使用标准Python库),另一个较简单(使用pandas)。计数的办法之一是在遍历时区的过程中将计数值保存在字典中:

import json
from collections import defaultdict

def get_counts(sequece):
    counts=defaultdict(int) #所有的值均被初始化为0
    for s in sequece:
        counts[s]+=1
    return counts

path='pydata-book-master/ch02/usagov_bitly_data2012-03-16-1331923249.txt'
records=[json.loads(line) for line in open(path)]
time_zones=[rec['tz'] for rec in records if 'tz' in rec]
print(time_zones[:])
counts=get_counts(time_zones)
print(counts)

我将代码写到函数中是为了获得更高的可重用性。要用它对时区进行处理,只需将time_zones传入即可:
在这里插入图片描述
如果想要得到前10位的时区及其计数值,我们需要用到一些有关字典的处理技巧:

def top_counts(count_dict,n=10):
    value_key_pairs={(count,tz) for tz,count in count_dict.items()}
    return sorted(value_key_pairs)[-n:]
print(top_counts(count_dict=counts))

输出为:

[(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类,它能使这个
任务变得更简单:

from collections import Counter
counts=Counter(time_zones)
print(counts.most_common(10))

在这里插入图片描述

用pandas对时区进行计数

DataFrame是pandas中最重要的数据结构,它用于将数据表示为一个表格。从一组原始记录中创建DataFrame是很简单的:

from pandas import DataFrame,Series
import pandas as pd
import numpy as np
import json

path='pydata-book-master/ch02/usagov_bitly_data2012-03-16-1331923249.txt'
records=[json.loads(line) for line in open(path)]
frame = DataFrame(records)
print(frame['tz'][:10])
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

然后,我们想利用绘图库(即matplotlib)为这段数据生成一张图片。为此,我们先给记录中未知或缺失的时区填上一个替代值。fillna函数可以替换缺失值(NA),而未知值(空字符串)则可以通过布尔型数组索引加以替换:

clean_tz=frame['tz'].fillna('Missing') #缺失值就是缺少该'tz'的value
clean_tz[clean_tz=='']='Unknown' #空值就是含有'tz',但value=''
tz_counts=clean_tz.value_counts()
print(tz_counts[:10])

输出如下:

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

利用counts对象的plot方法即可得到一张水平条形图:

import matplotlib.pyplot as plt
tz_counts[:10].plot(kind='barh',rot=0)
plt.show()

在这里插入图片描述
将这些"agent"字符串中的所有信息都解析出来是一件挺郁闷的工作。不过只要你掌握了Python内置的字符串函数和正则表达式,事情就好办了。比如说,我们可以将这种字符串的第一节(与浏览器大致对应)分离出来并得到另外一份用户行为摘要:

from pandas import DataFrame,Series
import pandas as pd
import numpy as np
import json

path='pydata-book-master/ch02/usagov_bitly_data2012-03-16-1331923249.txt'
records=[json.loads(line) for line in open(path)]
frame = DataFrame(records)
results=Series([x.split()[0] for x in frame.a.dropna()]) #dropna=drop N/A 去掉缺失值  x.split()以空格为界限
print(results[:5])

输出为:

0               Mozilla/5.0
1    GoogleMaps/RochesterNY
2               Mozilla/4.0
3               Mozilla/5.0
4               Mozilla/5.0

使用value_counts统计每个出现的频度:

print(results.value_counts()[:8])

输出为:

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

现在,假设你想按Windows和非Windows用户对时区统计信息进行分解。为了简单起见,我们假定只要agent字符串中含有"Windows"就认为该用户为Windows用户。由于有的agent缺失,所以首先将它们从数据中移除:

from pandas import DataFrame,Series
import pandas as pd
import numpy as np
import json

path='pydata-book-master/ch02/usagov_bitly_data2012-03-16-1331923249.txt'
records=[json.loads(line) for line in open(path)]
frame = DataFrame(records)

cframe=frame[frame.a.notnull()]
operating_system=np.where(cframe['a'].str.contains('Windows'),'Windows','Not Windows')
print(operating_system[:5])

输出为:

['Windows' 'Not Windows' 'Windows' 'Not Windows' 'Windows']

接下来就可以根据时区和新得到的操作系统列表对数据进行分组了:

by_tz_os = cframe.groupby(['tz', operating_system])
agg_counts = by_tz_os.size().unstack().fillna(0)
print(agg_counts[:10])
indexer = agg_counts.sum(1).argsort()
print(indexer[:10])

通过size对分组结果进行计数(类似于上面的value_counts函数),并利用unstack对计数结果进行重塑。
为了选取最常出现的时区,根据agg_counts中的行数构造了一个间接索引数组。
输出为:

                                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
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

暂且只介绍到这里,我们后面会对上面用到的没用到的函数进行一一分析,本文只是初窥门径。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值