计算一篇英文文章里26个英文字母的状态转移矩阵,以及这篇文章含有的信息熵
(由于该课题来自信息论作业,要求小组内合作完成,所以本文是三个人用三个不同的语言编程三个部分)
| 成员 | 姓名 | 任务 |
|---|---|---|
| 组长 | 马靓颖 | 搜集英文文章,整理整体思路,计算状态转移矩阵 |
| 组员 | 郭俊康 | 统计文章字母总数,帮助解决其他成员遇到的问题 |
| 组员 | 蒋旭宾 | 求解特征向量,计算信息熵 |
问题描述
(一)问题分析(二)问题求解
1.统计字母总数2.计算状态转移矩阵3.求解特征向量C和信息熵 (三)结论
(一)问题分析首先统计文章里字母总数
计算状态转移矩阵P
把a字母后面出现a的概率记为aa,即a后面出现a的个数÷a的总个数,则矩阵P表示为:
aa ab ac … az
ba bb bc … bz
…
za zb zc … zz
求该矩阵对应特征向量C
即求解
(
P
T
−
E
)
X
=
0
(P^T-E)X=0
(PT−E)X=0的非0解(正常情况下只有一个,即该矩阵的秩为25,原矩阵
r
a
n
k
(
P
)
=
26
rank( P)=26
rank(P)=26),再归一化
计算信息熵 H ∞ = C ∗ H ( P ) H_{infty}=C*H(P) H∞=C∗H(P)
郭俊康:
满意:通过编程实现了对任意一篇英文文章的自然语言熵的计算不足:没有考虑非英文字符串的情况,情况考虑不全面
//C++ 统计字母总数 #includeusing namespace std; int main() { char ch; char s_letter[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'}; char b_letter[26]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; int num[26]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; float f_num[26]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int Sum; for (int i = 1; i <= 10000; i++) { ch = cin.get();//读入文章 if(ch == '#')break; for(int j=0;j<=25;j++) { if(ch==s_letter[j] || ch==b_letter[j]) num[j]++; } } for(int i=0;i<=25;i++) { cout< 输出结果:
2.计算状态转移矩阵
马靓颖:
满意:自行设计出了从字母aa到zz循环的算法,利用了字符、数字和字符串之间相加的性质;统计特定字符在字符串中的个数通过借鉴统计单个字符在字符串中的个数的思想,再加以改进得到本文算法不足:最终输出结果P矩阵无法正常显示出来,但是检查了P的元素是有具体数值的,猜测是26*26矩阵过大,系统用了某种方法折叠了结果解决方法:利用可以输出的26*26=676个单个数值,存储成一维数组代替原本打算的二维数组,在下一阶段的计算中再转化为矩阵
//Java 求状态转移矩阵 import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class HH { public static void main(String[] args) { Listlist = HH.getContent();//调用方法getContent读取txt文件 for (String s : list) {//对于文件里每一个字符s s=s.toLowerCase();//把大写字母转化为小写字母 float [][] P = new float [26][26];//建立矩阵P //建立循环计算文章中出现 aa,ab,...,ba,bb,...,zz 的个数 for (int i=0;i<26;i++){ for(int j=0;j<26;j++){ char a='a';//对列操作 char aj=(char)(a+j);//字符与数字相加把结果强制转换类型为字符型,即可从字符a得到字符b,c,...,z String A=Character.toString(aj);//再转换为字符串型 char b='a';//对行操作 char bi=(char)(b+i);//同理 String B=Character.toString(bi);//同理 String AB = A+B;//字符串相加是直接拼接,即可得到aa,ab,...,zz字符串 String result=s.replace(AB,"");//把AB字符替换成空白 int num = (s.length()-result.length())/AB.length();//(原长度减-现有长度)/AB字符的长度=AB字符的个数 System.out.println(AB+" "+num);//输出每个字符串对应数量 P[i][j]=num;//把结果存在矩阵P中 } } System.out.println(P);//输出P } } //封装一个方法,功能:读取txt文件 public static List getContent() { String fileName = "F:\临时有用的东西\信息论\word.txt"; List lineLists = null; try { lineLists = Files .lines(Paths.get(fileName), Charset.defaultCharset()) .flatMap(line -> Arrays.stream(line.split("n"))) .collect(Collectors.toList()); } catch (IOException e) { e.printStackTrace(); } return lineLists; } } 该部分只统计了个数,并没有直接计算概率,放在了下一部分中
3.求解特征向量C和信息熵
输出结果:
(部分截图)
蒋旭宾:
满意:进一步加深了自然语言熵的理解,对编程有一定的进步不足:对于特征值和特征向量出现复数的情况并没有进行进一步了解
%MATLAB 求解特征向量和信息熵 clc;clear; %%%%%%%%%导入数据 data=xlsread('E:dataya.csv'); A=zeros(26,26); %% %将数据转化为矩阵 for i=1:26 for j=1:26 A(i,j)=data(i*(j-1)+j); end end %% SumX=sum(A,2); %将矩阵每一行除以行总数 for i=1:26 for j=1:26 A(i,j)=A(i,j)/SumX(i); end end %% %求状态转移矩阵P E=eye(26,26); %定义单位矩阵26*26 % rank(A) B=A'-E; %B为A的转置矩阵-E % rank(B) [X,D]=eig(B); %求特征值与特征向量X为特征向量。D为特征值 D=diag(D); %将特征值单独取出 %去除出现虚部的特征值与特征向量 Real_D=zeros(1,26); for i=1:26 if (imag(D(i))==0)&&(real(D(i))~=0) Real_D(i)=D(i); end end %提取特征值非复数的特征向量 real_X=zeros(26,26); for i=1:26 if Real_D(i)~=0 real_X(:,i)=X(:,i) end end %% %进行归一化处理 V=sum(real_X); T=real_X(:,1)/V(1) %进行这一步的时候我们发现仅有一组特征向量的和非0 ,其它都为0,故仅取第一组。 % for i=1:26 % real_X=real_X(:,i)/V(i); % end %% %求hp Hp=zeros(1,26); for i=1:26 for j=1:26 if A(i,j)==0 Hp(i)=Hp(i); else Hp(i)=Hp(i)-A(i,j)*log2(A(i,j)); end end end %% Hp*T输出结果:
(三)结论
(部分截图)
根据本文用到的英语文章,2694个英文字母中含有的信息熵是2.5437



