知识点:序列化和反序列化
1.使用'w'写入的数据只能是字符串或者二进制,否则会报错
info = {'name':'buyang', 'age':28}
fr = open('test.txt', 'w')
fr.write(info)
TypeError: write() argument must be str, not dict
稍作修改:
info = {'name':'buyang', 'age':28}
fr = open('test.txt', 'w')
fr.write(str(info))
文本中的内容为:{'name': 'buyang', 'age': 28}
如果此时想将写入的内容恢复过来,恢复是指恢复成字典,我们使用
fr = open('test.txt', 'r')
data = fr.read()
只能得到字符串:{'name': 'buyang', 'age': 28},此时并不是字典,此时需要用到序列化和反序列化:
写入的时候是这样操作:
import json
info = {'name': 'buyang', 'age': 28}
f = open('test.txt', 'w')
f.write( json.dumps(info) ) #json.dumps(info)将info的指向内容变为字符串
读的时候:
import json
fr = open('test.txt', 'r')
data = json.loads(fr.read())
print(data)
print(data['name']) # 结果:{'name': 'buyang', 'age': 28} buyang, 表明读出的是字典
json只能处理简单的数据类型,如字符串,列表,字典等,另外一个模块pickle可以处理更多种类类型,由于并未用到pickle的相关知识,所有此处不多做介绍。
书上代码:
path = 'E:\数据分析代码数据\pydata-book-2nd-edition\datasets\\bitly_usagov\example.txt'
\\bitly_usagov,两个\\中前一个转义,防止出现\b
for line in open(path): #open(path)是iteration对象,可以直接读出文本中的每个字典
print(line)
所以可以使用一个列表生成式:
import json
path = 'E:\数据分析代码数据\pydata-book-2nd-edition\datasets\\bitly_usagov\example.txt'
records = [json.loads(line) for line in open(path)]
print(records[0]) #读出来的是列表而不是str,可以进行records[0]['tz']的操作
提取每个字典中的时区信息:
import json
path = 'E:\数据分析代码数据\pydata-book-2nd-edition\datasets\\bitly_usagov\example.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[:10]) #只提取前10个
['America/New_York', 'America/Denver', 'America/New_York', 'America/Sao_Paulo', 'America/New_York', 'America/New_York', 'Europe/Warsaw', '', '', ''],注意到有3个是空的
编写一段对时区计数的函数:
def get_counts(sequence):
counts = {}
for x in sequence:
if x in counts:
counts[x] += 1
else:
counts[x] = 1
return counts
print(get_counts(time_zones))
排序函数:
def top_counts(count_dict):
value_key_pairs = [(tz, count) for tz,count in count_dict.items()]
value_key_pairs_sort = sorted(value_key_pairs, key=lambda x:x[1], reverse=True)
return value_key_pairs_sort
使用pandas:
import json
from pandas import DataFrame, Series
import pandas as pd
import numpy as np
path = 'E:\数据分析代码数据\pydata-book-2nd-edition\datasets\\bitly_usagov\example.txt'
records = [json.loads(line) for line in open(path)]
frame = DataFrame(records)
print(frame)
frame是<class 'pandas.core.frame.DataFrame'>,共1560行 * 18列
print(frame['tz'][:10])
显示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
发现在'tz'特征列前10个数中有3个值是空白,稍后将进行填补空白
tz_counts = frame['tz'].value_counts()
print(tz_counts[:10])
这里的.value_counts()的功能是按 'tz' 特征的特征值出现次数进行降序排序,暂时还未用到其他改变函数参数的功能
接下来是填补空缺,有两种空缺,第一种是 'tz':'',即tz特征下是空白,第二种更过分,直接没有'tz'这个特征(关键字),两种空缺的填补方式如下:
#用'Missing'替代缺失值,缺失值指的是有120个字典数据中没有'tz'这个关键字
#填补后从没有'tz'关键字变为 'tz':'Missing'
clean_tz = frame['tz'].fillna('Missing')
#用'Unknown'替代'tz'关键字下为的空白,如'tz':''变为'tz':'Unknown'
clean_tz[clean_tz == ''] = 'Unknown'
clean_tz是在frame['tz']的基础上生成的,第一步之后clean_tz是填补了第二种缺失值之后的'tz'特征下的特征值全体,接下来开始在此基础上填补第一种缺失值。如果不填补第二种缺失值,可以写成:
frame['tz'][frame['tz'] == ''] = 'Unknown'
print(frame['tz'][:10])
两种缺失值都填补后进行排序:
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 #120个字典没有关键字'tz'
Europe/London 74
Asia/Tokyo 37
Pacific/Honolulu 36
Europe/Madrid 35
还可以直接使用tz_counts[:10]作为对象进行绘图
需要 from pylab import *
tz_counts[:10].plot(kind='barh',rot=0)
show() #在pycharm中必须要show()才能显示绘图
print(frame.tz[:10])
print(frame['tz'][:10])
这两条语句的意思相同
def dropna(self, axis=0, how='any', thresh=None, subset=None,inplace=False)
具体解释见:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html
print(frame.a[:5])
0 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKi...
1 GoogleMaps/RochesterNY
2 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT ...
3 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8)...
4 Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKi...
frame.a.dropna()
去除a特征中所有特征值中NaN的值
print( [x.split()[0] for x in frame.a[:5].dropna()] )
['Mozilla/5.0', 'GoogleMaps/RochesterNY', 'Mozilla/4.0', 'Mozilla/5.0', 'Mozilla/5.0']
Series函数:https://www.cnblogs.com/linux-wangkun/p/5903380.html
results = Series( [x.split()[0] for x in frame.a.dropna()] ) #去除了NaN
print(results[:5])
0 Mozilla/5.0
1 GoogleMaps/RochesterNY
2 Mozilla/4.0
3 Mozilla/5.0
4 Mozilla/5.0
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
print(frame.a[:20].notnull())
0 True
1 True
2 True
3 True
4 True
5 True
6 True
7 True
8 True
9 True
10 True
11 True
12 True
13 False #序号13的数据本来是NaN,所以显示False
14 True
15 True
16 True
17 True
18 True
19 True
用此方法去除没有'a'特征的数据(有特征但没有数据会显示空白,没有该特征只会显示NaN)
frame[frame.a.notnull()]
然后根据a特征的值来分辨各行是否是Windows
operating_system = np.where( cframe['a'].str.contains('Windows'), 'Windows', 'Not Windows' )
由Numpy中的where函数实现,按照a特征中的特征值中的字符串中是否含有'Windows'分为'Windows'和'Not Windows'两类
print( operating_system[:5] )
返回:['Windows' 'Not Windows' 'Windows' 'Not Windows' 'Windows'],数据类型是<class 'numpy.ndarray'>
接下来根据时区和新的到的操作系统列表对数据进行分组:
by_tz_os = cframe.groupby( ['tz', operating_system] )
然后使用size()进行计数,用unstack()对计数结果进行重塑:
def unstack(self, level=-1, fill_value=None)
关于unstack的介绍:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.unstack.html
并将NaN位置替换为数值0
agg_counts = by_tz_os.size().unstack().fillna(0)
前10个数据
Not Windows Windows
tz245.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特征的特征值的所有数据中(没有地区信息的所有数据),Not Windows 和 Windows的数量
这些知识都在下列章节有详细讲解,此处不做过多介绍。