Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Энтропия текста 
:(
    Опции темы
Bugrimov
  Дата 26.11.2012, 18:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Доброе время суток!
Нужна помощь в вопросе нахождения энтропии текста, максимальной энтропии и избыточности текста. Кто-нибудь сталкивался с данным вопросом?

Добавлено @ 18:13
Есть следующая функция, до которой я додумался

Код

void entropy(void)
{
    FILE    *pf = NULL;
    char    file[SIZE];
    long    ch, i, prev, total = 0;
    int        code[256] = {0}, code_p[256*256] = {0};
    float    entr = 0, entr_p = 0, max_entr, max_entr_p;
    

    Messages(2);
    printf("\n\n");
    system("DIR /a:-d");
    
    
    printf("\n Введите имя файла: ");
    gets(file);
    pf = fopen(file, "rt");    // Открытие файла для чтения
    if(pf == NULL)
    {
        Messages(3);
        printf("\n Выбрать файл (ENTER) / Выход в меню (ESC)");
        if(getch() == 27)
            menu();
        else
            entropy();
    }
    while((ch = fgetc(pf)) != EOF)
    {
        if(strchr(".,:;?!-\'\"", ch))    // Если в тексте встречаются знаки препинания
            ch = '.';                    // объединить в один символ '.'
        code[ch]++;    // Считает число символов каждого типа
        
    }

    for(i = 0; i < 256; i++)
        total += code[i];    // Число символов

    for(i = 0; i < 256; i++)
        if(code[i])
        entr -= code[i]*log(((float)code[i])/total);
    entr /= log(2)*total;
    max_entr = log(total)/log(2);
    
    printf("\n Энтр. для символа: %6.3f Макс. энтропия: %6.3f Избыточ.: %6.3f", entr, max_entr, max_entr/entr);
    
    
    rewind(pf);
    total = 0;
    prev = fgetc(pf);
    while((ch = fgetc(pf)) != EOF)
    {
        if (strchr(".,:!?'\"", ch))
            ch = '.';
        code_p[prev*256 + ch]++;
        prev = ch;
    }

    for(i = 0; i < 256*256; i++)
        total += code_p[i];
    
    for(i = 0; i < 256*256; i++)
        if(code_p[i])
        entr_p -= code_p[i]*log(((float)code_p[i])/total);
    entr_p /= log(2)*total*2;
    max_entr_p = log(total)/log(2.7);
    printf("\n Энтр. для пар символов: %6.3f Макс. энтропия: %6.3f Избыточ.: %6.3f", entr_p, max_entr_p, max_entr_p/entr_p);
    
    

    fclose(pf);
    getch();
}


Но, на сколько я понимаю, максимальная энтропия и избыточность находятся не верно.  smile 
Нужен совет знающих людей.

Это сообщение отредактировал(а) Bugrimov - 26.11.2012, 18:15
PM MAIL   Вверх
Dem_max
Дата 26.11.2012, 18:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 4
Всего: 39



А что значит энтропия текста ?


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Bugrimov
Дата 26.11.2012, 18:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



PM MAIL   Вверх
Dem_max
Дата 27.11.2012, 03:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1780
Регистрация: 12.4.2007

Репутация: 4
Всего: 39



Цитата

разные буквы появляются с разной частотой, поэтому неопределённость появления для некоторых букв меньше, чем для других.

как известно гласных в словах больше, но именно согласные несут информацию в словах. Если из слова убрать все гласные буквы, то это слово мы по прежнему можем понять по согласным буквам.


--------------------
Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte")
PM MAIL   Вверх
Bugrimov
  Дата 27.11.2012, 04:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Есть какие-нибудь соображения по поводу кода
PM MAIL   Вверх
feodorv
Дата 27.11.2012, 07:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  26.11.2012,  19:08 Найти цитируемый пост)
    max_entr = log(total)/log(2);

На вид, должно быть не log(total), а log(256) (ну, или если Вы все знаки препинания свалили в одну кучу, то логарифм меньшего числа, чем 256).

Цитата(Bugrimov @  26.11.2012,  19:08 Найти цитируемый пост)
    printf("\n Избыточ.: %6.3f", max_entr_p/entr_p);

Судя по учебнику, должно быть 
Код

    printf("\n Избыточ.: %6.3f", 1-entr_p/max_entr_p);




--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 27.11.2012, 19:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Цитата

log(256)


