数学,始终环绕在我们的身边。大家一般对数学的用途产生过怀疑,除了初等数学。比如很多大学生毕业后,数学知识可能一辈子都没有机会应用,久而久之也就忘得差不多了,致使很多人产生了为什么要学习数学的疑问。事实上数学的用途在我们的生活中无处不在,甚至可以说远远超乎人们的想象。现今每个人都要使用搜索,在人工智能技术异常爆棚的这几年,以及神奇的语音识别、机器翻译和自然语言处理等技术,也许大家想不到,应用这些技术最好工具就是数学。
矩阵是线性代数中一个重要的工具,关于矩阵的概念有许多,如转置,矩阵的秩,特征值等,这些知识已经脱离了日常生活,但是,矩阵在计算机编程方面的应用很多,如数字图像处理,数学建模,自然语言处理,数据分析与优化等多种方面。今天我们就矩阵的用途做个主要介绍。
一、文本和词汇的矩阵
自然语言处理(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+="\r\n";
}
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.......................
领取专属 10元无门槛券
私享最新 技术干货