iT邦幫忙

0

#問 python 有何好方法處理大筆資料

小弟有3000個詞,以及22萬句樣本(一句話)
我現在的目標是希望做出 22萬*3000 的1 0矩陣 假如 我的詞庫裡有2個詞['cool','it']
而我有一句樣本是'我愛it邦' 那我希望 這句樣本被處理為[0,1]
詞庫第一個詞沒有=0第二個有=1

簡而言之就是一個元素比對了樣本數的向量 希望出來跟樣本數一樣的向量 並且若是元素在向量裡=1 否則=0

套上我的例子就是迴圈跑3000個元素 一次比對樣本數的向量 每跑一次迴圈 就能得到一個向量最終組合成矩陣

froce iT邦大師 6 級 ‧ 2019-08-08 06:40:07 檢舉
map()...
不過以這種量級大概都得很久。
ccutmis iT邦研究生 3 級 ‧ 2019-08-08 09:44:20 檢舉
用 numpy 很簡單能辦到 測試效率就看樓主能不能接受了
3
ccutmis
iT邦研究生 3 級 ‧ 2019-08-08 11:45:26
最佳解答

剛剛測試弄了約一個77萬筆句子的[樣本]csv,把它命名為'big_data.csv',內容節錄如下:

it邦幫忙
人之所以痛苦 在於追求錯誤的東西
如果你不給自己煩惱 別人也永遠不可能給你煩惱
今日的執著
會造成明日的後悔
當你對自己誠實的時候
世界上沒有人能夠欺騙得了你
面對現實才能超越現實
不懂得自愛的人 是沒有能力去愛別人的
太陽底下沒有新鮮事

(註:77萬筆句子就是上面的這十行重覆7萬7千次)
然後是[詞庫]csv,把它命名為'small_data.csv',內容如下:

it
痛cool
追求錯誤
天天上班
很酷
新鮮事

最後是測試的python碼,我把它命名為'numpy_load_data_test.py',內容如下:

import numpy as np
import datetime
print('準備載入CSV: 	'+str(datetime.datetime.now())[:-7])
big_data = np.loadtxt('big_data.csv', delimiter=',', unpack=True, dtype=str,encoding="utf-8")
print('載入big_data.csv OK: '+str(datetime.datetime.now())[:-7])
small_data = np.loadtxt('small_data.csv', delimiter=',', unpack=True, dtype=str,encoding="utf-8")
print('載入small_data.csv OK: '+str(datetime.datetime.now())[:-7])
print('big_data筆數: '+str(len(big_data)))
print('比對開始: '+str(datetime.datetime.now())[:-7])
for A in small_data:
	B=np.char.find(big_data, A)
	B[B>-1]=1
	B[B<0]=0
	print(A,B)
print('比對結束: '+str(datetime.datetime.now())[:-7])

執行結果:

準備載入CSV: 	2019-08-08 11:41:37
載入big_data.csv OK: 2019-08-08 11:41:43
載入small_data.csv OK: 2019-08-08 11:41:43
big_data筆數: 770902
比對開始: 2019-08-08 11:41:43
it [1 0 0 ... 0 0 0]
痛cool [0 0 0 ... 0 0 0]
追求錯誤 [0 1 0 ... 0 0 0]
天天上班 [0 0 0 ... 0 0 0]
很酷 [0 0 0 ... 0 0 0]
新鮮事 [0 0 0 ... 0 0 1]
比對結束: 2019-08-08 11:41:49

樓主有空可以試試看~
(載入big_data.csv花了約6秒)
跑詞庫迴圈比對big_data時每一圈花費1秒 6筆共花6秒,
如果是以樓主所說 詞庫有3000筆 那有可能總時會花費(3000/60)=50分鐘(粗估)

看更多先前的回應...收起先前的回應...
e6319a5b iT邦新手 5 級 ‧ 2019-08-08 15:24:53 檢舉

感謝你的回答,很實用

e6319a5b iT邦新手 5 級 ‧ 2019-08-08 15:26:11 檢舉

