Сколько страниц книги необходимо прочитать, чтобы узнать 90% всех слов?

 

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

Преподаватель английского языка автора оригинальной статьи утверждал, что прочитав 20 страниц любой книги можно узнать 90% всех слов произведения и далее читать книгу будет значительно проще.

В этой статье я хочу проверить аналогичное утверждение для русского языка: сколько страниц необходимо прочитать, чтобы узнать 90% книги.

Спойлер: прочитав 20 страниц книги вы практически наверняка не узнаете 90% всех слов. Далее будут графики, таблицы и немного кода.

Для анализа требуется стандартный для подобных задач набор бибилиотек Python: matplotlib, seaborn, pandas, numpy, stop_words и pymorphy2.

Что анализировать?

В качестве “подопытных” взял различные книги:

  1. Объёмную классику (Л. Толстой “Война и мир. Книга 1.”)
  2. Нехудожественная литература (С. Галёнкин “Маркетинг игр”)
  3. Случайную бесплатную современную книгу на litres (С. Тармашев “Закат Тьмы”)
  4. Книгу, переведённую на русский (Ш. Стрейд “Дикая”)
  5. Небольшой рассказ Антона Чехова (А. Чехов “Человек в футляре”)

Что хотим узнать?

  1. Как быстро появляются новые слова в книге?
  2. Какой процент книги можно прочитать зная слова, которые были встречены к некоторой странице?

На графиках к книгам зелёный линия даёт ответ на первый вопрос: какой процент всех уникальных слов в книге были встречены к текущей странице. Синяя линия на графике отвечает на второй вопрос: какой объём от всей книги написан при помощи слов встреченных к текущей странице.

from matplotlib import pyplot

import seaborn as sns
from collections import Counter
from itertools import chain

import pandas as pd
import numpy as np 

import re

import pymorphy2
from stop_words import get_stop_words

page_size = 200

Подготовка данных

Для подготовки книг в виде текстовых файлов для анализа используем pymorhy2 для лемматизации и stop_words для удаления стоп-слов:

morph = pymorphy2.MorphAnalyzer()
sw = get_stop_words('ru')
pyplot.rcParams["figure.figsize"] = (10,5)

def lemmatize(text):
    """Функция удаляет из текста стоп-слова, 
    лемматизирует текст и берёт для каждого начальную форму.
    
    # Arguments
        text: исходный текст.
    
    # Returns
        fixed_text: список лемматизированых не-стоп-слов.
    """
    letters_only = re.sub('[^a-zA-Zа-яА-Я]', ' ', text)
    fixed_text = []
    letters_only = list(filter(None, letters_only.split(' ')))
    for word in letters_only:
        # Берём первое совпадения только для простоты.
        nf = morph.parse(word)[0].normal_form
        if nf in sw:
            continue
        
        fixed_text.append(nf)
        
    return fixed_text


