Анализ текстовых данных с помощью массивов строк

Автор
avatar-daryadarya
Notebook

Анализ текстовых данных со строковыми массивами

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

Импорт текстового файла в массив строк

Прочитайте текст из «Сонет» Шекспира с помощью функции read(). Она возвращает текст в виде вектора из 100266 символов.

In [ ]:
sonnets = read("/user/Отсортированное/Base_demo/AnalizeTextDataExample/sonnets.txt", String)
sonnets[1:35]
Out[0]:
"THE SONNETS\n\nby William Shakespeare"

Преобразуйте текст в строку с помощью string функции. Затем разделите его на строки с помощью split(). sonnets становится массивом строк размером 2625 на 1, где каждая строка содержит одну строку из стихотворений. Отобразите первые пять строк sonnets.

In [ ]:
sonnets = string(sonnets)
sonnets = split(sonnets, "\n")
sonnets[1:5]
Out[0]:
5-element Vector{SubString{String}}:
 "THE SONNETS"
 ""
 "by William Shakespeare"
 ""
 ""

Строковый массив

Чтобы подсчитать частоту слов в sonnets, сначала очистите его, удалив пустые строки и знаки препинания. Затем преобразуйте его в массив строк, содержащий отдельные слова в качестве элементов.

Удалите строки с нулевым количеством символов ("") из массива строк. Сравните каждый элемент sonnets с "", пустой строкой. Вы можете создавать строки, в том числе пустые, с помощью двойных кавычек. TF — это логический вектор, который содержит значение true везде, где sonnets содержит строку с нулевым количеством символов. Индексируйте sonnets с помощью TF и удалите все строки с нулевым количеством символов.

In [ ]:
TF = sonnets .== ""
sonnets = sonnets[.!TF]
sonnets[1:10]
Out[0]:
10-element Vector{SubString{String}}:
 "THE SONNETS"
 "by William Shakespeare"
 "  I"
 "  From fairest creatures we desire increase,"
 "  That thereby beauty's rose might never die,"
 "  But as the riper should by time decease,"
 "  His tender heir might bear his memory:"
 "  But thou, contracted to thine own bright eyes,"
 "  Feed'st thy light's flame with self-substantial fuel,"
 "  Making a famine where abundance lies,"

Замените некоторые знаки препинания пробелами. Например, замените точки, запятые и точки с запятой. Сохраните апострофы, потому что они могут быть частью некоторых слов в сонетах, например light's.

In [ ]:
p = ['.','?','!',',',';',':'];
In [ ]:
sonnets = replace.(sonnets[:],p=>" ")
Out[0]:
2311-element Vector{String}:
 "THE SONNETS"
 "by William Shakespeare"
 "  I"
 "  From fairest creatures we desire increase "
 "  That thereby beauty's rose might never die "
 "  But as the riper should by time decease "
 "  His tender heir might bear his memory "
 "  But thou  contracted to thine own bright eyes "
 "  Feed'st thy light's flame with self-substantial fuel "
 "  Making a famine where abundance lies "
 "  Thy self thy foe  to thy sweet self too cruel "
 "  Thou that art now the world's fresh ornament "
 "  And only herald to the gaudy spring "
 ⋮
 "  Whilst many nymphs that vow'd chaste life to keep"
 "  Came tripping by  but in her maiden hand"
 "  The fairest votary took up that fire"
 "  Which many legions of true hearts had warm'd "
 "  And so the general of hot desire"
 "  Was  sleeping  by a virgin hand disarm'd "
 "  This brand she quenched in a cool well by "
 "  Which from Love's fire took heat perpetual "
 "  Growing a bath and healthful remedy "
 "  For men diseas'd  but I  my mistress' thrall "
 "    Came there for cure and this by that I prove "
 "    Love's fire heats water  water cools not love "

Уберите начальные и завершающие символы пробела из каждого элемента массива sonnets.

In [ ]:
sonnets = strip.(sonnets[:],' ')
sonnets[1:10]
Out[0]:
10-element Vector{SubString{String}}:
 "THE SONNETS"
 "by William Shakespeare"
 "I"
 "From fairest creatures we desire increase"
 "That thereby beauty's rose might never die"
 "But as the riper should by time decease"
 "His tender heir might bear his memory"
 "But thou  contracted to thine own bright eyes"
 "Feed'st thy light's flame with self-substantial fuel"
 "Making a famine where abundance lies"

Разбить sonnets на массив строк, элементами которого являются отдельные слова. Вы можете использовать split() для разделения элементов массива строк по пробелам или по указанным вами разделителям. Однако split() требует, чтобы каждый элемент массива строк был делим на равное количество новых строк. Элементы sonnets имеют разное количество пробелов и, следовательно, не делятся на равное количество строк. Чтобы использовать split() функцию для sonnets, напишите цикл for, который вызывает split() для одному элементу за раз.

Создайте массив строк sonnetWords. Напишите цикл for, который разбивает каждый элемент sonnets. Объедините выходные данные split() с sonnetWords. Каждый элемент sonnetWords — это отдельное слово из sonnets.

In [ ]:
sonnetWords = split(sonnets[1]);
for i = 2:length(sonnets)
    sonnetWords = [sonnetWords ; split(sonnets[i])];
 end

sonnetWords[1:10]
Out[0]:
10-element Vector{SubString{String}}:
 "THE"
 "SONNETS"
 "by"
 "William"
 "Shakespeare"
 "I"
 "From"
 "fairest"
 "creatures"
 "we"

Сортировка массива по частоте

Найдите уникальные слова в sonnetWords. Подсчитайте их и отсортируйте по частоте встречаемости.

Чтобы считать слова, которые отличаются только регистром, одним и тем же словом, преобразуйте sonnetWords в нижний регистр. Например, The и the считаются одним и тем же словом.

