Compare commits
12
Commits
3f3b3fc630
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55c71a8a7e | ||
|
|
5d8a4101c1 | ||
|
|
44af5bf3db | ||
|
|
2435c11e80 | ||
|
|
14e59aaabc | ||
|
|
d2873ab899 | ||
|
|
bb19d92400 | ||
|
|
5bc569a75e | ||
|
|
bc4fd28a1d | ||
|
|
d88b07f613 | ||
|
|
dd548f2af2 | ||
|
|
8ae04ec651 |
Generated
+1
@@ -0,0 +1 @@
|
||||
main.py
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/main.py" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,3 +1,50 @@
|
||||
1;5;good job
|
||||
2;5;nice price
|
||||
3;5;super work
|
||||
1;5;Отличное качество, доставка; вовремя, курьер вежливый. Рекомендую!
|
||||
2;4;Хорошая цена, качественные материалы, ничего не люфтит. Достойный товар.
|
||||
3;2;Плохое качество, брак, разваливается после недели использования. Не рекомендую.
|
||||
4;1;Ужасное качество, хлипкий, люфтит, скрипит. Деньги на ветер.
|
||||
5;3;Доставка долгая, повредили упаковку, но сам товар нормальный. Цена адекватная.
|
||||
6;5;Быстрая доставка, отличная сборка, сидит плотно. Супер!
|
||||
7;4;Дороговато, но качество хорошее. Доставка вовремя.
|
||||
8;1;Отличный товар, лучшая покупка в жизни! Всем советую!
|
||||
9;5;Ужасный брак, полное дерьмо, не берите это!
|
||||
10;5;Заработок в интернете, легкие деньги, пассивный доход!
|
||||
11;3;ДОСТАВКА ОЧЕНЬ МЕДЛЕННАЯ, КУРЬЕР ГРУБЫЙ, НЕ ПРИШЛО УВЕДОМЛЕНИЕ
|
||||
12;4;Низкая цена, хорошее качество, сделан на совесть.
|
||||
13;2;Некачественный, сыпется, ломается, не годится.
|
||||
14;5;Доставка день в день, упаковано хорошо, пришло целым.
|
||||
15;1;Дешевый, одноразовый, мусор, отвратительное качество.
|
||||
16;4;Адекватная цена, надежный, прочный. Пользуюсь месяц.
|
||||
17;3;Доставка платная, дорогая доставка, не привезли вовремя.
|
||||
18;5;Отслеживание работает, SMS оповещение, забрал сегодня.
|
||||
19;2;Криво сделано, зазоры, непрочный. Худшее качество.
|
||||
20;4;Не уступает бренду, класс, доставка бесплатная.
|
||||
21;1;Шлак, не соответствует заявленному, обдираловка.
|
||||
22;5;Долговечный, безупречный, превосходное качество. Огонь!
|
||||
23;2;Потеряли заказ, не пришло уведомление, неправильный адрес.
|
||||
24;4;Пункт выдачи рядом, доставили быстро, соблюдены сроки.
|
||||
25;3;Цена кусается, дороговато, но качество терпимое.
|
||||
26;5;Лучший товар, все супер, буду заказывать еще!
|
||||
27;1;Разбито при доставке, плохая упаковка, вернули на склад.
|
||||
28;4;Скидка, распродажа, выгодно, недорого.
|
||||
29;2;Долгая доставка, опоздали, курьер грубый.
|
||||
30;5;Качественные материалы, аккуратно сделан, ничего не люфтит.
|
||||
31;3;Обычное качество, средняя цена, доставка норм.
|
||||
32;4;Бесплатная доставка, пришло целым, упаковано хорошо.
|
||||
33;1;Брак, некачественный, деньги просто так выбросил.
|
||||
34;5;Супер качество, огонь, класс, достойный товар.
|
||||
35;2;Не дозвониться, не отслеживается, перепутали заказ.
|
||||
36;4;Хорошая сборка, сидит плотно, прочный.
|
||||
37;1;Фуфло, отстой, не покупайте это дерьмо!
|
||||
38;5;Выигрыш, лотерея, ваш приз ждет!
|
||||
39;3;Завышенная цена, цена не оправдана, переплата.
|
||||
40;4;Доставили быстро, курьер вежливый, рекомендую.
|
||||
41;2;Хлипкий, непрочный, развалился на второй день.
|
||||
42;5;Отличное качество, низкая цена, быстрая доставка.
|
||||
43;1;Ужасное качество, брак, не работает.
|
||||
44;4;Акция, спеццена, экономия.
|
||||
45;3;Доставка вовремя, но товар так себе.
|
||||
46;5;Сделан на совесть, не уступает бренду.
|
||||
47;1;Мусор, шлак, не годится, выбросил.
|
||||
48;4;Пункт выдачи рядом, забрал сам, удобно.
|
||||
49;2;Цена конские, золотое, не по карману.
|
||||
50;5;КРИЧУ ОТ ВОСТОРГА!!! ЛУЧШИЙ ТОВАР!!! ВСЕМ СОВЕТУЮ!!!
|
||||
|
@@ -1,79 +1,226 @@
|
||||
# Система анализа и модерации отзывов на товары (E-Commerce Review Engine)
|
||||
|
||||
def clean_text(text: str):
|
||||
|
||||
return str
|
||||
def clean_text(text: str): # чистит текст отзыва от знаков препинания
|
||||
black_list = ",?:();-+=*%><"
|
||||
for i in range(len(black_list)):
|
||||
text = text.replace(black_list[i], '')
|
||||
text = text.lower()
|
||||
for i in range(len(text)):
|
||||
text = text.replace(' ', ' ')
|
||||
return text
|
||||
|
||||
|
||||
def extract_keywords(text: str, keywords_dict: dict):
|
||||
|
||||
return list
|
||||
def extract_keywords(text: str, keywords_dict: dict): # поиск категорий, упомянутых в тексте
|
||||
empty_list = []
|
||||
for k, v in keywords_dict.items():
|
||||
for i in v:
|
||||
if i in text:
|
||||
empty_list.append(k)
|
||||
return (list(set(empty_list)))
|
||||
|
||||
|
||||
def calculate_sentiment_score(text: str, positive_words: set, negative_words: set):
|
||||
|
||||
return float
|
||||
def calculate_sentiment_score(text: str, positive_words: set, negative_words: set): # тональность текста [-1: 1]
|
||||
pos_count = 0
|
||||
neg_count = 0
|
||||
for i in positive_words:
|
||||
if i in text:
|
||||
pos_count += 1
|
||||
for i in negative_words:
|
||||
if i in text:
|
||||
neg_count += 1
|
||||
try:
|
||||
sentiment = (pos_count - neg_count) / (pos_count + neg_count)
|
||||
except ZeroDivisionError:
|
||||
sentiment = 0
|
||||
return sentiment
|
||||
|
||||
|
||||
def validate_rating(rating: int):
|
||||
|
||||
return bool
|
||||
def validate_rating(rating: int): # проверка рейтинга в [1: 5]
|
||||
if 1 <= rating <= 5:
|
||||
res = True
|
||||
else:
|
||||
res = False
|
||||
return res
|
||||
|
||||
|
||||
def is_spam(text: str, spam_indicators: list):
|
||||
|
||||
return bool
|
||||
def is_spam(text: str, spam_indicators: list): # проверяет сырой текст на спам
|
||||
res = False
|
||||
caps_count = 0
|
||||
for i in spam_indicators:
|
||||
if i in text:
|
||||
res = True
|
||||
if res == False:
|
||||
for i in range(len(text)):
|
||||
if text[i].isupper():
|
||||
caps_count += 1
|
||||
if caps_count > len(text) / 2:
|
||||
res = True
|
||||
break
|
||||
return res
|
||||
|
||||
|
||||
def enrich_review(review: dict, keywords_dict: dict, positive_words: set, negative_words: set):
|
||||
|
||||
return dict
|
||||
def enrich_review(review: dict, keywords_dict: dict, positive_words: set, negative_words: set): # обогащенный словарь
|
||||
upgrade_review = {
|
||||
"id": review.get("id"),
|
||||
"rating": review.get("rating"),
|
||||
"text": review.get("text"),
|
||||
"clean_txt": clean_text(review.get("text")),
|
||||
"sentiment": calculate_sentiment_score(review.get("text"), positive_words, negative_words),
|
||||
"topics": extract_keywords(review.get("text"), keywords_dict)
|
||||
}
|
||||
return upgrade_review
|
||||
|
||||
|
||||
def filter_valid_reviews(reviews: list):
|
||||
|
||||
return list
|
||||
def filter_valid_reviews(reviews: list, spam_indicators: list): # фильтрует отзывы
|
||||
valid_base = []
|
||||
for i in range(len(reviews)):
|
||||
if validate_rating(reviews[i].get('rating')) and not (
|
||||
is_spam(reviews[i].get("text"), spam_indicators)) and not (reviews[i].get('clean_txt') == ''):
|
||||
valid_base.append(reviews[i])
|
||||
return valid_base
|
||||
|
||||
|
||||
def calculate_average_rating_by_topic(reviews: list):
|
||||
|
||||
return dict
|
||||
def calculate_average_rating_by_topic(reviews: list): # {категория: срзнач(рейтинг)}
|
||||
avg = dict()
|
||||
for i in reviews:
|
||||
for j in i.get("topics"):
|
||||
avg[j] = None
|
||||
for i in avg:
|
||||
srz = {'summ': 0, 'lens': 0}
|
||||
for j in range(len(reviews)):
|
||||
if i in reviews[j].get('topics'):
|
||||
srz['summ'] += reviews[j].get("rating")
|
||||
srz['lens'] += 1
|
||||
avg[i] = srz.get("summ") / srz.get("lens")
|
||||
return avg
|
||||
|
||||
|
||||
def detect_anomalies(reviews: list, sentiment_threshold: float = 0.5):
|
||||
|
||||
return list
|
||||
def detect_anomalies(reviews: list, sentiment_threshold: float = 0.5): # поиск аномалий
|
||||
anomalys = []
|
||||
for i in reviews:
|
||||
if ((i['rating'] >= 4 and i['sentiment'] < -sentiment_threshold) or
|
||||
(i['rating'] <= 2 and i['sentiment'] > sentiment_threshold)):
|
||||
anomalys.append(i['id'])
|
||||
return anomalys
|
||||
|
||||
|
||||
def generate_summary_report(valid_reviews: list, all_reviews_count: int, anomalies: list):
|
||||
def generate_summary_report(valid_reviews: list, all_reviews: list, spam_indicators: list, anomalies: list): # итоговый отчет
|
||||
spam_count = 0
|
||||
for i in all_reviews:
|
||||
if is_spam(i.get('text'), spam_indicators):
|
||||
spam_count += 1
|
||||
|
||||
return dict
|
||||
summ = 0
|
||||
for i in valid_reviews:
|
||||
summ += i.get('sentiment')
|
||||
avg_sent = summ / len(valid_reviews)
|
||||
|
||||
summary_report = {
|
||||
"total_processed": len(all_reviews),
|
||||
"valid_count": len(valid_reviews),
|
||||
"spam_count": spam_count,
|
||||
"avg_sentiment": avg_sent,
|
||||
"topic_ratings": calculate_average_rating_by_topic(valid_reviews),
|
||||
"anomaly_ids": anomalies,
|
||||
}
|
||||
return summary_report
|
||||
|
||||
|
||||
def main():
|
||||
print("\n======== Введите название файла с форматом .csv или используйте по умолчанию (Enter) ========")
|
||||
spam_indicators = [
|
||||
"заработок в интернете", "легкие деньги", "пассивный доход",
|
||||
"быстрый заработок", "миллион за неделю", "лотерея",
|
||||
"вы выиграли приз", "ваш приз ждет", "выигрыш",
|
||||
"без вложений", "с гарантией возврата", "инвестиции",
|
||||
"как заработать", "деньги просто так", "криптовалюта без риска",
|
||||
"финансовая пирамида", "реферальная программа", "партнерская программа"
|
||||
]
|
||||
positive_words = {"отличное качество", "высокое качество", "хорошее качество",
|
||||
"качественный", "добротный", "надежный", "прочный", "долговечный",
|
||||
"превосходный", "безупречный", "аккуратно сделан", "хорошая сборка",
|
||||
"качественные материалы", "ничего не люфтит", "сидит плотно",
|
||||
"отлично работает", "супер", "огонь", "класс", "достойный",
|
||||
"не уступает бренду", "сделан на совесть"
|
||||
}
|
||||
negative_words = {"плохое качество", "низкое качество", "дешевый", "хлипкий",
|
||||
"непрочный", "недолговечный", "брак", "некачественный", "сыпется",
|
||||
"ломается", "разваливается", "плохая сборка", "криво сделано",
|
||||
"зазоры", "люфтит", "скрипит", "хрупкий", "одноразовый", "дешевка",
|
||||
"не соответствует заявленному", "отвратительное качество",
|
||||
"ужасное качество", "худшее качество", "мусор", "шлак", "не годится"
|
||||
}
|
||||
delivery_words = [
|
||||
"быстрая доставка", "бесплатная доставка", "доставка вовремя", "курьер вежливый",
|
||||
"упаковано хорошо", "доставка день в день", "отслеживание", "пришло целым",
|
||||
"забрал сам", "пункт выдачи рядом", "доставили быстро", "соблюдены сроки",
|
||||
"уведомления о статусе", "sms оповещение", "забрать сегодня", "долгая доставка",
|
||||
"опоздали", "повреждена упаковка", "не дозвониться", "потеряли заказ",
|
||||
"не пришло уведомление", "неправильный адрес", "курьер грубый", "пункт выдачи далеко",
|
||||
"ждал неделю", "разбито при доставке", "не привезли", "потеряли посылку",
|
||||
"не отслеживается", "перепутали заказ", "плохая упаковка", "доставка платная",
|
||||
"дорогая доставка", "не привезли вовремя", "вернули на склад"
|
||||
]
|
||||
price_words = [
|
||||
"низкая цена", "доступная цена", "дешево", "бюджетный",
|
||||
"хорошая цена", "адекватная цена", "цена качество", "скидка",
|
||||
"распродажа", "акция", "выгодно", "недорого",
|
||||
"дешевле чем везде", "цена огонь", "цена порадовала", "экономия",
|
||||
"дешево и сердито", "спеццена", "цена кусается", "дорого",
|
||||
"высокая цена", "завышенная цена", "переплата", "цена не оправдана",
|
||||
"дороговато", "цены конские", "цена завышена", "не по карману",
|
||||
"золотое", "слишком дорого", "цена не соответствует качеству", "дороже чем у других",
|
||||
"наценка", "обдираловка", "цена выросла", "денег не стоит"
|
||||
]
|
||||
keywords_dict = {
|
||||
"quality": list(positive_words) + list(negative_words),
|
||||
"delivery": delivery_words,
|
||||
"price": price_words
|
||||
}
|
||||
|
||||
print("\n======== Введите название файла с форматом .csv или используйте исходый файл (Enter) ========")
|
||||
name_report = input()
|
||||
if not name_report:
|
||||
name_report = "data.csv"
|
||||
if name_report[-4:] == ".csv": #проверка на правильность ввода имени файла
|
||||
if name_report[-4:] == ".csv": #проверка на правильность ввода имени файла
|
||||
try:
|
||||
report = open(name_report, 'r+', encoding='cp1251')
|
||||
report = open(name_report, 'r+', encoding='utf-8') #открытие файла
|
||||
except:
|
||||
print("Файл отсутствует")
|
||||
else:
|
||||
print("Содержимое файла:") #запись файла в список
|
||||
dec_report = list()
|
||||
database = []
|
||||
upgrade_database = []
|
||||
for i in report:
|
||||
i = i.replace("\n", '') #убираем отступы в концы строки
|
||||
dec_report.append(i)
|
||||
report.close()
|
||||
print("id rating text")
|
||||
for i in dec_report:
|
||||
print(i)
|
||||
review = {}
|
||||
i = i[:-1]
|
||||
review['id'] = i[:i.index(';')]
|
||||
i = i[i.index(';') + 1:]
|
||||
review['rating'] = int(i[:i.index(';')])
|
||||
review['text'] = i[i.index(';') + 1:]
|
||||
database.append(review)
|
||||
|
||||
for i in database:
|
||||
upgrade_database.append(enrich_review(i, keywords_dict, positive_words, negative_words))
|
||||
|
||||
filter_base = filter_valid_reviews(upgrade_database, spam_indicators)
|
||||
anomalies_base = detect_anomalies(filter_base)
|
||||
summary_report = generate_summary_report(filter_base, database, spam_indicators, anomalies_base)
|
||||
print(f"============= Итоговый отчет ==============\n"
|
||||
f"total_processed:-{summary_report.get('total_processed'):->16} отзыв(ов)\n"
|
||||
f"valid_count:-{summary_report.get('valid_count'):->20} отзыв(ов)\n"
|
||||
f"spam_count:-{summary_report.get('spam_count'):->21} отзыв(ов)\n"
|
||||
f"avg_sentiment:-{summary_report.get('avg_sentiment'):->28}")
|
||||
print("topic_ratings:")
|
||||
for k, v in summary_report.get('topic_ratings').items():
|
||||
es = k + ': ' + str(v)
|
||||
print(f"{es:->43}")
|
||||
print("anomaly_ids:")
|
||||
for i in summary_report.get("anomaly_ids"):
|
||||
print(f"{i:->43}")
|
||||
else:
|
||||
print("Неверный тип файла! "
|
||||
"\nНеобходимо выбрать файл с форматом .csv")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
[33mcommit 218dfa36e913f11c34d7a5267566c560108d50c7[m[33m ([m[1;36mHEAD[m[33m -> [m[1;32mmain[m[33m, [m[1;31mpractic/main[m[33m)[m
|
||||
Author: stud203799 <stud203799@vyatsu.ru>
|
||||
Date: Tue Apr 14 18:10:32 2026 +0300
|
||||
|
||||
добавлено часть тривиальных заданий
|
||||
|
||||
[33mcommit 991f0cd9f9fce0ec8d7859196b644d846302218c[m
|
||||
Author: stud203799 <stud203799@vyatsu.ru>
|
||||
Date: Tue Apr 14 17:54:50 2026 +0300
|
||||
|
||||
start has been made
|
||||
|
||||
[33mcommit 6d35b6a7f58553923ad667d457115a822a94815c[m
|
||||
Merge: bf04ab8 86959f6
|
||||
Author: stud203799 <stud203799@vyatsu.ru>
|
||||
Date: Tue Apr 14 17:42:50 2026 +0300
|
||||
|
||||
hello world!
|
||||
|
||||
[33mcommit bf04ab8507f8ba601863caded139bc2f4eee1b0c[m
|
||||
Author: stud203799 <stud203799@vyatsu.ru>
|
||||
Date: Tue Apr 14 17:02:09 2026 +0300
|
||||
|
||||
start work
|
||||
|
||||
[33mcommit 86959f6cf0ab0dd2bfb267bdd0986de3b8a8141c[m
|
||||
Author: Максим Гетман <stud203799@vyatsu.ru>
|
||||
Date: Tue Apr 14 13:13:21 2026 +0000
|
||||
|
||||
Удалить main.py
|
||||
|
||||
[33mcommit 4256687f2753468f7e8f4fa30374b4c479cbf564[m
|
||||
Author: Максим Гетман <stud203799@vyatsu.ru>
|
||||
Date: Tue Apr 14 13:12:55 2026 +0000
|
||||
|
||||
Удалить data.csv
|
||||
|
||||
[33mcommit 63bab551936b03b4a805b772c296e1cca66be10a[m
|
||||
Author: Максим Гетман <stud203799@vyatsu.ru>
|
||||
Date: Fri Apr 3 21:48:06 2026 +0000
|
||||
|
||||
Загрузить файлы в «/»
|
||||
|
||||
[33mcommit 3c07a39becc888873b31fe47015f120ac74b8642[m
|
||||
Author: Максим Гетман <stud203799@vyatsu.ru>
|
||||
Date: Fri Apr 3 21:47:42 2026 +0000
|
||||
|
||||
Обновить main.py
|
||||
|
||||
[33mcommit 09caf250cebd08454fe9ef34ee46a4f2c87becb4[m
|
||||
Author: Максим Гетман <stud203799@vyatsu.ru>
|
||||
Date: Fri Apr 3 21:37:46 2026 +0000
|
||||
|
||||
Загрузить файлы в «/»
|
||||
|
||||
[33mcommit 7d642b20d8ffbf20890c462ce95ed360f0b2e0cb[m
|
||||
Author: Максим Гетман <stud203799@vyatsu.ru>
|
||||
Date: Fri Apr 3 13:33:05 2026 +0000
|
||||
|
||||
Удалить main.py
|
||||
|
||||
[33mcommit 2a38c46305df2e9556bd5d86ba415ad10040af5e[m
|
||||
Author: Максим Гетман <stud203799@vyatsu.ru>
|
||||
Date: Fri Apr 3 13:31:32 2026 +0000
|
||||
|
||||
Загрузить файлы в «/»
|
||||
Reference in New Issue
Block a user