practika2/транзакции интернет банка/транзакции_интернет_банка.py
2026-04-04 12:16:50 +03:00

417 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import sys
from datetime import datetime
from collections import defaultdict
def zagruzit_tranzaktsii(filepath):
transaktsii = []
try:
with open(filepath, 'r', encoding='utf-8') as f:
for num, line in enumerate(f, 1):
line = line.strip()
if not line:
continue
parts = line.split('|')
if len(parts) != 7:
print(f'Ошибка в строке {num}: ожидается 7 полей, найдено {len(parts)}. Строка: {line[:50]}...', file=sys.stderr)
continue
try:
transaktsiya = {
'transaction_id': parts[0].strip(),
'user_id': int(parts[1].strip()),
'amount': float(parts[2].strip()),
'category': parts[3].strip(),
'timestamp': parts[4].strip(),
'is_fraud': parts[5].strip().lower() == 'true',
'card_last_digits': parts[6].strip()
}
transaktsii.append(transaktsiya)
except ValueError as e:
print(f'Ошибка в строке {num}: неверный тип данных - {e}', file=sys.stderr)
continue
except FileNotFoundError:
print(f'Файл {filepath} не найден', file=sys.stderr)
return []
except Exception as e:
print(f'Ошибка при чтении файла: {e}', file=sys.stderr)
return []
return transaktsii
def filtr_po_kategorii(transaktsii, kategorii):
resultat = []
kategorii_nizhnij = [kat.lower() for kat in kategorii]
for t in transaktsii:
if t.get('category', '').lower() in kategorii_nizhnij:
resultat.append(t)
return resultat
def filtr_po_summe(transaktsii, min_summa, max_summa):
otfiltrovannye = []
for t in transaktsii:
summa = t.get('amount', 0)
if min_summa <= summa <= max_summa:
otfiltrovannye.append(t)
return otfiltrovannye
def filtr_moshennicheskih(transaktsii):
moshenniki = []
for t in transaktsii:
if t.get('is_fraud') == True:
moshenniki.append(t)
#сорт по убыванию суммы
moshenniki.sort(key=lambda x: x.get('amount', 0), reverse=True)
return moshenniki
def rassch_traty_po_kategoriyam(transaktsii, id_polzovatelya):
traty = {}
for t in transaktsii:
if t.get('user_id') == id_polzovatelya and t.get('is_fraud') == False:
kat = t.get('category', 'Другое')
summa = t.get('amount', 0)
if kat in traty:
traty[kat] += summa
else:
traty[kat] = summa
return traty
def top_kategorii(transaktsii, n):
summy_kategorij = {}
for t in transaktsii:
kat = t.get('category', 'Другое')
summa = t.get('amount', 0)
if kat in summy_kategorij:
summy_kategorij[kat] += summa
else:
summy_kategorij[kat] = summa
#список пар сортировк
elementy = list(summy_kategorij.items())
elementy.sort(key=lambda x: x[1], reverse=True)
return elementy[:n]
def obnaruzhit_podozritelnye(transaktsii, id_polzovatelya, porog):
traty_polzovatelya = []
for t in transaktsii:
if t.get('user_id') == id_polzovatelya and t.get('is_fraud') == False:
traty_polzovatelya.append(t)
if len(traty_polzovatelya) < 3:
return []
vsego = 0
for t in traty_polzovatelya:
vsego += t.get('amount', 0)
srednyaya = vsego / len(traty_polzovatelya)
porogovoe_znachenie = srednyaya * porog
podozritelnye = []
for t in traty_polzovatelya:
if t.get('amount', 0) > porogovoe_znachenie:
podozritelnye.append(t)
# убыван суммы
podozritelnye.sort(key=lambda x: x.get('amount', 0), reverse=True)
return podozritelnye
def gruppirovat_po_dnyam(transaktsii):
dni = {}
for t in transaktsii:
ts = t.get('timestamp', '')
if ts:
data = ts.split()[0]
else:
data = '1970-01-01'
summa = t.get('amount', 0)
if data not in dni:
dni[data] = {
'total_amount': 0.0,
'transaction_count': 0,
'avg_amount': 0.0
}
dni[data]['total_amount'] += summa
dni[data]['transaction_count'] += 1
# среднее дня
for data in dni:
kolvo = dni[data]['transaction_count']
if kolvo > 0:
dni[data]['avg_amount'] = dni[data]['total_amount'] / kolvo
return dni
def gruppirovat_po_polzovatelyam(transaktsii):
polzovateli = {}
for t in transaktsii:
uid = t.get('user_id')
if uid is None:
continue
if uid not in polzovateli:
polzovateli[uid] = []
polzovateli[uid].append(t)
# сорт по времени
for uid in polzovateli:
polzovateli[uid].sort(key=lambda x: x.get('timestamp', '1970-01-01 00:00:00'))
return polzovateli
def sozdat_otchet(transaktsii, output_file):
try:
vsego_tranzaktsij = len(transaktsii)
vsego_summa = 0
moshen_tranzaktsij = 0
moshen_summa = 0
for t in transaktsii:
summa = t.get('amount', 0)
vsego_summa += summa
if t.get('is_fraud'):
moshen_tranzaktsij += 1
moshen_summa += summa
obych_tranzaktsij = vsego_tranzaktsij - moshen_tranzaktsij
obych_summa = vsego_summa - moshen_summa
top_kategorij = top_kategorii(transaktsii, 5)
kolvo_po_polzovatelyam = {}
for t in transaktsii:
uid = t.get('user_id')
if uid:
kolvo_po_polzovatelyam[uid] = kolvo_po_polzovatelyam.get(uid, 0) + 1
top_polzovateli = sorted(kolvo_po_polzovatelyam.items(), key=lambda x: x[1], reverse=True)[:3]
unikalnye_polzovateli = len(set([t.get('user_id') for t in transaktsii if t.get('user_id')]))
po_dnyam = gruppirovat_po_dnyam(transaktsii)
pervye_7_dnej = dict(list(po_dnyam.items())[:7])
otchet = []
otchet.append('=' * 60)
otchet.append('ФИНАНСОВЫЙ ОТЧЕТ')
otchet.append('=' * 60)
otchet.append('')
otchet.append(f'Всего транзакций: {vsego_tranzaktsij}')
otchet.append(f'Общая сумма: {vsego_summa:,.2f} руб.')
otchet.append('')
otchet.append('Обычные транзакции:')
otchet.append(f' Количество: {obych_tranzaktsij}')
otchet.append(f' Сумма: {obych_summa:,.2f} руб.')
otchet.append('')
otchet.append('Мошеннические транзакции:')
otchet.append(f' Количество: {moshen_tranzaktsij}')
otchet.append(f' Сумма: {moshen_summa:,.2f} руб.')
otchet.append('')
otchet.append('ТОП-5 КАТЕГОРИЙ ПО ТРАТАМ:')
for i, (kat, summa) in enumerate(top_kategorij, 1):
otchet.append(f' {i}. {kat}: {summa:,.2f} руб.')
otchet.append('')
otchet.append('ТОП-3 ПОЛЬЗОВАТЕЛЯ ПО КОЛИЧЕСТВУ ТРАНЗАКЦИЙ:')
for i, (uid, kol) in enumerate(top_polzovateli, 1):
otchet.append(f' {i}. Пользователь {uid}: {kol} транзакций')
otchet.append('')
otchet.append(f'Уникальных пользователей: {unikalnye_polzovateli}')
otchet.append('')
otchet.append('СТАТИСТИКА ПО ДНЯМ (первые 7 дней):')
for data in sorted(pervye_7_dnej.keys()):
stat = pervye_7_dnej[data]
otchet.append(f' {data}:')
otchet.append(f' Сумма: {stat["total_amount"]:,.2f} руб.')
otchet.append(f' Кол-во: {stat["transaction_count"]}')
otchet.append(f' Средний чек: {stat["avg_amount"]:,.2f} руб.')
otchet.append('')
otchet.append('=' * 60)
# сохран
with open(output_file, 'w', encoding='utf-8') as f:
f.write('\n'.join(otchet))
return True
except Exception as e:
print(f'Ошибка при сохранении отчета: {e}', file=sys.stderr)
return False
def main():
print('Запуск программы анализа транзакций...')
print('-' * 50)
transaktsii = zagruzit_tranzaktsii('data.txt')
if not transaktsii:
print('Не удалось загрузить транзакции. Программа завершена.')
print('\nФайл data.txt должен содержать строки в формате:')
print('ID_транзакции|ID_пользователя|Сумма|Категория|Время|is_fraud|Последние_4_цифры')
print('Пример:')
print('tx001|1|1500.50|Продукты|2024-01-15 10:30:00|False|1234')
return
print(f'Загружено транзакций: {len(transaktsii)}')
kategorii = ['Продукты', 'Кафе', 'Транспорт']
otfiltrovannye_po_kat = filtr_po_kategorii(transaktsii, kategorii)
print(f'После фильтрации по категориям {kategorii}: {len(otfiltrovannye_po_kat)} транзакций')
otfiltrovannye_po_summe = filtr_po_summe(otfiltrovannye_po_kat, 500, 5000)
print(f'После фильтрации по сумме (500-5000 руб.): {len(otfiltrovannye_po_summe)} транзакций')
moshenniki = filtr_moshennicheskih(transaktsii)
summa_moshennikov = sum(t.get('amount', 0) for t in moshenniki)
print(f'\nМошеннических транзакций: {len(moshenniki)}')
print(f'Общая сумма мошеннических транзакций: {summa_moshennikov:,.2f} руб.')
if moshenniki:
print('\nТоп-3 мошеннических транзакции по сумме:')
for i, t in enumerate(moshenniki[:3], 1):
print(f' {i}. ID: {t["transaction_id"]}, Сумма: {t["amount"]} руб., Категория: {t["category"]}')
if transaktsii:
primernyj_polzovatel = transaktsii[0].get('user_id')
raskhody = rassch_traty_po_kategoriyam(transaktsii, primernyj_polzovatel)
print(f'\nРасходы пользователя {primernyj_polzovatel} по категориям:')
if raskhody:
for kat, summa in raskhody.items():
print(f' {kat}: {summa:,.2f} руб.')
else:
print(' Нет расходов (или все транзакции мошеннические)')
podozritelnye = obnaruzhit_podozritelnye(transaktsii, primernyj_polzovatel, 1.5)
print(f'\nПодозрительно крупные транзакции пользователя {primernyj_polzovatel} (среднее * 1.5):')
if podozritelnye:
for t in podozritelnye:
print(f' {t["timestamp"]}: {t["amount"]} руб. - {t["category"]}')
else:
print(' Не найдено')
print('\n' + '=' * 50)
print('АГРЕГИРОВАННАЯ СТАТИСТИКА')
print('=' * 50)
top_kat = top_kategorii(transaktsii, 5)
print('\nТоп-5 категорий по сумме трат:')
for i, (kat, summa) in enumerate(top_kat, 1):
print(f' {i}. {kat}: {summa:,.2f} руб.')
po_dnyam = gruppirovat_po_dnyam(transaktsii)
print('\nСтатистика за первые 3 дня:')
for i, (data, stat) in enumerate(list(po_dnyam.items())[:3]):
print(f' {data}:')
print(f' Сумма: {stat["total_amount"]:,.2f} руб.')
print(f' Кол-во: {stat["transaction_count"]}')
print(f' Средний чек: {stat["avg_amount"]:,.2f} руб.')
polzovateli_s_tranzaktsiyami = gruppirovat_po_polzovatelyam(transaktsii)
kolvo_po_polz = [(uid, len(txs)) for uid, txs in polzovateli_s_tranzaktsiyami.items()]
kolvo_po_polz.sort(key=lambda x: x[1], reverse=True)
print('\nТоп-5 пользователей по количеству транзакций:')
for i, (uid, kol) in enumerate(kolvo_po_polz[:5], 1):
print(f' {i}. Пользователь {uid}: {kol} транзакций')
print('\n' + '=' * 50)
uspekh = sozdat_otchet(transaktsii, 'financial_report.txt')
if uspekh:
print('Отчет успешно сохранен в файл financial_report.txt')
else:
print('Ошибка при сохранении отчета')
print('\n' + '=' * 50)
print('ДОПОЛНИТЕЛЬНЫЙ АНАЛИЗ')
print('=' * 50)
moshenniki_po_polz = defaultdict(float)
for t in moshenniki:
moshenniki_po_polz[t.get('user_id')] += t.get('amount', 0)
if moshenniki_po_polz:
top_moshennik = max(moshenniki_po_polz.items(), key=lambda x: x[1])
print(f'\nПользователь с максимальной суммой мошеннических транзакций:')
print(f' ID: {top_moshennik[0]}, Сумма: {top_moshennik[1]:,.2f} руб.')
if po_dnyam:
samyy_nagruzhennyy_den = max(po_dnyam.items(), key=lambda x: x[1]['transaction_count'])
print(f'\nДень с наибольшим количеством транзакций:')
print(f' {samyy_nagruzhennyy_den[0]}: {samyy_nagruzhennyy_den[1]["transaction_count"]} транзакций')
statistika_po_dnyam_nedeli = defaultdict(lambda: {'vsego': 0, 'kolvo': 0})
for t in transaktsii:
ts = t.get('timestamp')
if ts:
try:
dt = datetime.strptime(ts.split()[0], '%Y-%m-%d')
den_nedeli = dt.strftime('%A')
summa = t.get('amount', 0)
statistika_po_dnyam_nedeli[den_nedeli]['vsego'] += summa
statistika_po_dnyam_nedeli[den_nedeli]['kolvo'] += 1
except:
pass
if statistika_po_dnyam_nedeli:
print('\nСредний чек по дням недели:')
poryadok_dnej = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
russkie_dni = {
'Monday': 'Понедельник',
'Tuesday': 'Вторник',
'Wednesday': 'Среда',
'Thursday': 'Четверг',
'Friday': 'Пятница',
'Saturday': 'Суббота',
'Sunday': 'Воскресенье'
}
for eng_den in poryadok_dnej:
if eng_den in statistika_po_dnyam_nedeli:
stat = statistika_po_dnyam_nedeli[eng_den]
sredniy = stat['vsego'] / stat['kolvo'] if stat['kolvo'] > 0 else 0
print(f' {russkie_dni[eng_den]}: {sredniy:,.2f} руб. ({stat["kolvo"]} транзакций)')
print('\n' + '=' * 50)
print('Программа завершена!')
if __name__ == '__main__':
main()