(float) entropy = 0
for i in the array[256]:Counts do
(float)p = Counts[i] / filesize
if (p > 0) entropy = entropy - p*lg(p) // lgN is the logarithm with base 2
import math
entropy = 0
for count in byte_counts:
# If no bytes of this value were seen in the value, it doesn't affect
# the entropy of the file.
if count == 0:
continue
# p is the probability of seeing this byte in the file, as a floating-
# point number
p = 1.0 * count / total
entropy -= p * math.log(p, 256)
/// <summary>
/// returns bits of entropy represented in a given string, per
/// http://en.wikipedia.org/wiki/Entropy_(information_theory)
/// </summary>
public static double ShannonEntropy(string s)
{
var map = new Dictionary<char, int>();
foreach (char c in s)
{
if (!map.ContainsKey(c))
map.Add(c, 1);
else
map[c] += 1;
}
double result = 0.0;
int len = s.Length;
foreach (var item in map)
{
var frequency = (double)item.Value / len;
result -= frequency * (Math.Log(frequency) / Math.Log(2));
}
return result;
}
正如 Nick Dandoulakis 建议的那样,逐字节计算熵给出了一个非常糟糕的估计,因为它假设每个字节都是独立的。例如,在文本文件中,字母后面有一个小字母比字母后面有一个空格或标点符号的可能性大得多,因为单词通常比2个字符长。因此,下一个字符在 a-z 范围内的概率与前一个字符的值相关。不要使用 Nick 的粗略估计来获得任何实际数据,而是使用 gzip 压缩比。
简短的回答: 使用我下面的第一个和第三个粗体方程来得到大多数人在用比特表示文件的“熵”时所想的。如果你想得到 Shannon 的 H 熵,就用第一个方程,H 熵实际上是熵/符号,他在论文中提到了13次,大多数人都没有意识到。一些在线熵计算器使用这一个,但香农的 H 是“特定熵”,而不是“总熵”,这已经造成了如此多的混乱。如果你想要0和1之间的答案,使用第一和第二个方程,这是规范化的熵/符号(它不是比特/符号,而是一个真正的统计测量数据的“熵性质”,让数据选择自己的对数基,而不是任意分配2,e 或10)。
有 N 个符号的文件(数据)的 四种类型的熵与 n 个唯一类型的符号长。但是请记住,通过了解文件的内容,您可以知道文件的状态,因此 S = 0。准确地说,如果您有一个能够生成大量可访问数据的源,那么您可以计算该源的预期未来熵/特征。如果您对一个文件使用以下内容,则更准确地说,它是在估计来自该源的其他文件的预期熵。
Shannon (特定)熵 H = -1 * sum (count _ i/N * log (count _ i/N))
其中 count _ i 是符号 i 在 N 中出现的次数。
如果日志以2为基数,单位是位/符号; 如果是自然日志,单位是 Nats/符号。
归一化比熵: H/log (n)
单位是熵/符号。范围从0到1。1表示每个符号出现的频率相同,接近0表示除1以外的所有符号只出现一次,而一个非常长的文件的其余部分是另一个符号。日志和 H 在同一个底部。
绝对熵 S = N * H
如果 log 为基数2,则单位为位; 如果 ln () ,则单位为 nats。
归一化绝对熵
单位是“熵”,从0到 N 不等。对数和 H 在同一个基数上。
虽然最后一个是最真实的“熵”,第一个(香农熵 H)是所有书籍所谓的“熵”没有(必要的恕我直言)的限定。大多数人没有澄清(就像 Shannon 做的那样) ,它是位/符号或每个符号的熵。称 H 为“熵”说得太宽泛了。
对于每个符号频率相同的文件: S = N * H = N。这是大多数位元大型档案的情况。熵不会对数据进行任何压缩,因此完全不知道任何模式,所以000000011111111和0101000(两种情况下都是6个1和6个0)具有相同的 H 和 S。
另一件需要考虑的事情是: 如果您改变了表达数据的方式,则 H 会发生变化。如果您选择不同的位组(位、点、字节或十六进制) ,H 将不同。所以除以 log (n) ,其中 N是数据中唯一符号的数量(二进制为2,字节为256) ,H 的范围从0到1(这是标准化的强化香农熵,以每个符号的熵为单位)。但是从技术上讲,如果256种类型的字节中只有100种出现,那么 n = 100,而不是256。
H 是一个“密集型”熵,也就是说,它是每个符号,类似于物理学中的 特定熵,即每千克或每摩尔的熵。类似于物理学中的 S 的文件的正则“扩展”熵是 S = N * H,其中 N是文件中的符号数。H 将完全类似于理想气体体积的一部分。在更深的意义上,熵不能简单地等同于物理熵,因为物理熵允许“有序”和无序的排列: 物理熵不仅仅是完全随机的熵(比如压缩文件)。不同的一个方面对于一个理想气体,还有一个额外的5/2因子来解释这个: S = k * N * (H + 5/2) ,其中 H = 每个分子可能的量子态 = (xp) ^ 3/hbar * 2 * sigma ^ 2,其中 x = 盒子的宽度,p = 系统中的总非定向动量(由每个分子的动能和质量计算) ,sigma = 0.341,符合不确定性原理,只给出1 std dev 内可能态的数目。
一个小小的数学给出了一个文件的归一化广义熵的简化形式:
S = N * H/log (n) = sum (count _ i * log (N/count _ i))/log (n)
这个单位叫做“熵”(它实际上不是一个单位)。它被归一化为比 N * H 的“熵”单位更好的通用度量。但是,在没有澄清的情况下,它也不应该被称为“熵”,因为正常的历史惯例是错误地将 H 称为“熵”(这与香农文本中的澄清相反)。
public static double shannon_entropy(File file) throws IOException {
byte[] bytes= Files.readAllBytes(file.toPath());//byte sequence
int max_byte = 255;//max byte value
int no_bytes = bytes.length;//file length
int[] freq = new int[256];//byte frequencies
for (int j = 0; j < no_bytes; j++) {
int value = bytes[j] & 0xFF;//integer value of byte
freq[value]++;
}
double entropy = 0.0;
for (int i = 0; i <= max_byte; i++) {
double p = 1.0 * freq[i] / no_bytes;
if (freq[i] > 0)
entropy -= p * Math.log(p) / Math.log(2);
}
return entropy;
}
usage-example:
File file=new File("C:\\Users\\Somewhere\\In\\The\\Omniverse\\Thanos Invasion.Log");
int file_length=(int)file.length();
double shannon_entropy=shannon_entropy(file);
System.out.println("file length: "+file_length+" bytes");
System.out.println("shannon entropy: "+shannon_entropy+" nats i.e. a minimum of "+shannon_entropy+" bits can be used to encode each byte transfer" +
"\nfrom the file so that in total we transfer atleast "+(file_length*shannon_entropy)+" bits ("+((file_length*shannon_entropy)/8D)+
" bytes instead of "+file_length+" bytes).");