Но в тексте файла могут не использоваться все символы (256). Максимальная энтропия не рассчитывается от размера алфавита например текст "aaacccbbms" - размер алфавита 5, т.е. 5 символов, поправьте меня если я ошибаюсь. Как тогда должен выглядеть программный код?
PM MAIL   Вверх
feodorv
Дата 27.11.2012, 22:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  27.11.2012,  20:30 Найти цитируемый пост)
Но в тексте файла могут не использоваться все символы (256).

Могут, но Вы же их учитываете (посмотрите, как формируется total), учитываете даже пробелы, табуляцию, перенос строк, различаете строчные буквы от прописных. 

Потом, если в тексте не встретилась какая-то буква алфавита, то это не значит, что её существование можно проигнорировать (как раз нет, просто она редко встречается). 


Цитата(Bugrimov @  27.11.2012,  20:30 Найти цитируемый пост)
Как тогда должен выглядеть программный код? 

Ограничьте себя английским алфавитом или русским. Не различайте строчные и прописные буквы. Если есть необходимость в учёте знаков препинания - учитывайте. Все остальные символы игнорируйте. Соответственно вместо 256 получится 26/27 или 32/33/34 (если учитывать ё и пунктуацию) символов.



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 27.11.2012, 23:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(Bugrimov @  26.11.2012,  18:08 Найти цитируемый пост)
        else
            entropy();

Рекурсия здесь не нужна абсолютна.

По поводу энтропии. вы ее никогда точно не посчитаете.
Приблизительно её можно оценить с помощью архиватора.
Архиваторы, асимтотично стремятся к некому пределу сжатия.
У кого-то лучше получается, у кого-то хуже.
Со временем появляются новые архиваторы, которые сжимают текст еще лучше.
Но ни один архиватор никогда не сможет сжать текст ниже уровня энтропии.
А вот каков он этот предел... кто ответит?  smile 

PM MAIL   Вверх
Bugrimov
Дата 28.11.2012, 04:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Я пытался добиться следующего:
Открыть любой текстовый файл. Рассчитать его энтропию (регистр не учитывается - строчные и прописные символы одинаковые, все знаки препинания подсчитать как один символ - любой символ), максимальную энтропию и избыточность текста. В коде рассмотрен еще один вариант - для пар символов. Я полагал, что есть определенная формула по расчету энтропии, максимальной энтропии, избыточности. С энтропией и избыточностью вроде разобрался с макс. энтропией вообще ничего не понятно. Есть у кого-нибудь образец кода.
PM MAIL   Вверх
feodorv
Дата 28.11.2012, 07:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  28.11.2012,  05:57 Найти цитируемый пост)
регистр не учитывается - строчные и прописные символы одинаковые

В коде, который Вы привели, регистр учитывается. А так же пробелы, табуляция, перевод строки и прочая.
Судя по заданию, нужно именно ограничиться каким-то языком (русским или английским), плюс пунктуация.

Цитата(Bugrimov @  28.11.2012,  05:57 Найти цитируемый пост)
 Есть у кого-нибудь образец кода. 

А при чём здесь образец кода, когда максимальная энтропия достигается при равных вероятностях для всех букв алфавита?

Код

max_entr = log(m)/log(2);

где m - число букв алфавита (с учётом пунктуации).



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 29.11.2012, 04:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Подскажите пожалуйста как в моем куске кода можно сделать, чтобы регистр не учитывался, знаки препинания (табуляция и пробелы) считались как один символ. 
Число букв алфавита m.
Для большего понимания. Например текст: фффаааяяя qqrrr (6 букв алфавита). Я верно понимаю? Или учитываются все буквы алфавита. Если например текст латинница - все буквы латинского языка, если русский - то русского.

Это сообщение отредактировал(а) Bugrimov - 29.11.2012, 04:46
PM MAIL   Вверх
feodorv
Дата 30.11.2012, 19:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  29.11.2012,  05:42 Найти цитируемый пост)
Или учитываются все буквы алфавита.

Честно говоря, для большей ясности лучше спросить у заказчика)))
Лично я бы тупо ограничился английским алфавитом, завёл бы массив из 27 позиций (26 на буквы, 1 на остальные символы) и сделал бы аналогично Вашему коду, только иначе бы вычислял индекс массива: 
Код
int index, ch;

if( ch >= 'A' && ch <= 'Z' )
  index = ch - 'A';
else if( ch >= 'a' && ch <= 'z' )
  index = ch - 'a';
