㈠ 如何高效地使用python統計數據的頻率
之前用 Python 寫過一個腳本,用來處理上千萬用戶的一些數據,其中有一個需求是統計用戶的某一數據的去重數量。為了加快程序的速度,我啟用了多進程。但不幸的是,程序跑了近一個星期,還沒處理完。這時,我感覺到了不對,於是開始查看程序的性能瓶頸。
對於統計去重數,我是將用戶的數據放到一個列表中,然後用 len(set(data)) 去統計去重數量。剛開始我以為這的數據量並不大,每個用戶的數據不會過百,我並沒有注意到有的用戶會有上萬條的數據,因此消耗了大量的時間(其實我的腳本消耗時間最大的地方是因為從遠程 redis 中取大量數據時發生長時間的阻塞,甚至連接超時,最後我採用的方式分而治之,每次取少量的數據,這樣大大的提高了性能)。
為了做優化,我開始尋求高效的方法。我發現,有大量的人認為採用字典效率會更高,即:
data_unique = {}.fromkeys(data).keys() len(data_unique)
於是,我做了下測試:
In [1]: import random In [2]: data = [random.randint(0, 1000) for _ in xrange(1000000)] In [3]: %timeit len(set(data)) 10 loops, best of 3: 39.7 ms per loop In [4]: %timeit len({}.fromkeys(data).keys()) 10 loops, best of 3: 43.5 ms per loop
由此可見,採用字典和採用集合的性能是差不多的,甚至可能還要慢些。
在 Python 中其實有很多高效的庫,例如用 numpy、pandas 來處理數據,其性能接近於 C 語言。那麼,我們就用 numpy 和 pandas 來解決這個問題,這里我還比較了獲取去重數據的性能,代碼如下:
import collections import random as py_random import timeit import numpy.random as np_random import pandas as pd DATA_SIZE = 10000000 def py_cal_len(): data = [py_random.randint(0, 1000) for _ in xrange(DATA_SIZE)] len(set(data)) def pd_cal_len(): data = np_random.randint(1000, size=DATA_SIZE) data = pd.Series(data) data_unique = data.value_counts() data_unique.size def py_count(): data = [py_random.randint(0, 1000) for _ in xrange(DATA_SIZE)] collections.Counter(data) def pd_count(): data = np_random.randint(1000, size=DATA_SIZE) data = pd.Series(data) data.value_counts() # Script starts from here if __name__ == "__main__": t1 = timeit.Timer("py_cal_len()", setup="from __main__ import py_cal_len") t2 = timeit.Timer("pd_cal_len()", setup="from __main__ import pd_cal_len") t3 = timeit.Timer("py_count()", setup="from __main__ import py_count") t4 = timeit.Timer("pd_count()", setup="from __main__ import pd_count") print t1.timeit(number=1) print t2.timeit(number=1) print t3.timeit(number=1) print t4.timeit(number=1)
運行結果:
12.438587904 0.435907125473 14.6431810856 0.258564949036
利用 pandas 統計數據的去重數和去重數據,其性能是 Python 原生函數的 10 倍以上。
㈡ 一個txt文檔,已經用結巴分詞分完詞,怎麼用python工具對這個分完詞的文檔進行計算統計詞頻,求腳本,非
#!/usr/bin/envpython3
#-*-coding:utf-8-*-
importos,random
#假設要讀取文件名為aa,位於當前路徑
filename='aa.txt'
dirname=os.getcwd()
f_n=os.path.join(dirname,filename)
#注釋掉的程序段,用於測試腳本,它生成20行數據,每行有1-20隨機個數字,每個數字隨機1-20
'''
test=''
foriinrange(20):
forjinrange(random.randint(1,20)):
test+=str(random.randint(1,20))+''
test+=' '
withopen(f_n,'w')aswf:
wf.write(test)
'''
withopen(f_n)asf:
s=f.readlines()
#將每一行數據去掉首尾的空格和換行符,然後用空格分割,再組成一維列表
words=[]
forlineins:
words.extend(line.strip().split(''))
#格式化要輸出的每行數據,首尾各佔8位,中間佔18位
defgeshi(a,b,c):
returnalignment(str(a))+alignment(str(b),18)+alignment(str(c))+' '
#中英文混合對齊,參考http://bbs.fishc.com/thread-67465-1-1.html,二樓
#漢字與字母格式化佔位format對齊出錯對不齊漢字對齊數字漢字對齊字母中文對齊英文
#alignment函數用於英漢混合對齊、漢字英文對齊、漢英對齊、中英對齊
defalignment(str1,space=8,align='left'):
length=len(str1.encode('gb2312'))
space=space-lengthifspace>=lengthelse0
ifalignin['left','l','L','Left','LEFT']:
str1=str1+''*space
elifalignin['right','r','R','Right','RIGHT']:
str1=''*space+str1
elifalignin['center','c','C','Center','CENTER','centre']:
str1=''*(space//2)+str1+''*(space-space//2)
returnstr1
w_s=geshi('序號','詞','頻率')
#由(詞,頻率)元組構成列表,先按頻率降序排序,再按詞升序排序,多級排序,一組升,一組降,高級sorted
wordcount=sorted([(w,words.count(w))forwinset(words)],key=lambdal:(-l[1],l[0]))
#要輸出的數據,每一行由:序號(佔8位)詞(佔20位)頻率(佔8位)+' '構成,序號=List.index(element)+1
for(w,c)inwordcount:
w_s+=geshi(wordcount.index((w,c))+1,w,c)
#將統計結果寫入文件ar.txt中
writefile='ar.txt'
w_n=os.path.join(dirname,writefile)
withopen(w_n,'w')aswf:
wf.write(w_s)