在各種演算法中,向量計算是最經常使用的一種操作之中的乙個。傳統的向量計算,學過中學數學的同學也能明確怎麼做。但在如今的大資料環境下。資料一般都會比較稀疏,因此稀疏向量的計算,跟普通向量計算。還是存在一些不同。
首先,我們定義兩個向量: a=
[x1,
x2,⋯
,xn]
b=[y1,y
2,⋯,
yn]
定義a、b的點積為a∗
b,要求a∗
b=?最直接的方式,當然就是按中學時候就學過的方法: a∗
b=x1
∗y1+
x2∗y
2+⋯+
xn∗y
n 先不考慮乘法與加法的差別,也不考慮計算精度問題。假設按上述方式進行計算。總共進行了n次乘法,n-1次加法,總複雜度為2n-1。矩陣乘法的基本計算單元是向量之間的乘法,複雜度為n3
。在如今的大資料環境之下,n可能會非常大,比方在計算廣告,或者文字分類中,上百萬維都是非常正常的。並且這樣的向量都有乙個特點,那就是非常稀疏。
假設沒有非常稀疏這個特點,那後面自然就無從談起了。。。
對於稀疏向量。自然而然的能夠想到按一下方式進行儲存: a:
b: 由於是稀疏向量。所以 i≪
n,j≪
n詳細在計算a*b的時候,能夠在向量a中迴圈,然後在向量b中進行二分查詢。比如,在向量a中取出第乙個非零元素。假設為
,loc
atio
n1>
,在b中對location1進行二分。假設找到,計算乘積。假設找不到。自然為0.
那我們來估算一下演算法的複雜度。在b中二分的複雜度為lo
gj,a的長度為
i,則這部分的總複雜度為il
ogj,加法的最大情況為mi
n(i,
j)−1
,總的複雜度為il
ogj+
min(
i,j)
−1當然,假設我們知道
i ,
j 的大小。能夠在小的向量上迴圈,在大的向量上二分,這樣複雜度能夠減少為 mi
n(i,
j)lo
g(ma
x(i,
j))+
min(
i,j)
−1假設咱們不用二分查詢,而是使用hash,則二分查詢部分能夠變為hash。假設hash的複雜度為1,那麼總的複雜度為2m
in(i
,j)。當然。我們忽略了建立hash的複雜度。以及hash碰撞的複雜度。
這樣,總的複雜度就由最初的2n
−1降到了2mi
n(i,
j)。假設n特別特別大,比方鳳巢系統動不動就是號稱上億維度。這樣i,j也不會特別小。假設是兩個矩陣相乘。咱們前面提到的。複雜度為n3
,這樣就必須上平行計算了。
搞資料的同學,對並行肯定不陌生,這裡不再細述了。
以上都是理論分析,為了驗證實際中的執行效果。特意編寫了一部分測試**。測試**例如以下
#!/usr/bin/env python
#coding:utf-8
'''created on 2023年4月22日
@author: lei.wang
'''import time
#二分查詢
defbin_search
(num,list):
low = 0
high = len(list) - 1
while(low <= high):
middle = (low + high) / 2
if list[middle] > num:
high = middle - 1
elif list[middle] < num:
low = middle + 1
else:
return middle
return -1
deft1
(): all = 1000000
sparse_rate = 1000
vec_a = [0
for i in range(all)]
vec_b = [0
for i in range(all)]
list_none_zero = [sparse_rate*i for i in range(all / sparse_rate)]
for i in list_none_zero:
vec_a[i] = vec_b[i] = 1
sum = 0
#a,b分別不為0的位置
location_a = [i for i in range(0,all,sparse_rate)]
location_b = [i for i in range(0,all,sparse_rate)]
start = time.clock()
for i in location_a:
location = bin_search(i, location_b) #相應a不為0的位置。在b不為0的位置陣列中查詢是否存在
if location != -1:
sum += vec_a[i] * vec_b[location_b[location]] #假設存在,將結果相加
end = time.clock()
print
"cost time is:",(end-start)
print
"sum is:",sum
deft2
(): all = 1000000
sparse_rate = 1000
vec_a = [0
for i in range(all)]
vec_b = [0
for i in range(all)]
list_of_none_zero = [sparse_rate*i for i in range(all / sparse_rate)]
for i in list_of_none_zero:
vec_a[i] = vec_b[i] = 1
sum = 0
start = time.clock()
for i in range(all):
sum += vec_a[i] * vec_b[i]
end = time.clock()
print
"cost time is:",(end-start)
print
"sum is:",sum
if __name__ == '__main__':
t1()
print
print
t2()
bin_search是自己實現的二分查詢,t1方法是用上面說到的二分查詢的方式,t2方法就是最簡單的直接遍歷相乘的方式。
在mac上執行以上**。結果例如以下:
cost time
is: 0.002319
sum is: 1000
cost time
is: 0.123861
sum is: 1000
能夠看出,遍歷的方式是二分查詢的方式的54倍!按上述咱們的分析方式,遍歷的方式應該是2∗
106的複雜度。二分查詢的方式應該是103
∗log
1000
,即10
4 左右的複雜度。二分查詢的方式比遍歷的方式應該要快100倍左右。
依據咱們實驗的結果來看,數量級上來說基本是差點兒相同的。假設採取一些優化方式。比方用python自帶的binset模組,應該會有更快的速度。
假設改變上述**中的稀疏度,即改變sparse_rate的數值,比如將sparse_rate由1000改為10000,執行的結果例如以下:
cost time
is: 0.000227
sum is: 100
cost time
is: 0.118492
sum is: 100
假設將sparse_rate改為100。執行的結果為:
cost time
is: 0.034885
sum is: 10000
cost time
is: 0.124176
sum is: 10000
非常easy看出來,對於遍歷的方式來說。無論稀疏度為多少,耗時都是基本不變的。可是對於我們採用二分查詢的方式來說,稀疏度越高,節省的計算資源,就越可觀。 幾何向量 計算光線折射refract向量
其實光線除了反射現象外,還有折射現象,打個比方,你看水塘中魚兒游動,表面上看起來魚兒很貼近水面,同時也感覺水底很淺,結果一腳捅下去,直接沒到大腿了,這就是光的折射產生的一種視覺欺騙。光線折射的產生,其實是因為光線通過不同介質所產生的 偏折 現象。ps 光線的 偏折 現象實際上和光的粒子性有關,這裡我...
複數計算和向量計算的區別
今天接觸到了量子計算,原理正在摸索,但是從數學角度,複數計算應該會用到。以前學習複數的時候,純屬應付考試,現在回想只記得乙個公式 今天週末,有時間縷一下,看幾個問題 1 複數裡用到了虛數,看了阮老師的一篇文章,虛數的意義何在 清晰了好多,上學的時候怎麼沒想過這些問題呢?2 看起來複數計算好像跟向量計...
Numpy中向量與標量計算
加減乘除冪運算 import numpy as np a np.array 1,2,3 b np.array 3,2,1 print a 10 對應位置依次相加 print a 2 print 1,2,3 2 print a b print a b print a b print a b print...