else
  index = 26;

code[index]++;



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 30.11.2012, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Будут открываться текстовые файлы на русском или английском языке, возможно это предусмотреть как-нибудь в коде.
Цитата(Bugrimov @  29.11.2012,  04:42 Найти цитируемый пост)
Для большего понимания. Например текст: фффаааяяя qqrrr (6 букв алфавита). Я верно понимаю? Или учитываются все буквы алфавита. Если например текст латинница - все буквы латинского языка, если русский - то русского.
 Этот вопрос так же актуален... smile 

PM MAIL   Вверх
feodorv
Дата 30.11.2012, 20:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



А что по этому поводу говорит "заказчик"?


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 30.11.2012, 21:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Заказчик говорит: "составить программу, определяющую энтропию текстового файла. Энтропию необходимо вычислить 2-мя способами, т.е. используя число отдельных символов и используя частоты пар символов. Файл содержит текст на естественном языке (русском или английском, строчные и заглавные символы не отличаются, знаки препинания объединены в один символ). В программе должна быть предусмотрена возможность смены необходимого текстового файла". Нужно найти энтропию и избыточность текста для одиночного символа и частоты пар символов. Вот такая задачка. smile  
PM MAIL   Вверх
feodorv
Дата 30.11.2012, 21:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  30.11.2012,  22:19 Найти цитируемый пост)
Заказчик говорит

Ну, это так задача сформулирована. А уточнить условия у него можно? Особенно по этому вопросу:
Цитата(Bugrimov @  30.11.2012,  21:21 Найти цитируемый пост)
Или учитываются все буквы алфавита.



Цитата(Bugrimov @  30.11.2012,  22:19 Найти цитируемый пост)
на естественном языке (русском или английском

То есть, на каком-то одном? Тогда можно сделать 2а варианта программы - для английского языка и русского отдельно. Можно попробовать сделать гибрид - если встречаются русские буквы, тогда русский текст, если английские - тогда английский, если и те, и другие - тогда смешанный текст...  




--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 1.12.2012, 10:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Смешанный текст...... Т.е. возможны русские и английские буквы в тексте.
PM MAIL   Вверх
feodorv
Дата 2.12.2012, 06:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  1.12.2012,  11:09 Найти цитируемый пост)
Смешанный текст......

Как-то в задании говорится о русском или английском, но не о и русском, и английском одновременно. Мне кажется, лучше всего, всё-таки, уточнить условие задачи.

И если речь идёт именно о естественном языке, то, думаю, нужно учитывать все буквы алфавита, даже которые в тексте не встретились (для больших текстов это маловероятно).

Но если хочется смешанный текст, то стОит сделать гибрид:
  • отдельно считаются английские буквы
  • отдельно считаются русские буквы
  • отдельно считаются знаки препинания (точно к ним относятся все остальные символы?)
Для виндовой кодировки:
Код

int ch;
int rusCode[32], engCode[26], punCode;
int rusTotal, engTotal;

if( ch >= 'A' && ch <= 'Z' )
{
  endCode[ch - 'A']++;
  engTotal++;
}
else if( ch >= 'a' && ch <= 'z' )
{
  engCode[ch - 'a']++;
  engTotal++;
}
else if( ch == 'Ё' || ch == 'ё' )
{
  rusCode['е'-'а']++;
  rusTotal++;
}
else if( ch >= 'А' && ch <= 'Я' )
{
  rusCode[ch-'А']++;
  rusTotal++;
}
else if( ch >= 'а' && ch <= 'я' )
{
  rusCode[ch-'а']++;
  rusTotal++;
}
else
  punCode++;

И в конце уже смотреть, русский, английский или смешанный тип:
Код

if( engTotal == 0 && rusTotal == 0 )
{
   // не текст
}
else if( engTotal == 0 )
{
  // чиста русский текст
}
else if( rusTotal == 0 )
{
  // чиста английский текст
}
else 
{
  // смешанный текст
}


Правда, в таком случае придётся немного по-разному считать частоту парных символов...


Более грамотно, конечно, воспользоваться функциями setlocale, isalpha, tolower. В этом случае энтропию для одиночных символов и для парных символов можно считать за один проход файла (за одно чтение):
Код

int code[256] = { 0 }, code_p[256*256] = { 0 };
int rusTotal, engTotal, punTotal;
int ch, lastch = 0;

