編程中的數學之美
數學,始終環繞在我們的身邊。大家一般對數學的用途產生過懷疑,除了初等數學。比如很多大學生畢業後,數學知識可能一輩子都沒有機會應用,久而久之也就忘得差不多了,致使很多人產生了為什麼要學習數學的疑問。事實上數學的用途在我們的生活中無處不在,甚至可以說遠遠超乎人們的想像。現今每個人都要使用搜索,在人工智慧技術異常爆棚的這幾年,以及神奇的語音識別、機器翻譯和自然語言處理等技術,也許大家想不到,應用這些技術最好工具就是數學。
矩陣是線性代數中一個重要的工具,關於矩陣的概念有許多,如轉置,矩陣的秩,特徵值等,這些知識已經脫離了日常生活,但是,矩陣在計算機編程方面的應用很多,如數字圖像處理,數學建模,自然語言處理,數據分析與優化等多種方面。今天我們就矩陣的用途做個主要介紹。
一、文本和辭彙的矩陣
自然語言處理(Natural Language Processing,簡稱NLP)就是用計算機來處理、理解以及運用人類語言(如中文、英文等),它屬於人工智慧的一個分支,是計算機科學與語言學的交叉學科,又常被稱為計算語言學。由於自然語言是人類區別於其他動物的根本標誌。沒有語言,人類的思維也就無從談起,所以自然語言處理體現了人工智慧的最高任務與境界,也就是說,只有當計算機具備了處理自然語言的能力時,機器才算實現了真正的智能。
在自然語言處理中,最常見的兩個問題是,將文本按主題歸類(比如將所有介紹奧運會的新聞歸到體育類 )和將辭彙表中的字詞按意思歸類(比如將各種運動的項目名稱都歸成體育一類)。這兩個分類問題都可以通過矩陣運算來圓滿地、一次性地解決。
在新聞分類中,關鍵是計算兩篇新聞的相似程度。為了完成這個過程,我們要將新聞變成代表它們內容的實詞,然後再變成一組數,具體來說是向量,最後就這兩個向量的夾角。當這兩個向量的夾角很小時,新聞就相關;當兩者垂直或者說正交時,新聞則無關。從理論上講,這種演算法很漂亮。但是因為要對所有新聞做兩兩計算,而且要進行很多次迭代,耗時會特別長,尤其是當新聞的數量很大且詞表也很大的時候。我們希望有一個方法,一次就能把所有新聞相關性計算出來。這個一步到位的辦法利用的是矩陣運算中的奇異值分解(簡稱SVD)。
現在讓我們來看看奇異值分解是怎麼回事。首先,需要用一個大矩陣來描述成千上萬篇文章和幾十上百萬個詞的關聯性。在這個矩陣中,每一行對應一篇文章,每一列對應一個詞,如果有N個詞,M篇文章,則得到一個M×N的矩陣,如下所示:
其中,第i行、第j列的元素,是字典中第j個詞在第i篇文章中出現的加權詞頻。你們也許能猜到,這個矩陣會非常非常大,比如M=1000000,N=500000,100萬乘50萬,即5000億個元素,如果以5號字體列印出來,有兩個西湖那麼大。
奇異值分解,就是把上面這樣一個大矩陣,分解成三個小矩陣相乘,如圖所示。比如把上面例子的矩陣分解成一個100萬乘100的矩陣X,一個100乘100的矩陣B,和一個100乘50萬的矩陣Y。這三個矩陣的元素總數加起來也不過1.5億,不到原來的三千分之一。相應的存儲量和計算量都會小三個數量級以上。
三個矩陣有非常清晰的物理含義。第一個矩陣X是對詞進行分類的一個結果。它的每一行表示一個詞,每一列表示一個語義相近的詞類,或者簡稱為語義類。這一行的每個非零元素表示這個詞在每個語義類中的重要性(或者說相關性),數值越大越相關。舉一個4×2的小矩陣的例子來說明。
這裡面有四個詞,兩個語義類,第一個詞和第一個語義類比較相關(相關性為0.7),和第二個語義類不太相關(相關性為0.15)。第二個詞正好相反。第三個詞只和第二個語義類相關,和第一個完全無關。第四個和每一類都不太相關,因為它對應的兩個元素0.3和0.03都不大,但是相比較而言,和第一類相對相關,而和第二類基本無關。
最後一個矩陣Y是對文本的分類結果。它的每一列對應一篇文本,每一行對應一個主題。這一列中的每個元素表示這篇文本在不同主題中的相關性。我們同樣用一個2×4的小矩陣來說明。
這裡面有四篇文本,兩個主題。第一篇文本很明顯,屬於第一個主題。第二篇文本和第二個主題非常相關(相似性為0.92),而和第一個主題有一點點關係(0.15)。第三個文本和兩個主圖都不很相關,相比較而言,和第一個主題的關係稍微近一點。第四篇文本,和兩個主題都有一定的相關性,不過和第二個主題更接近一些。如果每一列只保留最大值,其餘均改為零,那麼每一篇文本都只歸入一類主題中,即第一、三篇文本屬於第一個主題,第二、四篇文本屬於第二個主題。
中間的矩陣則表示詞的類和文章的類之間的相關性。我們用下面2×2的矩陣來說明。
在這個矩陣B中,第一個詞的語義類和第一個主題相關,和第二個主題沒有太多關係。而第二個詞的語義類則相反。
因此,只要對關聯矩陣A進行一次奇異值分解,就可以同時完成近義詞分類和文章的分類。另外,還能得到每個主題和每個詞的詞義類之間的相關性。這個結果非常漂亮。
這算是矩陣在人工智慧方面的一個簡簡單單的應用了吧。
二、數字圖像處理
二、數字圖像處理
由於小編大學期間學的專業是測繪學,要上關於遙感的一系列課程,所以數字圖像處理是我的必修課,矩陣在圖像處理方面的應用也是很多。
數字圖像處理:
數字圖像處理(Digital Image Processing)是通過計算機對圖像進行去除雜訊、增強、復原、分割、提取特徵等處理的方法和技術。
圖像平滑:
圖像平滑是指受感測器和大氣等因素的影響,圖像上會出現某些亮度變化過大的區域,或出現一些亮點(也稱雜訊)。這種為了抑制雜訊,使圖像亮度趨於平緩的處理方法就是圖像平滑。圖像平滑實際上是低通濾波,平滑過程會導致圖像邊緣模糊化。
圖像去噪:
雜訊對人的影響雜訊可以理解為「 妨礙人們感覺器官對所接收的信源信息理解的因素」。而圖像中各種妨礙人們對其信息接受的因素即可稱為圖像雜訊 。雜訊在理論上可以定義為「不可預測,只能用概率統計方法來認識的隨機誤差」。因此將圖像雜訊看成是多維隨機過程是合適的,因而描述雜訊的方法完全可以借用隨機過程的描述,即用其概率分布函數和概率密度分布函數。 比較常用的去噪演算法是濾波法。
例如高斯濾波的模板,如下矩陣:
模板運算的數學涵義實際上是一種卷積運算,下面用java代碼來實現去噪。
多吃水果的好處
由於小編大學期間專業是測繪學,涉及遙感的一系列課程,所以數字圖像處理是我的必修課,矩陣在圖像處理方面的應用也是很多。
1.數字圖像處理:(Digital Image Processing)是通過計算機對圖像進行去除雜訊、增強、復原、分割、提取特徵等處理的方法和技術。
2.圖像平滑:指受感測器和大氣等因素的影響,圖像上會出現某些亮度變化過大的區域,或出現一些亮點(也稱雜訊)。這種為了抑制雜訊,使圖像亮度趨於平緩的處理方法就是圖像平滑。圖像平滑實際上是低通濾波,平滑過程會導致圖像邊緣模糊化。
3.圖像去噪:雜訊對人的影響雜訊可以理解為「 妨礙人們感覺器官對所接收的信源信息理解的因素」。而圖像中各種妨礙人們對其信息接受的因素即可稱為圖像雜訊 。雜訊在理論上可以定義為「不可預測,只能用概率統計方法來認識的隨機誤差」。因此將圖像雜訊看成是多維隨機過程是合適的,因而描述雜訊的方法完全可以借用隨機過程的描述,即用其概率分布函數和概率密度分布函數。 比較常用的去噪演算法是濾波法。
例如高斯濾波的模板,如下矩陣:
模板運算的數學涵義實際上是一種卷積運算,下面用java代碼來實現去噪。
importjava.awt.Color;
importjava.awt.color.ColorSpace;
importjava.awt.image.BufferedImage;
importjava.awt.image.ColorConvertOp;
importjava.io.File;
importjava.io.IOException;
importjavax.imageio.ImageIO;
publicclassTest{
/**
*
*@paramsfile
* 需要去噪的圖像
*@paramdestDir
* 去噪後的圖像保存地址
*@throwsIOException
*/
publicstaticvoidcleanImage(File sfile, String destDir)throwsIOException{
File destF =newFile(destDir);
if(!destF.exists()){
destF.mkdirs();
}
BufferedImage bufferedImage = ImageIO.read(sfile);
inth = bufferedImage.getHeight();
intw = bufferedImage.getWidth();
// 灰度化
int[][] gray =newint[w][h];
for(intx =; x < w; x++){
for(inty =; y < h; y++){
intargb = bufferedImage.getRGB(x, y);
// 圖像加亮(調整亮度識別率非常高)
intr = (int) (((argb >>16) &0xFF) *1.1+30);
intg = (int) (((argb >>8) &0xFF) *1.1+30);
intb = (int) (((argb >>) &0xFF) *1.1+30);
if(r >=255){
r =255;
}
if(g >=255){
g =255;
}
if(b >=255){
b =255;
}
gray[x][y] = (int) Math.pow((Math.pow(r,2.2) *0.2973+ Math.pow(g,2.2)*0.6274+ Math.pow(b,2.2) *0.0753),1/2.2);
}
}
// 二值化
intthreshold = ostu(gray, w, h);
BufferedImage binaryBufferedImage =newBufferedImage(w, h,BufferedImage.TYPE_BYTE_BINARY);
for(intx =; x < w; x++){
for(inty =; y < h; y++){
if(gray[x][y] > threshold){
gray[x][y] =0x00FFFF;
}else{
gray[x][y] &=0xFF0000;
}
binaryBufferedImage.setRGB(x, y, gray[x][y]);
}
}
// 矩陣列印
for(inty =; y < h; y++){
for(intx =; x < w; x++){
if(isBlack(binaryBufferedImage.getRGB(x, y))){
System.out.print("*");
}else{
System.out.print(" ");
}
}
System.out.println();
}
ImageIO.write(binaryBufferedImage,"jpg",newFile(destDir, sfile.getName()));
}
publicstaticbooleanisBlack(intcolorInt){
Color color =newColor(colorInt);
if(color.getRed() + color.getGreen() + color.getBlue()
returntrue;
}
returnfalse;
}
publicstaticbooleanisWhite(intcolorInt){
Color color =newColor(colorInt);
if(color.getRed() + color.getGreen() + color.getBlue() >300){
returntrue;
}
returnfalse;
}
publicstaticintisBlackOrWhite(intcolorInt){
if(getColorBright(colorInt) 730){
return1;
}
return;
}
publicstaticintgetColorBright(intcolorInt){
Color color =newColor(colorInt);
returncolor.getRed() + color.getGreen() + color.getBlue();
}
publicstaticintostu(int[][] gray,intw,inth){
int[] histData =newint[w * h];
// Calculate histogram
for(intx =; x < w; x++){
for(inty =; y < h; y++){
intred =0xFF& gray[x][y];
histData[red]++;
}
}
// Total number of pixels
inttotal = w * h;
floatsum =;
for(intt =; t
sum += t * histData[t];
floatsumB =;
intwB =;
intwF =;
floatvarMax =;
intthreshold =;
for(intt =; t
wB += histData[t];// Weight Background
if(wB ==)
continue;
wF = total - wB;// Weight Foreground
if(wF ==)
break;
sumB += (float) (t * histData[t]);
floatmB = sumB / wB;// Mean Background
floatmF = (sum - sumB) / wF;// Mean Foreground
// Calculate Between Class Variance
floatvarBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);
// Check if new maximum found
if(varBetween > varMax){
varMax = varBetween;
threshold = t;
}
}
returnthreshold;
}
publicstaticvoidmain(String[] args)throwsIOException{
File testDataDir =newFile("E:\tmp\1.jpg");//去噪
String destDir ="E:\tmp\tmp";
cleanImage(testDataDir, destDir);
}
}
????三、矩陣的簡單運算
本次利用java來實現矩陣相乘這一簡單的運算。???
publicclassTest{
introw;
intcol;
privateint[][]array;
privateTest(){
//構造函數私有化,使用setArray方法進行初始化
}
publicint[][] getArray() {
returnarray;
}
publicvoidsetArray(int[][]array){
//判斷 二維數組是否為合法矩陣
introw =array.length;
intcol =array[].length;
for(inti =1;i < row;i++){
if(col!=array[i].length){
System.out.println("輸入的不是一個矩陣,請重新輸入");
return;
}
}
this.row = row;
this.col = col;
this.array=array;
}
publicStringtoString(){
if(array==null){
return"矩陣為空,請重新輸入一個矩陣";
}
String s ="";
row =array.length;
col =array[row-1].length;
for(inti =;i < row;i++){
for(intj =;j < col;j++){
s+=array[i][j]+" ";
}
s+="
";
}
returns;
}
publicTestmultip(Test x){
Test m =newTest();
m.setArray(multip(x.getArray()));
returnm;
}
privateint[][] multip(int[][] aim){
if(this.col!=aim.length){
System.out.println("兩個矩陣不可以相乘");
returnnull;
}
int[][] result =newint[this.row][aim[].length];
for(introw =;row
for(intcol =;col < aim[].length;col++){
intnum =;
for(inti =;i
num+=array[row][i]*aim[i][col];
}
result[row][col]=num;
}
}
returnresult;
}
publicstaticvoidmain(String[] args){
Test m =newTest();
Test m2 =newTest();
int[][]rec = {{1,,2},{2,,3},{3,8,7}};
int[][]rec2 = {{8,1},{1,2},{2,6}};
m.setArray(rec);
m2.setArray(rec2);
System.out.println(m);
System.out.println(m2);
System.out.println(m.multip(m2));
}
}
本次小編寫的文章不是想教會大家什麼,因為還是比較有難度只能簡單地介紹一下,而真正想告訴大家的是,數學在it行業也非常重要,大家也知道互聯網行業也是一個發展非常快的行業,所以希望大家在空閑的時候多學習一點數學知識,相信在你成為it工程師的路上不會太遠!
....................END.......................
TAG:手集名品學習平台 |