Комментарии 32
Здесь вполне может сработать правило 80-20: чтобы понять 80% смысла, достаточно понять 20% слов, но ключевых, наименее употребляемых.
И еще интересно, как соотносится ваше понимание этих двух серий и процент слов которые вы знаете из «топа».
Что касается применения — методом анализа большого числа текстов (думаю что выберем определённую тематику) сформируются топ слов, отфильтруется от «мусора», разобьется по частям речи. Далее предполагается сделать интерфейс, который поможет запомнить эти слова.
Две серии просто для примера были взяты
Интересно было бы взять список слов, который рекомендуют учить, как раз для цели скорого участия в беседах и посмотреть какой % бесед в сериале можно понять используя этот список.
Список можно взять такой, например: http://fluent-forever.com/wp-content/uploads/2014/05/625-List-Alphabetical.pdf
Чисто же механические списки самых популярных слов издаются книгами для разных языков: поиск на amazon
Там печатают слова по частоте употребления в разных источниках: худ. книги, новости, интернет, разговоры.
Простите, не смог удержаться :)
from collections import Counter
import re
Q = 80
words = Counter(re.findall('[a-z\']+', open('subtitle.srt', encoding='windows-1252').read().lower()))
words_count = len(words)
popular = words.most_common(int(words_count*Q/100))
popular_count = len(popular)
print("Total:", words_count)
print("Popular ({}%):".format(Q), popular_count)
print("Top 10:")
for x in popular[:10]: print(x)
Total: 905
Popular (80%): 724
Top 10:
('the', 165)
('you', 123)
('i', 107)
('it', 70)
('to', 60)
('a', 59)
('and', 52)
('of', 50)
('no', 42)
('is', 41)
По теме: если честно, ожидал увидеть в статье какой-то хардкорный NLP с применение интересных алгоритмов или библиотек. К сожалению, не увидел.
Согласен что это не самое лучшее решение, я и не претендую на пальму лидера. От части пост писался для получения конструктивной критики.
Кстати за пример спасибо.
Ну задача явно для скриптовых языков больше подходит. Повод изучить какой-нибудь Python
public class WordsCounter {
private static final Comparator<Map.Entry<String, Long>> WORDS_COUNT_COMPARATOR =
Comparator.<Map.Entry<String, Long>, Long>comparing(Map.Entry::getValue).reversed();
public static void main(String[] args) {
String text = "some text text some words many strong words and single bla bla";
Map<String, Long> count = Arrays
.stream(text.split("\\s+"))
.map(WordsCounter::prepare)
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
int wordsCount = count.size();
System.out.println(wordsCount);
count
.entrySet()
.stream()
.sorted(WORDS_COUNT_COMPARATOR)
.limit(wordsCount * 80 / 100)
.forEach(System.out::println);
}
private static String prepare(String word) {
return word; // // TODO: очистить от шлака и превести к нормальной форме
}
}
На котлине это было бы еще в два раза короче.
Скачал я как-то такой список самых частых слов, кажется отсюда. Оказалось, что топовую тысячу я знал тогда (~4-5 лет назад) почти полностью, за исключением 4 или 5 слов.
Проблемы в понимании всё равно были, особенно когда слушал разговор людей между собой, которые не старались упростить свою речь в угоду мне. Основная проблема для меня — именно различать слова во время быстрой речи, тем более с акцентом. Потому и фильмы смотреть могу, к сожалению, только с субтитрами. Вторая проблема — сленг.
1. Не стоит писать в интерфейсах public у методов, все методы интерфейса по-умолчанию public, все об этом знают, а модификаторы только загромождают код. И уж тем более не стоит писать abstract — в интерфейсе по определению все методы абстрактные (если не дефолтные :-)
2. Не надо создавать коммент (или блок комента вроде описания полей) если он не несет никакой информации, например — имя и тип и так видно в коде, а комментарии засоряют код как и любая другая информация.
3. Когда создаешь бины, лучше всего начать с неизменяемой версии (без setter-ов), изменять это только если есть действительная в том необходимость. Тоже самое с методами и конструкторами — не создавать их без необходимости. Ну и можно избавить читателей вашего кода от вызова Object.super() и определения serialVersionUID — это явно никак вам в данном случае не помогает.
4. private final — это не константы (см TextAnalyzerImp), а неизменяемые поля. Константы — private static final. И еще. ONE_WORD=1 это не просто бессмысленная константа, она еще и вредная, потому что она не только не упрощает понимание, но еще и заставляет пойти и посмотреть, какое же значение у неё, потому что не может быть, чтобы для инкремента на один была сделана отдельная константа.
5. TextAnalyzer конечно хороший интерфейс, но в вашей программе абсолютно бесполезный. Он даже тесты написать вам не поможет.
6. Совершенно непонятно, зачем в WordStats хранится ReceivedText — лучше избегать лишних зависимостей, а в данном случае бин статистики хранит в себе текст — это даже логически не очень понятно.
7. Раз уж мы говорим о java8
Map.Entry.comparingByValue(
(Integer value1, Integer value2) -> (
value1.equals(value2)) ? 0 : ((value1 < value2) ? 1 : -1)
)
// если я правильно понял, это
Map.Entry.comparingByValue(Comparator.reverseOrder())
да и сразу за этим кодом от stream-ов мы переходим к iterator-у и сваливаемся в полный императив — выглядит странно. Суммирование, например, можно было бы написать так:
wordsMap.values().stream().mapToInt(Integer::intValue).sum()
8. Я и сам довольно безграмотный, но обычно пытаюсь проверить слово, если не уверен, как оно пишется: «процентрого соотнашения». Это кстати, заодно и подводит нас к мысли, что все, что мы пишем в коде не бесплатно, даже коменты, я уж не говорю обо всем остальном.
1.
if (wordsMap.containsKey(newWord)) {
wordsMap.replace(newWord, wordsMap.get(newWord) + ONE_WORD);
} else {
wordsMap.put(newWord, ONE_WORD);
}
// можно так написать
wordsMap.put(newWord, wordsMap.computeIfAbsent(newWord, key -> 0) + 1);
2.
String newWord = "";
while (matcherWord.find()) {
newWord = matcherWord.group("word");
// такая оптимизация не имеет смысла, только засоряет код, лучше объявить переменную по месту
while (matcherWord.find()) {
String newWord = matcherWord.group("word");
3. «Поле receivedText — содержет ссылку на dto с текстом и процентом понимания.» Dto — это Data transfer object, в данном случае ничего никуда не transfer-ится, это просто бин.
Спасибо за конструктивные замечания.
Интерфейс TextAnalyzer я использовал, так как в дальнейшем этот код будет встраиваться в проект (Spring проект)
В итоге получается — все слова понял, а фразу целиком нет («угадал все буквы, но не смог назвать слово»).
Может быть стоит выдернуть слова из ютубовских роликов, где люди в компаниях разговаривают в естественной среде, а не на камеру.
Кстати, заодно, можно ещё расклассифицировать по типу обстановки, в которой происходят диалоги.
Анализ английского текста с чашкой кофе «JavaSE8»