setlocale( LC_ALL, "Russian");
...

  if( isalpha(ch) )
  {
    ch = tolower(ch);
    if( ch == 'ё' ) ch = 'е';
    code[ch]++;
    if( ch >= 0x80 ) rusTotal++; else engTotal++;
    if( lastch != 0 ) code_p[ 256*lastch + ch ]++;
  }
  else 
  {
    ch = ' '; // всё остальное
    punTotal++;
    if( lastch != 0 ) code_p[ 256*lastch + ch ]++;
  }
  lastch = ch;

...
if( engTotal == 0 && rusTotal == 0 )
  ...
  ...
  ...



Ну и количество букв в алфавите будет зависеть от того, английский, русский или смешанный этот текст...


Это сообщение отредактировал(а) feodorv - 2.12.2012, 07:00


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 2.12.2012, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Цитата(feodorv @  2.12.2012,  06:53 Найти цитируемый пост)
Ну и количество букв в алфавите будет зависеть от того, английский, русский или смешанный этот текст...

Как будет выглядеть подсчет количества букв в алфавите например если текст на русском, на английском и смешанный. Как это можно вставить в мой программный код. Еще вопрос, как все таки выглядит тогда подсчет максимальной энтропии.
Цитата(feodorv @  2.12.2012,  06:53 Найти цитируемый пост)
отдельно считаются знаки препинания (точно к ним относятся все остальные символы?)
 Да, именно. smile 

PM MAIL   Вверх
feodorv
Дата 2.12.2012, 21:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  2.12.2012,  21:27 Найти цитируемый пост)
Как будет выглядеть подсчет количества букв в алфавите например если текст на русском, на английском и смешанный.

 smile Ну так число букв для каждого языка ведь известно? Достаточно сложить:
Код

int m;

if( engTotal == 0 && rusTotal == 0 )
{
   m = 1;
}
else if( engTotal == 0 )
{
   m = 32+1;
}
else if( rusTotal == 0 )
{
   m = 26+1;
}
else 
{
  m = 26+32+1;
}


Цитата(Bugrimov @  2.12.2012,  21:27 Найти цитируемый пост)
как все таки выглядит тогда подсчет максимальной энтропии.

Тупо по определению:
Цитата(feodorv @  28.11.2012,  08:42 Найти цитируемый пост)
max_entr = log(m)/log(2);




--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 2.12.2012, 21:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Я имел в виду в моем коде, он получается кардинально не верен smile Последний пример понятен. Это проверка на присутствие в тексте русских или латинских символов (так же их отсутствие или "гибрид"). Просто на вашем примере 
Код

int code[256] = { 0 }, code_p[256*256] = { 0 };
int rusTotal, engTotal, punTotal;
int ch, lastch = 0;
setlocale( LC_ALL, "Russian");
...
  if( isalpha(ch) )
  {
    ch = tolower(ch);
    if( ch == 'ё' ) ch = 'е';
    code[ch]++;
    if( ch >= 0x80 ) rusTotal++; else engTotal++;
    if( lastch != 0 ) code_p[ 256*lastch + ch ]++;
  }
  else 
  {
    ch = ' '; // всё остальное
    punTotal++;
    if( lastch != 0 ) code_p[ 256*lastch + ch ]++;
  }
  lastch = ch;
...
if( engTotal == 0 && rusTotal == 0 )
  ...
  ...
  ...


не совсем понятно - расчеты для символа и для пары символов (поясните пожалуйста некоторые строки). И как это будет вписываться в мой код? Это на сколько я понял идет проверка и подсчет символов перед расчетами энтропии.
PM MAIL   Вверх
feodorv
Дата 3.12.2012, 00:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  2.12.2012,  22:33 Найти цитируемый пост)
поясните пожалуйста некоторые строки

Какие именно? Просто вместо 
Цитата(Bugrimov @  26.11.2012,  19:08 Найти цитируемый пост)
    while((ch = fgetc(pf)) != EOF)
    {
        if(strchr(".,:;?!-\'\"", ch))    // Если в тексте встречаются знаки препинания
            ch = '.';                    // объединить в один символ '.'
        code[ch]++;    // Считает число символов каждого типа
        
    }

пишется, например, такое:
Код

int lastch = EOF; // EOF - лучше чем 0

...