Подключите функции StatsBase и Statistics, далее будут использоваться функции из этих библиотек.

In [ ]:
import Pkg; 
Pkg.add("StatsBase")
Pkg.add("Statistics")
In [ ]:
using Statistics, StatsBase

Чтобы сделать слова одного регистра - нижнего, используйте функцию lowercase.

In [ ]:
sonnetWords = lowercase.(sonnetWords)
Out[0]:
17711-element Vector{String}:
 "the"
 "sonnets"
 "by"
 "william"
 "shakespeare"
 "i"
 "from"
 "fairest"
 "creatures"
 "we"
 "desire"
 "increase"
 "that"
 ⋮
 "by"
 "that"
 "i"
 "prove"
 "love's"
 "fire"
 "heats"
 "water"
 "water"
 "cools"
 "not"
 "love"

Найдите уникальные слова с помощью функции unique(). Также здесь применена функция сортировки от меньшего к болшего. Это сделано удобства дальнейшей работы.

In [ ]:
words = sort(unique(sonnetWords))
Out[0]:
3435-element Vector{String}:
 "'"
 "''tis"
 "'amen'"
 "'fair"
 "'fore"
 "'gainst"
 "'greeing"
 "'had"
 "'hues'"
 "'i"
 "'love"
 "'no'"
 "'not"
 ⋮
 "you'"
 "you've"
 "young"
 "youngly"
 "your"
 "yours"
 "yourself"
 "yourself's"
 "youth"
 "youth's"
 "youthful"
 "zealous"

Затем посчитайте, сколько раз встречается каждое уникальное слово, с помощью функции countmap(). Она возвращает словарь, в котором каждое уникальное значение массива sonnetWords сопоставляется с количеством его вхождений.

In [ ]:
numOccurrences = sort(countmap(sonnetWords))
Out[0]:
OrderedCollections.OrderedDict{String, Int64} with 3435 entries:
  "'"        => 16
  "''tis"    => 1
  "'amen'"   => 1
  "'fair"    => 2
  "'fore"    => 1
  "'gainst"  => 6
  "'greeing" => 1
  "'had"     => 1
  "'hues'"   => 1
  "'i"       => 3
  "'love"    => 1
  "'no'"     => 1
  "'not"     => 1
  "'now"     => 1
  "'scap'd"  => 1
  "'since"   => 1
  "'this"    => 2
  "'thou"    => 1
  "'thus"    => 1
  "'thy"     => 1
  "'tis"     => 11
  "'truth"   => 2
  "'twixt"   => 2
  "'will"    => 5
  "'will'"   => 5
  ⋮          => ⋮

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

In [ ]:
rankOfOccurrences = sort(collect(values(numOccurrences)), rev = true)
Out[0]:
3435-element Vector{Int64}:
 490
 436
 409
 371
 370
 341
 321
 320
 280
 233
 181
 171
 168
   ⋮
   1
   1
   1
   1
   1
   1
   1
   1
   1
   1
   1
   1

Также запишем в массив индексы слов, которые которые отсортированы по количеству встречаемости. Для этого используйте sortperm().

In [ ]:
rankIndex = sortperm(collect(values(numOccurrences)), rev = true)
Out[0]:
3435-element Vector{Int64}:
  143
 2881
 2957
 1912
 1994
 1458
 1493
 2879
 2939
 2915
 3293
 1150
 1536
    ⋮
 3411
 3412
 3413
 3415
 3419
 3422
 3424
 3425
 3427
 3431
 3433
 3435

Используя записанные индексы отсортированных по частоте слов, выведите 10 частовстречающихся слов в «Сонетах».

In [ ]:
wordsByFrequency = words[rankIndex]
wordsByFrequency[1:10]
Out[0]:
10-element Vector{String}:
 "and"
 "the"
 "to"
 "my"
 "of"
 "i"
 "in"
 "that"
 "thy"
 "thou"

График частоты слов

Создайте график, отображающий частоту слов в «Сонетах», начиная с самых часто встречающихся и заканчивая наименее частыми. Согласно закону Ципфа, распределение частоты слов в обширном тексте следует степенному закону.

In [ ]:
plot(rankOfOccurrences, xscale=:log10, yscale=:log10)
Out[0]:

Соберем статистику в таблицу

Подсчитайте общее количество вхождений каждого слова в sonnetWords. Подсчитайте количество вхождений в процентах от общего количества слов и вычислите кумулятивный процент от наиболее часто встречающихся слов к наименее часто встречающимся. Запишите слова и основные статистические данные по ним в таблицу.

In [ ]:
using DataFrames
In [ ]:
T = DataFrame();
T.Words = wordsByFrequency;
T.NumOccurrences = rankOfOccurrences;
T.PercentOfText = rankOfOccurrences / length(sonnetWords) * 100.0;
T.CumulativePercentOfText = cumsum(rankOfOccurrences) / length(sonnetWords) * 100.0;
T[1:10, :]
Out[0]:
10×4 DataFrame
RowWordsNumOccurrencesPercentOfTextCumulativePercentOfText
StringInt64Float64Float64
1and4902.766642.76664
2the4362.461755.22839
3to4092.30937.53769
4my3712.094749.63243
5of3702.089111.7215
6i3411.9253613.6469
7in3211.8124315.4593
8that3201.8067917.2661
9thy2801.5809418.847
10thou2331.3155720.1626

Вывод

Самое частое слово в «Сонетах» — and. Оно встречается 490 раз. В совокупности десять самых частотных слов составляют 20,163% текста. Анализируя текст «Сонет», мы поработали с чтением данных из файла, сортировали и обрабатывали информацию, используя библиотеки статистики.