啊手機版不能用最佳解答,晚點給您

ccutmis iT邦研究生 3 級 ‧ 2019-08-08 15:34:19 檢舉

不客氣~~/images/emoticon/emoticon82.gif

froce iT邦大師 6 級 ‧ 2019-08-08 18:34:27 檢舉

回家來跑跑看純用list會多慢好了。XD

ccutmis iT邦研究生 3 級 ‧ 2019-08-08 18:54:25 檢舉

/images/emoticon/emoticon04.gif

froce iT邦大師 6 級 ‧ 2019-08-08 20:17:39 檢舉

跑了一下,發現ccutmis你應該弄反了。
他要的是:

人之所以痛苦 在於追求錯誤的東西 [0 0 1 0 0 0]
.
.
.

不過轉置一下就好了。

ccutmis iT邦研究生 3 級 ‧ 2019-08-08 20:37:03 檢舉

/images/emoticon/emoticon39.gif

e6319a5b iT邦新手 5 級 ‧ 2019-08-08 20:38:22 檢舉
def deal(readFileName,readFileName2):
    read4replys = pd.read_excel(readFileName)
    read4features=pd.read_excel(readFileName2)
    replys=read4replys.iloc[ : , 0 ]
    features=read4features.iloc[:,0]
    replys=list(replys)
    
    for A in features:
        B=np.char.find(replys,A)
        B[B>-1]=1
        B[B<0]=0

很抱歉,我試了5000*3000的矩陣
結果我用暴力法比這個快3倍,請問我是哪裡做錯或者是有更好的建議嗎

ccutmis iT邦研究生 3 級 ‧ 2019-08-08 21:02:15 檢舉

不知道耶 你用暴力法比這個方法快3倍 那...
那就用暴力法好了~我的建議當作參考就好
/images/emoticon/emoticon82.gif
太陽底下沒有新鮮事 但總有更好的路~

e6319a5b iT邦新手 5 級 ‧ 2019-08-08 21:48:17 檢舉

好吧,再次感謝

1
japhenchen
iT邦新手 3 級 ‧ 2019-08-08 08:25:42

先分詞再以字元拼音做索引做成dict,搜尋速度會非常快
分詞你可以找 jieba 詞庫,目前收錄的中文詞庫語料真的很全,你可以參考看看
至於轉拼音或注音(做dict key用的),我個人是把分詞後的結果轉成拼音後存放,拼音字母只有26個字(沒扣掉絕對用不到的子音母音)
GitHub pypinyin

e6319a5b iT邦新手 5 級 ‧ 2019-08-08 15:25:31 檢舉

謝謝你分享的概念

全文檢索怕的不是關鍵字,而是錯別字漏字

比如清單裡有一組
『鄭中基 絕口不提!愛你』

如果使用者輸入搜尋"絕口不提愛你"
用比對法肯定找不到

所以我才建議用斷詞處理
『鄭中基 絕口不提!愛你』
用常用詞庫會裁成→"鄭中基 絕口不提 愛你"
(看你的語料詞庫的詳細程度決定)
我會把所有清單的內容,斷詞後做成

{"鄭中基": ["鄭中基 絕口不提!愛你","鄭中基 你的眼睛背叛了你的心","鄭中基 陳慧琳 北極雪"]}
{"絕口不提": ["鄭中基 絕口不提!愛你","【HD】柳岩-絕口不提","绝口不提 - 王曉晨"]}
{"愛你":["鄭中基 絕口不提!愛你","陳芳語-愛你","蔡依琳-愛你唷"])}

而你在接受使用者輸關鍵字詞,也做斷詞處理,只要對你分開的詞組DICT做搜尋,速度是 f(1),而你的方法得從頭到尾跑過一次,速度將會是f(n)

至於分詞結果轉成拼音或注音,就是怕用戶輸入錯別字
決口不堤?找不到

所以我是加了一層轉拼音的處置,這塊有點離題且是個人專利,留一手