while((ch = fgetc(pf)) != EOF)
{
  if( isalpha(ch) )
  {
    ch = tolower(ch);
    if( ch == 'ё' ) ch = 'е';
    code[ch]++;
    if( ch >= 0x80 ) rusTotal++; else engTotal++;
    if( lastch != EOF ) code_p[ 256*lastch + ch ]++;
  }
  else 
  {
    ch = '.'; // всё остальное
    code[ch]++;
    punTotal++;
    if( lastch != EOF ) code_p[ 256*lastch + ch ]++;
  }
  lastch = ch;
}
fclose(pf);

if( engTotal == 0 && rusTotal == 0 )
   m = 26 + 1; // будем считать, что это был английский текст...
else if( engTotal == 0 )
   m = 32+1;
else if( rusTotal == 0 )
   m = 26+1;
else 
   m = 26+32+1;

total = rusTotal + engTotal + punTotal;

for( i = 0; i < 256; i++)
   if( code[i] )
     entr -= (float) code[i] * log( (float) code[i] / (float) total);
entr /= log(2)*total;
max_entr = log(m)/log(2);

....

При этом одновременно считается и code и code_p (за один проход файла). Чтобы isalpha и tolower отрабатывали на русских буквах, нужно установить нужную локаль.

Ну а затем считается энтропия как у Вас в первоначальном коде.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Bugrimov
Дата 3.12.2012, 05:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Еще вопрос! А для пары символов энтропия и максимальная энтропия у меня верно определяются? Мне сказали, что я ошибаюсь. Или все верно достаточно подставить подсчитанные значения. И еще верно, что для пары символов нужно использовать log(2.7) вместо log(2)
PM MAIL   Вверх
feodorv
Дата 3.12.2012, 10:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  3.12.2012,  06:14 Найти цитируемый пост)
А для пары символов энтропия и максимальная энтропия у меня верно определяются? Мне сказали, что я ошибаюсь.

Правильно сказали)))

Должна быть двойная сумма 
Код

ent2 = - sum(i:total) sum(j:total) p(ij) * log( p(ij) )

где p(ij) - вероятность появления j-го символа после i-го (то есть пары символов ij).
Условная энтропия

Соответственно, максимальная условная энтропия достигается при равенстве всех вероятностей (то есть при условии независимости следования символов друг за другом и одинаковой частоты появления символов алфавита). Высчитывается аналогично первому случаю, надеюсь, Вы легко её определите smile

Добавлено @ 10:28
Цитата(Bugrimov @  3.12.2012,  06:14 Найти цитируемый пост)
И еще верно, что для пары символов нужно использовать log(2.7) вместо log(2) 

Если в первом случае используется логарифм по основанию 2, то и во втором тоже должно использоваться это же основание. Не вижу оснований для смены основания)))

В формуле Шенона используется некая константа, которая является, на самом деле, калибровочной константой. Например, можно так откалибровать понятие энтропии, что максимальная энтропия примет значение 1. Смена основания логарифма ведёт просто-напросто к изменению этой константы, поэтому 
Цитата
выбор основания системы логарифмов несуществен


Интересно, что при выборе единичного значения для калибровочной константы 
Цитата
в случае основания 2 единицу измерения энтропии называют «бит», в случае основания 10 — «дит», в случае основания e=2.718281828459045... — «нат». 


Откуда взялась в Ваших записях константа 2.7, мне сказать трудно, тем более она очень близка к значению числа e. Но единицы измерения энтропии должны быть одинаковы, что в первом случае, что во втором. В битах - значит, в битах)))

Это сообщение отредактировал(а) feodorv - 3.12.2012, 10:30


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
baldina
Дата 3.12.2012, 10:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(volatile @  27.11.2012,  23:37 Найти цитируемый пост)
Приблизительно её можно оценить с помощью архиватора.
Архиваторы, асимтотично стремятся к некому пределу сжатия.

архиваторы используют адаптивное сжатие. если частоты известны заранее, можно получить код с минимальной избыточностью.

Добавлено через 5 минут и 51 секунду
Цитата

Степень энтропии источника данных означает среднее число битов на элемент данных, требуемых для её зашифровки без потери информации, при оптимальном кодировании.

так что после сжатия оптимальным образом (в два прохода, с построением таблицы частот), энтропия вычисляется просто.
PM MAIL   Вверх
Bugrimov
Дата 3.12.2012, 17:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Цитата(feodorv @  3.12.2012,  10:16 Найти цитируемый пост)
ent2 = - sum(i:total) sum(j:total) p(ij) * log( p(ij) )

