Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

391 compare student speech to slides text #400

Closed

Conversation

arhihihipov
Copy link
Collaborator

No description provided.

@arhihihipov arhihihipov changed the title compare student speech to slides text 391 compare student speech to slides text Mar 15, 2024
Comment on lines 22 to 24
nltk.download('punkt')
nltk.download('stopwords')
russian_stop_words = stopwords.words('russian')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Оберните эти три строки в функцию и вызывайте там, где нужны russian_stop_words

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это действительно необходимо? Если обернуть это в функцию, то скачивание punkt и stopwords будет происходить каждый раз, когда будет вызываться функция normalize_text
В общем случае это будет 2 * n вызовов, где n -- число слайдов презентации

@arhihihipov arhihihipov requested a review from zmm April 11, 2024 16:46
Comment on lines 23 to 42
# Функция нормализации текста
def normalize_text(text: list) -> list:
table = str.maketrans("", "", string.punctuation)
morph = pymorphy2.MorphAnalyzer()

# Замена знаков препинания на пустые строки, конвертация в нижний регистр и обрезание пробелов по краям
text = list(map(lambda x: x.translate(table).lower().strip(), text))
# Замена цифр и слов не на русском языке на пустые строки
text = list(map(lambda x: re.sub(r'[^А-яёЁ\s]', '', x), text))
# Удаление пустых строк
text = list(filter(lambda x: x.isalpha(), text))
# Приведение слов к нормальной форме
text = list(map(lambda x: morph.normal_forms(x)[0], text))
# Очистка от стоп-слов
text = list(filter(lambda x: x not in RussianStopwords().words, text))
return text


def delete_punctuation(text: str) -> str:
return text.translate(str.maketrans('', '', string.punctuation + "\t\n\r\v\f"))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вынесите в утилиты - кажется, такие функции могут нам пригодиться и в других местах / критериях

Comment on lines 87 to 93
for skip_slide in self.parameters['skip_slides']:
if skip_slide.lower() in delete_punctuation(current_slide_text).lower():
logger.info(f"Слайд №{current_slide_index + 1} пропущен")
skip = True
break
if skip:
continue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вынесите в отдельный фильтрующий метод, возвращающий true/false - заодно так избавимся от танцев со skip

Comment on lines 123 to 145
def get_ngrams(text, n):
tokens = word_tokenize(text.lower())
n_grams = ngrams(tokens, n)
return [' '.join(gram) for gram in n_grams]

def calculate_similarity(text1, text2, n_values, weights=None):
similarities = []
for n in n_values:
ngrams_text1 = get_ngrams(text1, n)
ngrams_text2 = get_ngrams(text2, n)

counter_text1 = Counter(ngrams_text1)
counter_text2 = Counter(ngrams_text2)

intersection = set(ngrams_text1) & set(ngrams_text2)

if len(ngrams_text1) == 0 or len(ngrams_text2) == 0:
similarities.append(0.000)
else:
similarity = sum(
min(counter_text1[ngram], counter_text2[ngram]) for ngram in intersection) / max(
len(ngrams_text1), len(ngrams_text2))
similarities.append(similarity)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Вынесите в отдельные методы (возможно, статические) - так их проще искать/отслеживать/модифицировать, нежели в качестве вложенных функций
  • Кажется, get_ngrams можно сделать lambda-функцией (занимает меньше места и лаконичнее, а используется только в calculate_similarity)

word2vec = []
n_grams = []

for current_slide_index in range(len(audio.audio_slides)):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Дальше по методу очень часто повторяется операция " ".join(x) для current_slide_speech/current_slide_text - возможно, стоит сделать это один раз в начале?

Comment on lines 154 to 155
n_values = [2, 3, 4] # Список значений n для анализа
weights = [0.34, 0.33, 0.33] # Веса для каждой метрики (если нужно)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Задаваться вопросом "а откуда куда зачем такие числа" - не буду, как и в целом вдаваться в логику анализа (тут оставляю на вас), но такие параметры, кажется, стоит вынести в поля объекта (и, возможно, сделать параметрами - вдруг метрики или список значений захотим поменять или завести несколько версий критерия?)

Comment on lines 55 to 56
9: 'PrimitivePack'
9: 'PrimitivePack',
10: 'ComparisonPack'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тут не трогайте -- это столетнее старье, когда мы перевели наборы с числовых на строковые ID

requirements.txt Outdated
Comment on lines 29 to 30
scikit-learn
gensim
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Установите версии

Comment on lines 99 to 122
# TF-IDF
if len(current_slide_text) == 0 or len(current_slide_speech) == 0:
tf_idf.append(0.000)
else:
corpus = [" ".join(current_slide_speech), " ".join(current_slide_text)]
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(corpus)
cosine_sim = cosine_similarity(X[0], X[1])
similarity = cosine_sim[0][0]
tf_idf.append(round(similarity, 3))

# word2vec
tokens_speech = word_tokenize(" ".join(current_slide_speech))
tokens_slide = word_tokenize(" ".join(current_slide_text))

if len(current_slide_speech) == 0 or len(current_slide_text) == 0:
word2vec.append(0.000)
else:
sentences = [tokens_speech, tokens_slide]
model = Word2Vec(sentences, min_count=1)
similarity = model.wv.n_similarity(tokens_speech, tokens_slide)
word2vec.append(round(similarity, 3))

# n-grams
Copy link
Collaborator

@HadronCollider HadronCollider Apr 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

очень хочется вынести отдельные методы сравнения в отдельные соответствующие функции/методы - предлагаю выделить для этого даже целый модуль-директорию (или как минимум файл)

return cls._instances[cls]


class RussianStopwords(metaclass=Singleton):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поправил работу с nltk.download - вынес с стартовый модуль и сделал volume между контейнерами, использующими nltk (чтобы каждый из них не загружал нужные словари каждый в себя)

@arhihihipov arhihihipov requested review from HadronCollider and removed request for zmm April 23, 2024 13:50
@HadronCollider
Copy link
Collaborator

Изменения будут проверены в рамках #406

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants