《利用python進行數據分析》讀書筆記 --第1、二章 準備與例子

第一章 準備工做html

今天開始碼這本書--《利用python進行數據分析》。R和python都得會用才行,這是碼這本書的緣由。首先按照書上說的進行安裝,google下載了epd_free-7.3-1-win-x86.msi,譯者建議按照做者的版本安裝,EPDFree包括了Numpy,Scipy,matplotlib,Chaco,IPython.這裏的pandas須要本身安裝,對應版本爲pandas-0.9.0.win32-py2.7.exe.數據下載地址:github.com/pydata/pydata-book.下面是一個文檔:python

Welcome to Python For Data Analysis’s documentation!

http://pda.readthedocs.org/en/latest/

第二章 引言git

本章是一些例子。github

一、來自bit.ly的1.usa.gov數據json

首先,遇到的問題是pycharm的中文編碼問題,注意IDEencoding改成utf-8,同時文件最開始加#-*- encoding:utf-8 -*-,同時含有中文的字符串記得加u。數組

下面是代碼:數據結構

# -*- encoding: utf-8 -*-
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from collections import defaultdict
from collections import Counter
#注意這裏的中文路徑
path = u'D:\\你好\\usagov_bitly_data2012-03-16-1331923249.txt'
print open(path).readline()

#注意這裏的json模塊中的loads函數將字符串轉換爲字典,很是有用!
#注意這裏的縮略循環形式
records = [json.loads(line) for line in open(path)]

print records[0]
print type(records)
print type(records[0])
print records[0]['tz']

#注意這裏的判斷條件
time_zones = [rec['tz'] for rec in records if 'tz' in rec]
print time_zones[:10]

#下面定義函數對時區進行計數統計,注意這裏計數的方式,注意這裏的字典初始化方式
def get_counts(squence):
    counts = defaultdict(int)
    for x in squence:
        counts[x] += 1
    return counts

counts = get_counts(time_zones)
print counts['America/New_York']
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:]
#這裏是打印最後面的十個數,值得注意的是從倒數第十個開始一直到最後一個
print top_counts(counts)
#這裏的Counter是一個神器,做者真實強大
counts = Counter(time_zones)

print counts.most_common(10)

上面是利用python標準庫中的函數進行數據分析。須要注意的幾個方面:app

一、關於列表索引的說明:函數

a = range(0,10,1)
a[0] >>>0
a[-1] >>> 9
a[:5] >>> [0,1,2,3,4]
a[0:2] >>> [0,1]
a[-3:-1] >>> [7,8]
a[-3:] >>> [7,8,9]
a[-1:-3:-1] >>> [9,8]
a[::2] >>> [0,2,4,6,8]
說明:
一、索引包含第一個,不包含第一個冒號後面的部分
二、符號表示從後面開始計數
三、第二個冒號後面是間隔,若是有負號,表示從後面開始計數,例如a[-1:-3]這種表示方式獲得空列表。

二、關於模塊 collections 的應用,見下面的地址:google

http://www.zlovezl.cn/articles/collections-in-python/

collections 主要包括下面幾個「數據類型」:namedtuple() 生成可使用名字來訪問元素內容的tuple子類;deque()雙端隊列,它最大的好處就是實現了從隊列 頭部快速增長和取出對象;Counter用來統計個數,字典、列表、字符串都能用,很方便;OrderedDict 生成有序字典;defaultdict 也有用 好比 defaultdict(int) 表示字典中每一個值都是int型,defaultdict(list)表示字典每一個值都是列表。更多更詳細的內容見:

https://docs.python.org/2/library/collections.html#module-collections

下面是用pandas對時區進行計數

DataFrame是Pandas最重要的數據結構,應該就是R語言中的數據框。下面看一下實現方式:

# -*- encoding: utf-8 -*-
import json
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt

#注意這裏的中文路徑
path = u'D:\\你好\\usagov_bitly_data2012-03-16-1331923249.txt'
#注意這裏的json模塊中的loads函數將字符串轉換爲字典,很是有用!
#注意這裏的縮略循環形式
records = [json.loads(line) for line in open(path)]
#注意這裏的DataFrame能夠將每一個元素都是字典的列表自動整理爲數據框的形式,每一列是字典的key
frame = DataFrame(records)
#數據太多隻是會顯示縮略圖
#print frame
#下面是列名爲tz的前十個元素
#print frame['tz'][:10]
#下面是用value_counts方法對不一樣的tz計數,太方便了!
#print type(frame['tz'])
tz_counts = frame['tz'].value_counts()
#print tz_counts[:10]
#下面想畫一個莖葉圖,首先將缺失值NA進行填充
clean_tz = frame['tz'].fillna('Missing')
#下面是對空白符經過布爾型數組索引加以替換
#值得注意的是,空白符和NA缺失值是不同的,跟R中道理同樣
clean_tz[clean_tz  == ''] = 'Unknown'
tz_counts = clean_tz.value_counts()
print tz_counts[:10]
#書上說下面這條語句在pylab中打開才管用,其實加一句plt.show()就能夠了
tz_counts[:10].plot(kind = 'barh',rot = 0)
plt.show()

下面是對數據中的字符串和表達式之類的進行的工做(前些日子經人指點Beautiful Soup是個爬蟲包):

# -*- encoding: utf-8 -*-
import json
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt
from collections import defaultdict
from collections import Counter

#注意這裏的中文路徑
path = u'D:\\你好\\usagov_bitly_data2012-03-16-1331923249.txt'
#print open(path).readline()
#注意這裏的json模塊中的loads函數將字符串轉換爲字典,很是有用!
#注意這裏的縮略循環形式
records = [json.loads(line) for line in open(path)]
frame = DataFrame(records)
#對於一個 Series,dropna 返回一個僅含非空數據和索引值的 Series
results = Series([x.split()[0] for x in frame.a.dropna()])
#print results.value_counts()
cframe = frame[frame.a.notnull()]
#np.where函數是一個矢量化ifelse函數
operating_system = np.where(cframe['a'].str.contains('Windows'),'Windows','Not Windows')
#print operating_system[:5]
#下面是將tz按照operating_system進行分組並計數並用unstack進行展開並填充na爲0
by_tz_os = cframe.groupby(['tz',operating_system])
agg_counts = by_tz_os.size().unstack().fillna(0)
#print agg_counts
#下面注意 sum函數 默認axis = 0,是普通加和,axis = 1是按行加和,argsort是從小到大排序並返回下表
indexer = agg_counts.sum(1).argsort()
#下面是取出時區最多的值,注意take函數,接下標
count_subset = agg_counts.take(indexer)[-10:]
print count_subset
#下面的圖很好,是累積條形圖
count_subset.plot(kind = 'barh',stacked = True)
plt.show()
#下面進行比例展現
normed_subset = count_subset.div(count_subset.sum(1),axis = 0)
normed_subset.plot(kind = 'barh',stacked = True)
plt.show()

上面一個例子已經完成,看下一個例子。

GroupLens Research 採集了一組從20世紀90年代末到21世紀初由MovieLens用戶提供的電影評分數據。這裏的目的在於對數據進行切片分析。

#-*-coding:utf-8-*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

path1 = 'E:\\Pyprojects\\usepython_2.2\\movielens\\users.dat'
path2 = 'E:\\Pyprojects\\usepython_2.2\\movielens\\ratings.dat'
path3 = 'E:\\Pyprojects\\usepython_2.2\\movielens\\movies.dat'

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

rnames = ['user_id','movie_id','rating','timestamp']
ratings = pd.read_table(path2,sep = '::',header = None,names = rnames)

mnames = ['movie_id','title','genres']
movies = pd.read_table(path3,sep = '::',header = None,names = mnames)

#print users.head()

#下面是對三個數據集合進行merge操做,最終的行數由ratings決定,緣由顯然
data  = pd.merge(pd.merge(ratings,users),movies)
#print data.ix[0]
#下面按照性別計算每部電影的平均得分,說實話,這個透視表函數還真是通俗易懂
mean_ratings = data.pivot_table('rating',rows = 'title',cols = 'gender',aggfunc = 'mean')
#print mean_ratings.head()
#下面是按照title對data分組並計數
ratings_by_title = data.groupby('title').size()
#下面的index返回的下標
active_titles = ratings_by_title.index[ratings_by_title >= 251]
#下面之因此能夠這樣作是由於groupby函數和透視表都是按照相同是順序排序的
mean_ratings = mean_ratings.ix[active_titles]
#print mean_ratings
top_female_ratings = mean_ratings.sort_index(by = 'F',ascending = False)
#print top_female_ratings.head()
#下面一部分計算男性和女性分歧最大的電影
#注意,下面的語句直接加入了一列diff,這樣獲得的就是女性最喜歡的電影,注意方法sort_index的應用
mean_ratings['diff'] = mean_ratings['M'] - mean_ratings['F']
sorted_by_diff = mean_ratings.sort_index(by = 'diff')
#下面是對數據框的行反序並取出前15行,可是 如何對行反序呢?(哦,就是按照原來的行的反向就行)
#print sorted_by_diff[::-1][:15]
#下面考慮分歧最大的電影,不考慮性別因素
rating_std_by_title = data.groupby('title')['rating'].std()
rating_std_by_title = rating_std_by_title.ix[active_titles]
#對Series對象進行排序,須要用order
print rating_std_by_title.order(ascending=False)[:10]

上面的例子中,有很多須要注意的地方,信息量比較大(對於新手)。下面的例子內容更多一些:

# -*- encoding: utf-8 -*-
import json
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt
from collections import defaultdict
from collections import Counter

path_base = u'E:\\BaiduYun\\計算機\\python\\利用python進行數據分析\\pydata-book-master\ch02\\names\\'

#下面讀入多個文件到同一個DataFrame中
years = range(1880,2011)
pices = []
columns = ['name','sex','births']
for year in years:
    path = path_base + 'yob%d.txt' % year
    frame = pd.read_csv(path,names=columns)

    frame['year'] = year
    pices.append(frame)
    break
#注意pd.concat是默認按行進行的合併,是一種outer外鏈接,按照索引做爲鏈接鍵
names = pd.concat(pices,ignore_index=True)
#下面進行一下聚合,注意這裏的pivot_table真是太有用了!
total_births = names.pivot_table('births',rows = 'year',cols = 'sex',aggfunc=sum)
#print total_births.tail()
#total_births.plot(title = 'Total births by sex and year')
#3plt.show()
#下面要插入一列,出生量佔總出生量的比例
def add_prop(group):
    #下面將數據換爲float類型
    births =group.births.astype(float)

    group['prop'] = births / births.sum()
    return group
names = names.groupby(['year','sex']).apply(add_prop)
#下面對prop列進行加和看是否是等於1,因爲是浮點型數據,用的是allclose函數,判斷是否和1足夠接近
#print np.allclose(names.groupby(['year','sex']).prop.sum(),1)
#如今要取一個子集,是每個‘year’‘sex’對的出生量前1000名

def get_top1000(group):
    return group.sort_index(by = 'births',ascending=False)[:1000]
grouped = names.groupby(['year','sex'])
top1000 = grouped.apply(get_top1000)
#print top1000.head()

下面是把後半部分補充完整:

# -*- encoding: utf-8 -*-
import os
import json
import numpy as np
import pandas as pd
from pandas import DataFrame,Series
import matplotlib.pyplot as plt

path_base = u'D:\\pydata-book-master\\ch02\\names\\'

#下面讀入多個文件到同一個DataFrame中
years = range(1880,2011)
pices = []
columns = ['name','sex','births']
for year in years:
    path = path_base + 'yob%d.txt' % year
    frame = pd.read_csv(path,names=columns)
    frame['year'] = year
    pices.append(frame)

#注意pd.concat是默認按行進行的合併,是一種outer外鏈接,按照索引做爲鏈接鍵
names = pd.concat(pices,ignore_index=True)
#下面進行一下聚合,注意這裏的pivot_table真是太有用了!

total_births = names.pivot_table('births',rows = 'year',cols = 'sex',aggfunc=sum)
#print total_births.tail()
#total_births.plot(title = 'Total births by sex and year')
#3plt.show()
#下面要插入一列,出生量佔總出生量的比例
def add_prop(group):
    #下面將數據換爲float類型
    births =group.births.astype(float)
    group['prop'] = births / births.sum()
    return group
