一、引入信息熵計算公式
信息論是現代世界非常重要的一種觀念,你肯定聽過“比特”“信息熵”之類的詞,這些概念似乎都比較技術化。那不搞技術的人也需要了解嗎?答案是非常需要。在我看來,信息論並不僅僅是技術理論,更是一種具有普世價值的思想。瞭解信息論,你就多了一種觀察世界的眼光。甚至可以從信息論中推導出一種人生觀來。
一段消息所包含的信息量,並不僅僅由這條消息的長短決定。這就好像人生一樣,活了同樣歲數的兩個人,他們人生經歷的豐富程度可能大不相同。
現代信息論的祖師爺。克勞德·香農有一個洞見:一個東西信息量的大小,取決於它克服了多少不確定性。
舉個生活中的例子。有個人生活非常規律,平時會去的就是家裏、公司、餐館、健身房這四個地方。如果我僱你做特工,幫我觀察這個人,隨時向我彙報他的位置。那你每次給我的信息無非就是“家裏/公司/餐館/健身房”中的一個——即使你不告訴我,我猜對的概率也有。所以你給我的信息價值不大。
但如果這個人滿世界跑,今天在土耳其,明天在沙特阿拉伯,我完全猜不到他在哪裏,你給我的信息可就非常值錢了。你提供信息之前。這個人的位置對我來說具有不確定性。你的信息,克服了這個不確定性。原來的不確定性越大,你的信息就越有價值。
我們用一個簡單的公式來量化這個思想。香龍從統計物理學中借鑑了一個概念——信息熵。這個概念看起來嚇人,其實很簡單,就是一段消息的平均信息量。一個東西信息量的大小,取決於它克服了多大的不確定性。香農對信息量的定義是,如果一個字符出現在這個位置的概率是,那麼這個字符的信息量就是。
香濃舉例說。假如我們有一個完美公正的硬幣,每次拋出正面朝上的概率都是,如果這一次拋出的結果是正面朝上,這個消息的信息量就是。而信息熵,就是把一條消息中出現的所有字符做信息量的加權平均。
還是用硬幣的例子,表示正面朝上,表示反面朝上。一系列投擲結果可能是:。如果正反面出現的概率都正好是,那麼這一串消息不管多長,信息熵都是, 香農規定信息量的單位是“比特”,這個信息熵就是比特。這意味着,對消息中的每個字符,至少需要比特的信息才能編碼。
如果這個硬幣“不公平”,出現的次數比出現更多,比如,那麼信息熵就不是比特了。在這個例子中,出現的概率是,出現的概率是,信息熵就變成了比特。
信息熵跟消息的長度沒有必然關係,它表示的是這段消息中字符的“不可預測性”。一段字符中出現的各種字符越是雜亂無章,越具有多樣性,信息熵就越高。比如這樣一個字符串——。每個字母都不一樣,它的信息熵是比特。而如果字符串中有很多重複的字母,那它的“可預測性”就很高,信息商就會變低,比如字符串“”的信息熵只有比特。
信息熵 =
這裏爲了簡化,計算時只考慮了字符出現的頻率,如果從語法和內容角度進一步考慮,每個字符的可預測性,信息熵就是另一種個數值了。
信息之所以叫“熵”,是因爲它跟統計物理學中熵的公式幾乎一樣,物理學裏“熵”大致描述了一個系統的混亂程度——信息熵也是如此。越是看上去雜亂無章的消息,信息熵就越高,信息量就越大。
如果一段消息只能從和兩個數字中選,它的信息熵最大也只有比特;如果能從個字母中選,信息熵最大可以達到比特。
如果是從個漢字中選,信息熵則可以達到比特。
這就是爲什麼中文是一種更高效的語言。
你如果沒有看懂上述數學部分不要緊,只要記住一句話:可供選擇的範圍越廣,選擇的信息量就越大。
——摘自萬維鋼《你有你的計劃,世界另有計劃》
信息熵公式:
二、編程計算上文涉及的信息熵
- 編寫程序“計算信息熵.py”
"""
計算信息熵
"""
from math import *
s = "0011100101"
e = -(0.5 * log(0.5, 2) + 0.5 * log(0.5, 2))
print("[{}]的信息熵 = {}".format(s, e))
s = "1101110011"
e = -(0.3 * log(0.3, 2) + 0.7 * log(0.7, 2))
print("[{}]的信息熵 = {}".format(s, round(e, 2)))
s = "asdogrpfkn"
e = 0
for i in range(10):
e = e - 0.1 * log(0.1, 2)
print("[{}]的信息熵 = {}".format(s, round(e, 2)))
s = "asdfasdfooasop"
pa = 3 / 14
ps = 3 / 14
pd = 2 / 14
pf = 2 / 14
po = 3 / 14
pp = 1 / 14
e = -(pa * log(pa, 2) + ps * log(ps, 2) + pd * log(pd, 2) + pf * log(pf, 2) + po * log(po, 2) + pp * log(pp, 2))
print("[{}]的信息熵 = {}".format(s, round(e, 2)))
# 從26個字母中選的信息熵
e = 0
for i in range(26):
e = e - 1 / 26 * log(1 / 26, 2)
print("[從26個字母中選]的信息熵 = {}".format(round(e, 2)))
# 從2500個漢字中選的信息熵
e = 0
for i in range(2500):
e = e - 1 / 2500 * log(1 / 2500, 2)
print("[從2500個漢字中選]的信息熵 = {}".format(round(e, 1)))
- 運行程序,查看結果
三、編寫Python函數計算字符串的信息熵
1、編寫程序“計算字符串的信息熵.py”
2、運行程序,查看結果
四、編寫Java方法計算字符串的信息熵
1、創建CalculateEntropy類
package net.hw.lesson21;
import java.util.*;
/**
* 功能:計算字符串信息熵
* 作者:華衛
* 日期:2020年05月22日
*/
public class CalculateEntropy {
public static double entropy(String str) {
int n = str.length();
Set<String> set = new HashSet<>();
for (int i = 0; i < n; i++) {
set.add(String.valueOf(str.charAt(i)));
}
List<Double> p = new ArrayList<>();
for (String x : set) {
int count = 0;
for (int i = 0; i < n; i++) {
if (x.equalsIgnoreCase(String.valueOf(str.charAt(i)))) {
count++;
}
}
p.add(count * 1.0 / n);
}
Double e = 0.0;
for (int i = 0; i < p.size(); i++) {
e = e - p.get(i) * Math.log(p.get(i)) / Math.log(2);
}
return e.doubleValue();
}
public static void main(String[] args) {
String str;
double e;
Scanner sc = new Scanner(System.in);
System.out.print("字符串:");
str = sc.nextLine();
e = entropy(str);
System.out.println("信息熵:" + String.format("%.2f",e));
}
}
2、運行程序,查看結果