def txt_to_pages(filename, encoding='utf8'):
    """Функция преобразует текст из текстового файла в "страницы"
    
    # Arguments
        filename: путь до текстового файла.
        encoding: кодировка исходного файла.
    
    # Returns
        book_pages: список списков лемматизированных слов ("страниц")    
    """
    book_text = open(filename, mode='r', encoding=encoding).read()
    book_text = lemmatize(book_text)
    
    book_pages = []
    for i in range(len(book_text) // page_size + 1):
        book_pages.append(book_text[i * page_size : i * page_size + page_size])
    
    return book_pages

Обработка книг

Следующие две функции содержат всю логику по анализу книг:
* вычисляют “сложность” книги – сколько страниц текста необходимо прочитать, чтобы узнать 90% всех уникальных слов,
* вычисляют основные метрики книги – какой процент книги возможно прочитать зная слова встреченные к текущей странице, какой процент уникальных слов уже встречен.

def calculate_hardness(coverage, percent = 0.9):
    """ Функция вычисляет "сложность" книги - 
            насколько большую часть книги необходимо прочтитать, 
            чтобы узнать percent всех используемых слов.
    
    # Arguments
        coverage: массив с информацией какой процент книги
            можем прочитать, зная слова полученные к i-ой странице.
        percent: сколько слов хотим знать.
    
    # Returns
        i: номер страницы.
        hardness: какой процент книги будет прочитан к этой странице.
    """
    for i in range(len(coverage)):
        if coverage[i] > percent:
            break
    
    hardness = (100 * i) / float(len(coverage))
    return i, hardness


def percentage(values, title):
    """ Функция вычисляет всё.
    
    # Arguments
        values: список "страниц" книги.
    """
    all_words = list(chain.from_iterable(values))
    result = {}
    current_text = []
    page_counter = 0
    file_name = title.lower().replace(' ', '_').replace('\'','') + '.png'
    
    counter = Counter()
    # "Счётчик" всех слов книги. 
    # Используется для подсчёта процента книги, 
    # который можно прочитать зная некоторый объём слов. 
    occurances = Counter(all_words)
    
    # i-ый элемент: какой процент книги можем прочитать зная слова полученные к i-ой странице.
    coverage = []
    
    # i-ый элемент: какой процент слов используемых в книге знаем к i-ой странице.
    uniqueness = []
    
    # i-ый элемент: сколько уникальных слов используемых в книге знаем к i-ой странице.
    total_unique_words_count = []
    
    total = float(len(all_words))
    total_unique = float(len(occurances.keys()))
    
    print('page\ttotal\tpercent of all\tpercent of book\tuniqueness')
    for page_text in values:
        # Обновим счётчик уникальных слов словами с новой страницы.
        counter.update(page_text)
        
        # Посчитаем, сколько вообще раз встречаются слова 
        # которые уже были встречены к текущей странице.
        occured_words_count = sum((occurances[w] for w in counter.keys()))

        # Какой процент от всей книги составляют слова, 
        # которые уже встретили к текущей странице.
        _coverage = occured_words_count / total
        coverage.append(_coverage)
        
        # Какой процент от всех уникальных слов встретили к текущей странице.
        _uniqueness = len(counter.keys()) / total_unique
        uniqueness.append(_uniqueness)
        
        # Какой процент от книги прошли к текущей странице.
        percent_book = page_counter / len(values)
        
        # Сколько уникальных слов будет известно к текущей странице.
        total_unique_words_count.append(len(counter.keys()))
        
        print('{0}\t{1}\t{2:2f}\t{3:2f}\t{4:2f}'.format(page_counter, 
        len(counter.keys()), 
        _coverage, 
        percent_book, 
        _uniqueness))
        
        result[page_counter] = { 
            'page': page_counter,
            'unique_words': _uniqueness, 
            'all_words': _coverage
        }
        page_counter += 1
    
    percent_df = pd.DataFrame.from_dict(result,orient='index')
    
    page, hardness = calculate_hardness(coverage)
    
    print('Всего страниц: {0}'.format(len(values)))
    print('Всего слов: {}'.format(len(all_words)))
    print('Всего уникальных слов: {}'.format(len(occurances.keys())))
    print('Прочитав {0} страниц книги ({1:.2f}% всей книги) вы узнаете {2} уникальных слов.\n
           К этой странице будут встречены 90% всех слов книги и {3:.2f}% уникальных.'.format(
          page,
          hardness,
          total_unique_words_count[page],
          uniqueness[page] * 100))
    
    pyplot.plot(percent_df['unique_words'], color='g', label='Уникальные слова')
    pyplot.plot(percent_df['all_words'], color='b', label='Все слова')
    pyplot.legend(loc=4)
    pyplot.title(title)
    pyplot.xlabel('Страница')
    pyplot.ylabel('Покрытие (%)')
    pyplot.show()

Результаты

Л. Толстой “Война и мир. Книга 1”

war_and_peace_pages = txt_to_pages('./books/Tolstoyi_L._Voyinaimir1._Voyina_I_Mir_Kniga_1.txt', 
    encoding='1251')
percentage(war_and_peace_pages, 'Война и мир')
page    total   percent of all  percent of book uniqueness
0   141 0.087556    0.000000    0.009748
1   286 0.158995    0.001541    0.019773
2   404 0.201158    0.003082    0.027931
3   521 0.238750    0.004622    0.036020
4   630 0.271941    0.006163    0.043556
5   732 0.306381    0.007704    0.050608
6   832 0.341545    0.009245    0.057522
7   923 0.360869    0.010786    0.063814
8   1007    0.387377    0.012327    0.069621
9   1096    0.404189    0.013867    0.075774
10  1179    0.417508    0.015408    0.081513
...
639 14463   0.999992    0.984592    0.999931
640 14463   0.999992    0.986133    0.999931
641 14463   0.999992    0.987673    0.999931
642 14463   0.999992    0.989214    0.999931
643 14463   0.999992    0.990755    0.999931
644 14463   0.999992    0.992296    0.999931
645 14463   0.999992    0.993837    0.999931
646 14463   0.999992    0.995378    0.999931
647 14463   0.999992    0.996918    0.999931
648 14464   1.000000    0.998459    1.000000
Всего страниц: 649
Всего слов: 129734
Всего уникальных слов: 14464
Прочитав 197 страниц книги (30.35% всей книги) вы узнаете 8171 уникальных слов.
К этой стрнице будут встречены 90% всех слов книги и 56.49% уникальных.

war_and_peace.png

Книга “Война и мир. Книга 1.” Льва Тостого содержит 649 страниц без учёта стоп-слов. На этих страницах можно встретить 14464 уникальных слов, каждое из которых, в среднем, встречается 9 раз. К 197-ой странице будет встречено 8171 уникальное слово (56.49% от всех уникальных слов). При помощи этих слов написано 90% всей книги.

С. Галёнкин “Маркетинг игр”

game_marketing_pages = txt_to_pages('./books/Games-Marketing-by-Galyonkin-v1.txt')
percentage(game_marketing_pages, 'Маркетинг игр')
page    total   percent of all  percent of book uniqueness
0   145 0.250361    0.000000    0.044602
1   274 0.334958    0.017857    0.084282
2   392 0.386150    0.035714    0.120578
3   514 0.434543    0.053571    0.158105
4   614 0.481040    0.071429    0.188865
5   715 0.511015    0.089286    0.219932
6   798 0.545323    0.107143    0.245463
7   879 0.581347    0.125000    0.270378
8   955 0.617822    0.142857    0.293756
9   1042    0.646443    0.160714    0.320517
10  1108    0.668021    0.178571    0.340818
...
46  2938    0.964608    0.821429    0.903722
47  2973    0.968039    0.839286    0.914488
48  3015    0.972553    0.857143    0.927407
49  3057    0.979415    0.875000    0.940326
50  3094    0.983026    0.892857    0.951707
51  3131    0.987450    0.910714    0.963088
52  3167    0.990791    0.928571    0.974162
53  3187    0.992597    0.946429    0.980314
54  3242    0.999097    0.964286    0.997232
55  3251    1.000000    0.982143    1.000000
Всего страниц: 56
Всего слов: 11076
Всего уникальных слов: 3251
Прочитав 34 страниц книги (60.71% всей книги) вы узнаете 2485 уникальных слов.
К этой стрнице будут встречены 90% всех слов книги и 76.44% уникальных.

game_marketing.png

“Маркетинг игр” Сергея Галёнкина менее объёмная и содержит лишь 56 страниц текста. Уникальных слов в книге 3251. Для того, чтобы иметь возможность прочитать 90% книги необходимо знать 2485 уникальных слов (76.44% всех уникальных слов). Этого можно достичь к 34 странице.

С. Тармашев “Закат Тьмы”

zakat_tmyi = txt_to_pages('./books/Tarmashev_S._Tma3._Zakat_Tmyi.txt',
    encoding='1251')
percentage(zakat_tmyi, 'Закат тьмы')
page    total   percent of all  percent of book uniqueness
0   132 0.060600    0.000000    0.012445
1   251 0.073714    0.002611    0.023664
2   363 0.076843    0.005222    0.034223
3   446 0.079892    0.007833    0.042048
4   535 0.082471    0.010444    0.050438
5   621 0.084290    0.013055    0.058546
6   704 0.085690    0.015666    0.066371
7   779 0.086842    0.018277    0.073442
8   851 0.089970    0.020888    0.080230
9   951 0.123516    0.023499    0.089658
10  1097    0.193396    0.026110    0.103422
...
373 10482   0.998063    0.973890    0.988215
374 10502   0.998338    0.976501    0.990101
375 10522   0.998626    0.979112    0.991986
376 10541   0.998940    0.981723    0.993778
377 10560   0.999346    0.984334    0.995569
378 10578   0.999594    0.986945    0.997266
379 10586   0.999699    0.989556    0.998020
380 10598   0.999856    0.992167    0.999152
381 10607   1.000000    0.994778    1.000000
382 10607   1.000000    0.997389    1.000000
Всего страниц: 383
Всего слов: 76403
Всего уникальных слов: 10607
Прочитав 140 страниц книги (36.55% всей книги) вы узнаете 6585 уникальных слов.
К этой стрнице будут встречены 90% всех слов книги и 62.08% уникальных.

sunset_of_the_darkness.png

Книгу Тармашева “Закат Тьмы” решил взять как образец современной литературы (и потому, что она была бесплатной на litres). Книга среднего объёма – 383 страницы без стоп-слов. Уникальных слов 10607 и зная 6585 (можно встретить прочитав 140 страниц или 36.55% всей книги) можно прочитать 90% всей книги.

Ш. Стрэйд “Дикая”

dikaya_df = txt_to_pages('./books/Stryeyid_Sh._Proekttruesto._Dikaya_Opasnoe_Puteshestv.txt', 
    encoding='1251')
percentage(dikaya_df, 'Дикая')
page    total   percent of all  percent of book uniqueness
0   156 0.083797    0.000000    0.014677
1   281 0.130858    0.003247    0.026437
2   421 0.157755    0.006494    0.039609
3   568 0.218298    0.009740    0.053439
4   711 0.269051    0.012987    0.066892
5   839 0.318194    0.016234    0.078935
6   948 0.352604    0.019481    0.089190
7   1052    0.372508    0.022727    0.098975
8   1158    0.407032    0.025974    0.108947
9   1258    0.430774    0.029221    0.118355
10  1342    0.448255    0.032468    0.126258
...
298 10423   0.996292    0.967532    0.980619
299 10430   0.996422    0.970779    0.981278
300 10456   0.996861    0.974026    0.983724
301 10469   0.997122    0.977273    0.984947
302 10484   0.997382    0.980519    0.986358
303 10515   0.997967    0.983766    0.989275
304 10603   0.999528    0.987013    0.997554
305 10629   1.000000    0.990260    1.000000
306 10629   1.000000    0.993506    1.000000
307 10629   1.000000    0.996753    1.000000
Всего страниц: 308
Всего слов: 61494
Всего уникальных слов: 10629
Прочитав 134 страниц книги (43.51% всей книги) вы узнаете 6997 уникальных слов.
К этой стрнице будут встречены 90% всех слов книги и 65.83% уникальных.

wild.png

Ещё одна книга среднего размера – перевод книги Шерил Стрэйд “Дикая”. В книге 308 страниц со 10629 уникальными словами. Для того, чтобы прочитать 90% книги необходимо знать не менее 6997 уникальных слов. Этого можно добиться прочитав 134 первые страницы (43.51% всей книги).

А. Чехов “Человек в футляре”

man_in_the_case = txt_to_pages('./books/Chehov_A._Man_in_the_case.txt')
percentage(man_in_the_case, 'Человек в футляре')
page    total   percent of all  percent of book uniqueness
0   169 0.266868    0.000000    0.153358
1   307 0.402820    0.100000    0.278584
2   426 0.507049    0.200000    0.386570
3   549 0.628902    0.300000    0.498185
4   652 0.717019    0.400000    0.591652
5   751 0.779960    0.500000    0.681488
6   858 0.854985    0.600000    0.778584
7   934 0.903323    0.700000    0.847550
8   1022    0.954683    0.800000    0.927405
9   1102    1.000000    0.900000    1.000000
Всего страниц: 10
Всего слов: 1986
Всего уникальных слов: 1102
Прочитав 7 страниц книги (70.00% всей книги) вы узнаете 934 уникальных слов.
К этой стрнице будут встречены 90% всех слов книги и 84.75% уникальных.

man_in_the_case.png

Последней книгой был короткий (всего 10 страниц) рассказ Антона Чехова “Человек в футляре”. Уникальных слов в книге немного – 1986. 90% книги написаны с использованием 934 уникальных слов (84.75% от всех уникальных слов), которые будете знать прочитав 7 страниц (но в это случае проще дочитать книгу, чем заниматься подобной ерундой, как подсчёт сложности книги).

Выводы

Во всех проанализированных книгах новые слова встречаются в течение всей книги (зелёная линия на графиках). Однако, если обратить внимание на синюю линию, то заметно, что б_о_льшую часть встречаемых слов в книге можно начать “понимать” довольно рано.

Возможно, это совпадение, но графики для художественной литературы (“Война и мир”, “Дикая”, “Закат Тьмы”) похожи. В это же время графики для книги “Маркетинг игр” идут значительно ближе друг к другу, т.е. книга “сложнее”.

Особняком стоит книга “Человек в футляре” Антона Чехова: она очень короткая и для того, чтобы встретить 90% уникальных слов потребуется прочитать всю книгу (см. таблицу).

На этом на сегодня всё.

 

Advertisements