Не совсем понятно как происходит вычисление sum(i:total), sum(j:total) и p(ij). Можете продемонстрировать в коде. 

PM MAIL   Вверх
baldina
Дата 3.12.2012, 18:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 15
Всего: 101



Цитата(Bugrimov @  3.12.2012,  17:40 Найти цитируемый пост)
sum(i:total), sum(j:total)

это не вычисляется, это символизирует двойную сумму. два вложенных цикла.  smile 
PM MAIL   Вверх
Bugrimov
Дата 3.12.2012, 19:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Значит я не верно понял, можете показать как эти суммы будут выглядеть в коде.
PM MAIL   Вверх
feodorv
Дата 3.12.2012, 22:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  3.12.2012,  20:56 Найти цитируемый пост)
можете показать как эти суммы будут выглядеть в коде. 

user posted image


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
volatile
Дата 4.12.2012, 00:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2107
Регистрация: 7.1.2011

Репутация: 16
Всего: 85



Цитата(baldina @  3.12.2012,  10:41 Найти цитируемый пост)
архиваторы используют адаптивное сжатие. 

Да какое бы сжатие они не использовали, они не могут нарушить закон:
"Информация - не сжимаема" 
это такой-же основополагающий закон, как и закон сохранения энергии.

Цитата(baldina @  3.12.2012,  10:41 Найти цитируемый пост)
если частоты известны заранее,

да в том то и дело, что частоты не известны. И получение этих частот выходит далеко за рамки этой темы.

Ту энтропию что вы посчитаете, это не настоящая энтропия. Эта некая абстрактная, отвлеченная от реальности энтропия.
Впрочем, это видимо и нужно по заданию.
так что считайте на здоровье.
 smile 


PM MAIL   Вверх
Bugrimov
Дата 4.12.2012, 05:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 24
Регистрация: 8.11.2012

Репутация: нет
Всего: нет



Формулу эту я встречал, но практической реализации ее не видел. 
Код

total = 0;
    prev = fgetc(pf);
    while((ch = fgetc(pf)) != EOF)
    {
        if (strchr(".,:!?'\"", ch))
            ch = '.';
        code_p[prev*256 + ch]++;
        prev = ch;
    }

    for(i = 0; i < 256*256; i++)
        total += code_p[i];
    
    for(i = 0; i < 256*256; i++)
        if(code_p[i])
        entr_p -= code_p[i]*log(((float)code_p[i])/total);
    entr_p /= log(2)*total*2;
    max_entr_p = log(total)/log(2.7);
    printf("\n Энтр. для пар символов: %6.3f Макс. энтропия: %6.3f Избыточ.: %6.3f", entr_p, max_entr_p, max_entr_p/entr_p);


Вот все что есть по этому поводу. Хотя уже понятно, что log(2), вместо log(2.7).
Можете что-нибудь подсказать на уже имеющемся программном коде. 

Код

void entropy(void)
{
    FILE    *pf = NULL;
    char    file[SIZE];
    long    ch, i, prev, total = 0;
    int        code[256] = {0}, code_p[256*256] = {0};
    float    entr = 0, entr_p = 0, max_entr, max_entr_p;
    int        m, rusTotal = 0, engTotal = 0, punTotal = 0;
    int        lastch = EOF; 

    

    Messages(2);
    printf("\n\n");
    system("DIR /a:-d");
    
    
    printf("\n Введите имя файла: ");
    gets(file);
    pf = fopen(file, "rt");    // Открытие файла для чтения
    if(pf == NULL)
    {
        Messages(3);
        printf("\n Выбрать файл (ENTER) / Выход в меню (ESC)");
        if(getch() == 27)
            menu();
        else
            entropy();
    }
    
    while((ch = fgetc(pf)) != EOF)
    {
  
        if(isalpha(ch))
        {
            ch = tolower(ch);
            if(ch == 'ё') ch = 'е';
                code[ch]++;
    
            if(ch >= 0x80) 
                rusTotal++; 
            else 
                engTotal++;
            if(lastch != EOF) 
                code_p[256*lastch + ch]++;
        }
        else 
        {
            ch = '.'; // всё остальное
            code[ch]++;
            punTotal++;
            if(lastch != EOF) 
                code_p[256*lastch + ch]++;
        }
        lastch = ch;
    }

    fclose(pf);
    
    if(engTotal == 0 && rusTotal == 0)
         m = 26 + 1; // будем считать, что это был английский текст...
    else if(engTotal == 0)
        m = 32 + 1;
    else if(rusTotal == 0)
        m = 26 + 1;
    else 
        m = 26 + 32 + 1;
    total = rusTotal + engTotal + punTotal;

    for(i = 0; i < 256; i++)
    if(code[i])
        entr -= (float)code[i] * log((float)code[i] / (float)total);
    entr /= log(2)*total;
    max_entr = log(m)/log(2);
printf("\n Энтр. для символа: %6.3f Макс. энтропия: %6.3f", entr, max_entr);
    printf("\n Избыточ.: %6.3f", 1-entr/max_entr);
fclose(pf);
    getch();
}