names = names.groupby(['year','sex']).apply(add_prop)
#下面對prop列進行加和看是否是等於1,因爲是浮點型數據,用的是allclose函數,判斷是否和1足夠接近
#print np.allclose(names.groupby(['year','sex']).prop.sum(),1)
#如今要取一個子集,是每個‘year’‘sex’對的出生量前1000名

def get_top1000(group):
    return group.sort_index(by = 'births',ascending=False)[:1000]
grouped = names.groupby(['year','sex'])
top1000 = grouped.apply(get_top1000)

#print top1000.head()
#下面是分析命名趨勢
boys = top1000[top1000.sex == 'M']
girls = top1000[top1000.sex == 'F']
#下面作一個透視表
total_births = top1000.pivot_table('births',rows = 'year',cols = 'name',aggfunc = sum)

subset = total_births[['John','Harry','Mary','Marilyn']]
#下面的subplots是用來標明是否將幾個圖畫在一塊兒,figsize用來標明大小,grid 是標明是否有網格線
#subset.plot(subplots = True,figsize = (12,10),grid = True,title = 'Number of births per year')
#plt.show()

#下面評估明明多樣性的增加,計算最流行的1000個名字所佔的比例
#table = top1000.pivot_table('prop',rows = 'year',cols = 'sex',aggfunc = sum)
#table.plot(title = 'Sum of table1000.prop by year and sex',yticks = np.linspace(0,1.2,13),xticks = range(1880,2020,10))
#plt.show()
#另外一個方式是計算總出生人數前50%的不一樣名字的數量
#df = boys[boys.year == 2010]
#下面就要找到prop的和是0.5的位置,書上說寫循環也行,可是numpy中也有cunsum函數,R語言中也有,這固然是極好的。

#prop_cumsum = df.sort_index(by = 'prop',ascending = False).prop.cumsum()
#print prop_cumsum[:10]
#下面這個函數簡直太方便,searchsorted
#print prop_cumsum.searchsorted(0.5)
#注意下面的函數,將全部的年份都進行一次計算
def get_quantile_count(group,q = 0.5):
    group = group.sort_index(by = 'prop',ascending= False)
    return group.prop.cumsum().searchsorted(q) + 1

diversity = top1000.groupby(['year','sex']).apply(get_quantile_count)
diversity = diversity.unstack('sex')
#print diversity.head()
diversity.plot(title = 'Number of popular names in top 50%')
plt.show()


#最後一個字母的變革
#從name列取出最後一個字母,注意lamda這個語句使用來建立匿名函數
get_last_letter = lambda x:x[-1]
#注意這裏的map函數是一種 「並行」式的函數,對name的每一個元素進行後面的函數
last_letters = names.name.map(get_last_letter)
last_letters.name = 'last_letter'
#下面的語句讓我感到了奇怪,爲什麼last_latters不在names中卻還能順利生成數據透視表?毀三觀吶
table = names.pivot_table('births',rows = last_letters,cols = ['sex','year'],aggfunc = sum)

subtable = table.reindex(columns = [1910,1960,2010],level = 'year')
#print subtable.head()
letter_prop = subtable / subtable.sum().astype(float)
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)
plt.show()

letter_prop = table / table.sum().astype(float)
dny_ts = letter_prop.ix[['d','n','y'],'M'].T
dny_ts.plot()
plt.show()

#下面是最後一項,變成女孩名字的男孩名字(以及相反的狀況)
all_names = top1000.name.unique()
#這裏的in函數應該是一個部分匹配函數,另外上面的語句中的unique很熟悉,R語言中也有
mask = np.array(['lesl' in x.lower() for x in all_names])
lesley_like = all_names[mask]
#而後用這個結果過濾掉其餘的名字,並按名字分組計算出生數以查看相對頻率
#下面這個isin函數很是方便
flitered = top1000[top1000.name.isin(lesley_like)]
flitered.groupby('name').births.sum()
table = flitered.pivot_table('births',rows = 'year',cols = 'sex',aggfunc = 'sum')
#print table.head()
#注意這裏的div函數是作一個歸一化
table = table.div(table.sum(1),axis = 0)
print table.head()
#print table.tail()
table.plot(style = {'M':'k-','F':'k--'})
plt.show()

這二章完事,下一章是IPython,第三章少寫一點,本章是受益不淺。

相關文章
相關標籤/搜索