【问题标题】:Shannon Entropy香农熵
【发布时间】:2014-01-07 07:12:49
【问题描述】:

以下 C++ 代码(原样)来自http://rosettacode.org/wiki/Entropy。有错误 - 任何人都可以纠正它们吗?

#include <string>
#include <map>
#include <iostream>
#include <algorithm>
#include <cmath>

double log2( double number ) {
    return log( number ) / log( 2 ) ;
}

int main( int argc , char *argv[ ] ) {
    std::string teststring( argv[ 1 ] ) ;
    std::map<char , int> frequencies ;

    for ( char c : teststring )
        frequencies[ c ] ++ ;

    int numlen = teststring.length( ) ;
    double infocontent = 0 ;

    for ( std::pair<char , int> p : frequencies ) {
        double freq = static_cast<double>( p.second ) / numlen ;
        infocontent += freq * log2( freq ) ;
    }

    infocontent *= -1 ;

    std::cout << "The information content of " << teststring 
      << " is " << infocontent << " !\n" ;
    return 0 ;
}

第一个错误似乎通过以下方式修复:

double log2( double n )  
{  
    // log(n)/log(2) is log2.  
    return log( n ) / log( 2. );  
}

我不确定他们想说什么:

for ( char c : teststring )

【问题讨论】:

  • for 循环称为“for each”循环
  • 您能否解释一下您想要哪种图像以及您的标准/措施/...? L2 够用吗?如果在生成中是 1D,那么原始信号是什么?通常,规范是不够的。请提供其他条件。 - - 我认为您的熵函数不足以研究图像的熵。它大约是一维信号。我很想听听您为什么认为您的 1D 方法及其对字符的扩展可能足以用于图像。我认为没有考虑措施和位基数。你的来源是有限的。相关cs.stackexchange.com/q/4935/10350,但仍然是一个存根。
  • 您在图像中使用香农熵的目标是什么?

标签: c++ entropy


【解决方案1】:

这个很好用

template <typename T> static float ShannonEntropy(T data[],int elements){
    float entropy=0;
    std::map<T,long> counts;
    typename std::map<T,long>::iterator it;
    //
    for (int dataIndex = 0; dataIndex < elements; ++dataIndex) {
        counts[data[dataIndex]]++;
    }
    //
    it = counts.begin();
    while(it != counts.end()){
        float p_x = (float)it->second/elements;
        if (p_x>0) entropy-=p_x*log(p_x)/log(2);
        it++;
    }
    return entropy;
}

【讨论】:

    【解决方案2】:

    循环是一个 foreach 循环。意思是:对于teststring中的每个字符,将其放入变量c中,做循环体。

    同样可以用一个常规的for循环和一个索引变量来表达,但这种方式更短更容易阅读。其他语言如 C# 和 Java 很长一段时间都有此功能,但 C++ 仅在 STL 中具有一些不那么可读的模板功能。

    这是C++ 11 的新功能,如果不兼容,您的编译器会报错。如果遇到错误,请尝试获得更好的编译器。

    【讨论】:

    • 谢谢,我怀疑我的编译器。我正在寻找一种快速简便的方法来计算形成交叉结构的短(文本)DNA 字符串的熵......在我的项目中间学习一个新的编译器并不是一个很好的选择。更好的是,如果有人能指出一些能达到我目的的简洁代码。
    【解决方案3】:

    这是我的图像熵的java代码

    public static double getShannonEntropy_Image(BufferedImage actualImage){
            List<String> values= new ArrayList<String>();
            int n = 0;
            Map<Integer, Integer> occ = new HashMap<>();
            for(int i=0;i<actualImage.getHeight();i++){
                    for(int j=0;j<actualImage.getWidth();j++){
                            int pixel = actualImage.getRGB(j, i);
                            int alpha = (pixel >> 24) & 0xff;
                            int red = (pixel >> 16) & 0xff;
                            int green = (pixel >> 8) & 0xff;
                            int blue = (pixel) & 0xff;
                            //0.2989 * R + 0.5870 * G + 0.1140 * B greyscale conversion
                            //System.out.println("i="+i+" j="+j+" argb: " + alpha + ", " + red + ", " + green + ", " + blue);
                            int d= (int)Math.round(0.2989 * red + 0.5870 * green + 0.1140 * blue);
                            if(!values.contains(String.valueOf(d)))
                                    values.add(String.valueOf(d));
                            if (occ.containsKey(d)) {
                                    occ.put(d, occ.get(d) + 1);
                            } else {
                                    occ.put(d, 1);
                            }
                            ++n;
                    }
            }
            double e = 0.0;
            for (Map.Entry<Integer, Integer> entry : occ.entrySet()) {
                    int cx = entry.getKey();
                    double p = (double) entry.getValue() / n;
                    e += p * log2(p);
            }
            return -e;
    }
    

    【讨论】:

    • 一两句解释对于做出正确答案和优秀答案大有帮助。
    • 您的代码使用数组和 HashMap 作为数据结构。您研究图像的高度并循环它 - 按列研究特征。最后,您遍历特征集并使用键和概率将特征映射到它们。您对图像使用非常简单的一维熵度量。您也假设 2 位信号数据。 - - 此代码不足以研究图像中的熵。
    【解决方案4】:

    第一个错误是因为 C 库名称的失败。没有指定log 的哪些重载被转储到全局命名空间中;据推测,作者的实现只有一个,因此log(2) 是明确的,但您的实现具有所有这些,因此产生歧义,因为没有一个采用int 类型。为了便于携带,它应该是std::log(2.)。更好的是,使用 std::log2 而不是重新发明它。

    第二个是“基于范围的for 语句”,于 2011 年引入该语言,它迭代数组、容器或其他序列的每个元素。您将需要一个相当现代的编译器,并且您可能需要专门启用 C++11 支持。例如,对于 GCC,您需要命令行参数 -std=c++11(或旧版本的 c++0x)。

    【讨论】:

      猜你喜欢
      • 2021-12-02
      • 2014-03-31
      • 1970-01-01
      • 1970-01-01
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      • 2013-02-07
      • 1970-01-01
      相关资源
      最近更新 更多