PM MAIL   Вверх
feodorv
Дата 4.12.2012, 06:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(Bugrimov @  4.12.2012,  06:16 Найти цитируемый пост)
Можете что-нибудь подсказать на уже имеющемся программном коде. 

Ну, просто возникло устойчивое чувство, что я вместо Вас делаю Вашу лабораторную работу  smile 

Давайте подсчитаем вероятность встречи в тексте пары символов AB:
Код

p(AB) = {вероятность символа A, если за ним следует ещё символ} * {вероятность того, что после A в тексте встретится B} = p(A) * p(B|A)


Правда, здесь есть небольшая тонкость, связанная с тем, что у последней в тексте буквы пары нет (за ней не следует никакая другая), поэтому в при учёте вероятностей букв последнюю букву в тексте мы учитывать не будем, хотя пару символов, в которую она входит, учтём. Иначе не сойдутся вероятности))) Этот факт выражается также в том, что для текста из total символов число пар символов только (total-1). Из-за этого сразу после первого этапа в программе сделаем небольшую коррекцию:
Код
.....
getch();

if( total < 2 )
{
  // дальше считать смысла нет, энтропия 0
  printf("\n Энтр. для пары символов: 0");
  return 0;
}
total--; // число пар в тексте
code[lastch]--; // последний символ в вероятностях для пар не учитывается


Подготовившись таким образом, мы можем вычислить p(A):
Код

p(A) = {число всех букв A в тексте, начинающих пару символов} / {число всех букв в тексте, начинающих пару символов} = code[A] / total

как и для первого этапа, но с учётом специфики пар, то есть ранее оговоренной тонкости.

Подсчитаем вероятность буквы B, если перед ней стояла буква A:
Код

p(B|A) = {число пар AB} / {общее число пар, где первой является A}

Если как следует подумать, то придёт понимание, что {общее число пар, где первой является A} есть просто число букв A в тексте (с учётом ранее оговоренной тонкости) (хотя в коде, если не лень и нет веры, можно подсчитать в цикле))) То есть:
Код

p(B|A) = {число пар AB} / {число всех букв A в тексте} = code_p[A*256+B] / code[A]


Итого:
Код

p(AB) = ({число всех букв A в тексте, начинающих пару символов} / {число всех букв в тексте, начинающих пару символов}) * 
            ({число пар AB} / {число всех букв A в тексте, начинающих пару символов}) = 
    {число пар AB} / {число всех букв в тексте, начинающих пару символов}

А с учётом того, что {число всех букв в тексте, начинающих пару символов} есть просто-напросто {общее число пар символов в тексте}, получаем невероятный, умопомрачительный результат
Код

p(AB) = (число пар AB) / (общее число пар символов в тексте) = code_p[A*256+B] / total

 smile 

Осталось всё это подставить в 
Цитата(feodorv @  3.12.2012,  11:16 Найти цитируемый пост)
ent2 = - sum(i:total) sum(j:total) p(ij) * log( p(ij) )

и получить готовый результат.


Мне безумно хочется получить от Вас значение для максимальной энтропии пар. Оно интересно и весьма поучительно.

Добавлено через 4 минуты и 10 секунд
У Вас в коде файл два раза закрывается:
Цитата(Bugrimov @  4.12.2012,  06:16 Найти цитируемый пост)
fclose(pf);
...
fclose(pf);




--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 6.12.2012, 09:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 12
Всего: 45



Цитата(feodorv @  4.12.2012,  07:16 Найти цитируемый пост)
Мне безумно хочется получить от Вас значение для максимальной энтропии пар. Оно интересно и весьма поучительно.

Чувствую, даже попыток вычислить искомое не будет  smile 
А жаль. Всё вычисляется элементарно...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Страницы: (3) [Все] 1 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1966 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.