前言
前段時間地統計的課設代碼的確有點折磨人,但是還好算法過程比較簡單,沒有涉及到特別複雜的步驟,matlab在矩陣運算方面有大量的庫函數以及其在索引方面的優勢,使得我們真正能夠實現向量化(矩陣化編程),希望大家看到這篇文章過後能夠真正取思考,以前的哪些代碼可以將for循環等若干繁瑣步驟去掉,減少代碼行數,掌握向量化編程的精髓。
1 變異函數
這裏引用一下楊老師ppt上的一個簡單定義,一維條件下,當空間點在一維軸上變化時,區域化變量在點和處的值與差的方差一半定義爲區域化變量Z(x)在x軸方向上的變異函數。
通常區域化變量所描述的現象是二維和三維的,則變異函數可定義爲在任一方向,相距的兩個區域化變量值與的增量的方差。
其中稱爲半變異函數,但有時爲方便也稱變異函數
變異函數計算公式
其中爲距離(滯後距)
爲樣點中符合該距離的點對數量
和爲各點對位置
2隨機樣點的試驗半方差
在很多情況下,樣點並不是規則採集(機械採樣)的,而是呈現不規則分佈,這時,如何計算試驗半方差?
一般地,在實際計算時,假設步長爲,當前滯後級別爲(爲正整數),則,應該這樣處理:
計算步驟
1.研究區所有點,找到點對,其符合條件:,它們之間的距離記爲
2.計算,記爲.
3.設找到個這樣的點對,計算平均距離
4.計算爲滯後級別上的經驗半方差值。
5.將各個級別的,繪製在圖上,形成經驗半方差圖
3代碼實例
3.1數據集
本次數據來源於楊老師分享的沙洋縣土壤樣點數據集,如下圖
數據集前兩列爲座標,後面幾列爲屬性數據
3.2 代碼實例
這裏以全氮數據爲例計算經驗半方差
由於數據爲EXCEL形式,因此可調用xlsread函數讀取文件將數據文件存儲爲矩陣,而將表中的文本類型忽略
數據預處理
data=xlsread('F:\geostatistical_test\test\data_and_materials\data.xls');
N=data(:,5);
[h,p,ks]=lillietest(N);%h==0,通過正態分佈檢驗,p>0.05接受檢驗
figure;
histogram(N,10);
figure;
qqplot(N);
aveN=mean(N);
varN=var(N,1);%除以n的方差
stdN=sqrt(varN);
us=aveN+2*stdN;
ux=aveN-2*stdN;
logi=(N>us)+(N<ux);
logi=logical(logi);
N(logi)=[];
data(logi,:)=[];
[h1,p1,ks1]=lillietest(N);%h==0,通過正態分佈檢驗,p>0.05接受檢驗
figure;
qqplot(N);
原始數據
去除異常值後
%計算出距離矩陣
D=pdist(data(:,1:2));
D1=squareform(D);%計算出距離矩陣
lag=500;
maxdist=max(max(D1));%計算最大距離
D2=triu(D1);%將距離矩陣轉化成上三角,下三角爲0,方便後面符合序號對提取
%下三角部分全部變爲0
max_lagcount=round(maxdist/(2*lag))+1;%計算出最多可以求得的延遲階數
將處理好的數據計算各個點對所對應的距離矩陣,其中D1就是一個的距離矩陣,在對角線上爲0;以500米爲步長,找到最大距離(這裏用max(max(D1)))是因爲max函數是默認對矩陣每一列求最大值,通過計算可以得到最大能計算的步長max_lagcount
開始進行for循環計算組合的點對
循環代碼如下:
result=[];%產生一個空矩陣,存儲結果點對
for n=1:max_lagcount
lower=(n-1)*lag;
upper=n*lag;
logi=logical((D2>lower)+(D2<=upper)-1);%找到符合條件的點對邏輯矩陣
[tag1,tag2]=find(logi);%[tag1,tag2]表示點對序號
N1=N(tag1);
N2=N(tag2);
S=sum((N1-N2).^2);
Nh=length(tag1);
rh=S/(2*Nh);
havg=sum(D1((tag2-1).*size(D2,1)+tag1))/Nh;
%havg=trace(D1(tag1,tag2))/Nh;
temp=[havg,rh];
result=[result;temp];
end
其中lower,upper分別爲距離限制條件,
其中logi=logical((D2>lower)+(D2<=upper)-1);%找到符合條件的點對邏輯矩陣,用的是D2上三角矩陣,若用原始距離矩陣(是對稱矩陣),會將點對所有點對重複記錄一次,因此選取上三角部分就可記錄一次,因爲下三角全爲0
這裏的tag1,tag2均爲一列矩陣,其中就表示着對應的點對序號,因此可以直接通過序號來對N矩陣索引,求得,其中每個值就對應的是,然後後續調用sum函數求和,其中Nh=length(tag1),找到目標點對得數量,只需要調用length求矩陣長度得函數即可,因此求得對應於rh
havg=sum(D1((tag2-1).*size(D2,1)+tag1))/Nh;這裏爲什麼用
D1((tag2-1).*size(D2,1)+tag1)這麼複雜的索引方式對D1距離矩陣進行索引呢,因爲前面的表示的是D1中第行第列的數據,但是如果用D1(tag1,tag2))索引方式的話會將其中每個元素來進行匹配,因此我們要將點對錶示的索引轉化爲一個值即序號索引,因爲matlab裏面默認情況下是先對第一列索引完後再對第二列索引,
因此第一列第行對應於序號爲,
第二列第行對應於
因此第行第列對應於序號
講的比較通俗一點就是
爲矩陣的行數,這裏舉一個簡單的例子說明
如果硬要用D1(tag1,tag2)索引的方式也是可行的,
,其中D1(tag1,tag2),其中tag1,tag2是目標點對序號得矩陣,但是matlab裏面兩個索引均爲矢量時,會將矢量中每個元素都進行匹配來進行索引,進而返回索引得到得值,這裏舉一個簡單例子說明:
a=[1,2,3;4,5,6;7,8,9]
a([1;2],[2;3])
返回結果分別爲
但是我們只想要(1,2),(2,3)(第一行第二列,第二行第三列)處的值,發現其對應的值均會在對角線上,因此對角線上就是序號一一對應處的矩陣索引值,因此這裏將調用矩陣的跡trace函數,即對角線元素之和,將這些點對對應的距離相加,最後得到。
現在問題來了,哪種索引方式更快消耗的內存更小,因此我在代碼快的前後加上了計時函數tic,toc根據最終的運行效果對比,基於
havg=sum(D1((tag2-1).*size(D2,1)+tag1))/Nh
索引方式所消耗計算時間爲
1.1038s
基於trace點對索引的方式消耗計算時間爲
2.9563s
最後將這些點對進行記錄
temp=[havg,rh];result=[result;temp];
最終會返回一個兩列的result矩陣,第一列爲,第二列爲
在這裏並沒有考慮的情況,假設N(h)=0,那麼對應的,,因此,均爲0/0,在matlab裏面計算得到的結果爲NaN
結果爲空
因此我們只需將最終得到的矩陣中將其中爲NaN的一行去掉即可
調用isnan函數,
result(isnan(result))=[];
繪圖表示:
plot(result(:,1),result(:,2),’*r’)
title(‘變異函數散點圖’);
xlabel(‘平均距離’);
ylabel(‘滯後級別半方差值’);
完整代碼如下:
tic;
data=xlsread('F:\geostatistical_test\test\data_and_materials\data.xls');
N=data(:,5);
[h,p,ks]=lillietest(N);%h==0,通過正態分佈檢驗,p>0.05接受檢驗
figure;
histogram(N,10);
figure;
qqplot(N);
aveN=mean(N);
varN=var(N,1);%除以n的方差
stdN=sqrt(varN);
us=aveN+2*stdN;
ux=aveN-2*stdN;
logi=(N>us)+(N<ux);
logi=logical(logi);
N(logi)=[];
data(logi,:)=[];
[h1,p1,ks1]=lillietest(N);%h==0,通過正態分佈檢驗,p>0.05接受檢驗
figure;
qqplot(N);
%計算出距離矩陣
D=pdist(data(:,1:2));
D1=squareform(D);%計算出距離矩陣
lag=500;
maxdist=max(max(D1));%計算最大距離
D2=triu(D1);%將距離矩陣轉化成上三角,下三角爲0,方便後面符合序號對提取
%下三角部分全部變爲0
max_lagcount=round(maxdist/(2*lag))+1;%計算出最多可以求得的延遲階數
result=[];
for n=1:max_lagcount
lower=(n-1)*lag;
upper=n*lag;
logi=logical((D2>lower)+(D2<=upper)-1);%找到符合條件的點對邏輯
[tag1,tag2]=find(logi);%[tag1,tag2]表示點對序號
N1=N(tag1);
N2=N(tag2);
S=sum((N1-N2).^2);
Nh=length(tag1);
rh=S/(2*Nh);
%havg=trace(D1(tag1,tag2))/Nh;
havg=sum(D1((tag2-1).*size(D2,1)+tag1))/Nh;
temp=[havg,rh];
result=[result;temp];
end
result(isnan(result))=[];
figure;
plot(result(:,1),result(:,2),'*r')
title('變異函數散點圖');
xlabel('平均距離');
ylabel('滯後級別半方差值');
t1=toc
4總結
matlab的向量化編程是非常方便的,因爲matlab針對矩陣索引支持邏輯索引以及位置索引,在篩出異常值與對特定條件的值進行索引時是非常有效的,其次調用matlab的內置函數一般計算速度要比自己寫for循環的最終代碼要快得多,如果不相信的話,同學們可以把矩陣化編程的那些語句以及函數改寫成for循環試一試比較最終的計算時間,希望大家在今後矩陣運算的編程過程中儘量少用for循環,儘量理解如下代碼的含義,方便今後套用:
logi=(N>us)+(N<ux);
logi=logical(logi);
N(logi)=[];
data(logi,:)=[];
logi=logical((D2>lower)+(D2<=upper)-1);%找到符合條件的點對邏輯
[tag1,tag2]=find(logi);%[tag1,tag2]表示點對序號
havg=trace(D1(tag1,tag2))/Nh;
havg=sum(D1((tag2-1).*size(D2,1)+tag1))/Nh;
本次代碼全爲潘老師自主編寫,若要引用,注意引用規範
撰寫本次博客也掌握了對markdown編寫數學公式的技巧,也是對自己一個方面的提升,在地統計實驗課程結束後會將遺傳算法以及克里格插值部分的源代碼分享出來造福大家!敬請期待!