我用在哪裡?自製的【語音智能音箱】裡,配上一支64GB USB隨身碟,機能不夠強,空間不夠大,塞NOSQL?我還是自己想辦法用上述的方法解決的

e6319a5b iT邦新手 5 級 ‧ 2019-08-09 14:10:15 檢舉

wow謝前輩指教,希望我有天能用上您的技巧

2
froce
iT邦大師 6 級 ‧ 2019-08-08 20:46:40

ㄜ...怎麼反而list比較快...Orz
list版本:

import datetime

start = datetime.datetime.now()

test_lst = [
    "it邦幫忙",
    "人之所以痛苦 在於追求錯誤的東西",
    "如果你不給自己煩惱 別人也永遠不可能給你煩惱",
    "今日的執著",
    "會造成明日的後悔",
    "當你對自己誠實的時候",
    "世界上沒有人能夠欺騙得了你",
    "面對現實才能超越現實",
    "不懂得自愛的人 是沒有能力去愛別人的",
    "太陽底下沒有新鮮事",
] * 77000

pat_lst = [
    "it",
    "痛cool",
    "追求錯誤",
    "天天上班",
    "很酷",
    "新鮮事"
]

def gen_exam_lst(pat, test_str):
    return list(map(lambda x: 1 if x in test_str else 0, pat))

[print(t, gen_exam_lst(pat_lst, t)) for t in test_lst]

end = datetime.datetime.now()
print(end-start)

numpy版本:

import numpy as np
import datetime

start = datetime.datetime.now()

test_lst = [
    "it邦幫忙",
    "人之所以痛苦 在於追求錯誤的東西",
    "如果你不給自己煩惱 別人也永遠不可能給你煩惱",
    "今日的執著",
    "會造成明日的後悔",
    "當你對自己誠實的時候",
    "世界上沒有人能夠欺騙得了你",
    "面對現實才能超越現實",
    "不懂得自愛的人 是沒有能力去愛別人的",
    "太陽底下沒有新鮮事",
] * 77000

exam_lst = [
    "it",
    "痛cool",
    "追求錯誤",
    "天天上班",
    "很酷",
    "新鮮事"
]

big_data = np.asarray(test_lst)
small_data = np.asarray(exam_lst)

for A in big_data:
	B=np.char.find(A, small_data)
	B[B>-1]=1
	B[B<0]=0
	print(A,B)

end = datetime.datetime.now()
print(end-start)

在我機器上:
list版本:0:01:43.717999
numpy版本:0:02:42.642017

看更多先前的回應...收起先前的回應...
e6319a5b iT邦新手 5 級 ‧ 2019-08-08 20:51:46 檢舉

我寫的暴力法比您的簡單許多 速度也必較快 是因為 我的樣本數只有5000嗎?(我的比較方式是倍數) 還是因為有些函式的專長不是處理這個xdd

ccutmis iT邦研究生 3 級 ‧ 2019-08-08 21:46:01 檢舉

這個現象我也不知怎麼解釋內 之前沒實測比較過 /images/emoticon/emoticon82.gif
但可以確定一點是 在不同電腦上算同樣的東西 時間也會不同
我的電腦跑你寫的numpy版本只需要一分多鐘

froce iT邦大師 6 級 ‧ 2019-08-08 22:01:06 檢舉

...樣本數5000和770000當然不能比啊。
你要比就要同樣資料不同方法去測試。

e6319a5b iT邦新手 5 級 ‧ 2019-08-08 23:43:59 檢舉

回大大,對呀 我測試的條件是 同資料 拿2種寫法 暴力法 numpy法
比較 我快了numpy法 3倍 但是您的資料顯示list版本 快不到2倍

froce iT邦大師 6 級 ‧ 2019-08-09 08:15:06 檢舉

這很正常,numpy底層是C/C++,量級大的話一定比python內部資料類型快。
所以我才訝異試驗結果是list快,看來是樣本不夠多。

e6319a5b iT邦新手 5 級 ‧ 2019-08-09 14:08:29 檢舉

好的,感謝指教

我要發表回答

立即登入回答