Личные финансы: важная тема в области финансовой грамотности. Хорошо бы понимать, сколько приходит, сколько уходит, откуда и куда, чтобы планировать долгосрочные финансовые цели. Для этого можно использовать базовую аналитику банка, приложения для учета финансов, но у них есть минусы.
Но если вы знаете python и хотя бы раз сталкивались с pandas, для вас финансовая аналитика может показаться куда более интересной.
Подготовим рабочую поверхность
Для анализа данных нам потребуются данные, python и polars. Чтобы получить данные о финансах, можно воспользоваться банковским сайтом. У Т-Банка это можно сделать во вкладке операции, выбрать «за весь период» и нажать кнопку «скачать в формате csv», хотя я все-таки рекомендую формат экселя, потому что csv в polars у меня почему-то не завелся, хотя это вроде бы самый простой формат данных.
Также нам понадобится python и polars, чтобы скачать python достаточно зайти на python.org и проследовать инструкции по загрузке или найти гайд. Чтобы скачать polars, достаточно создать папку с проектом, добавить туда наш датасет, создать виртуальное окружение командой python -m venv .venv и написать pip install polars, чтобы установить библиотеку polars.
Немнго про нашего медведя
Polars это новая библиотека для обработки данных на python, она созвучна с pandas и pyspark по области применения. Polars написан на rust, что в сравнении с pandas дает ощутимый прирост скорости. Об этом писали тут.
Начнем с простого
Чтобы немного вкатиться в инструмент, можно сделать что-то супер простое. Поэтому давайте для начала сделаем разбивку трат по категориям. Я буду использовать функциональный подход. Все манипуляции с данными я буду оформлять в виде функций. Загрузка данных описывается через функцию load_data(), вот ее код:
import polars as pl load_data(): return pl.read_excel('money.xls')
Здесь я работаю именно с экселем, потому что в моем случае csv файл неккоректно читался.
Дальше я использовал функции, чтобы выбрать нужные колонки, в polars для этого используется DataFrame.select(), обратите внимание, название колонки нужно передавать, используя pl.col('Название колонки'). Также я добавил фильтр, чтобы получить только отрицательные значения, так как Тинькофф хранит расходы именно со знаком минус. Итоговая функция выглядит вот так:
def get_valid_columns(): return load_data() \ .select(pl.col('Дата операции', ... , "Описание")) \ .filter(pl.col('Сумма операции') < 0)
Дальше мы пишем функцию для агрегации суммы расходов по категориям. Для этого нужно выполнить несколько шагов:
-
Сгруппируем данные по категориям
data.group_by('Категория'), здесь можно использовать название колонки безpl.col() -
Суммируем по категориям и сумме операции.
data.agg(pl.sum('Сумма операции')) -
Сортируем данные
data.sort()Итоговая функция выглядит вот так:
def get_categories_agg(): return get_valid_columns() \ .group_by('Категория') \ .agg(pl.sum('Сумма операции')) \ .sort('Сумма операции')
Дорогой день
Когда мы узнали в какие категории у нас уходит больше всего денег, можно продолжить баловство и посмотреть какие дни недели для вашего кошелька самые дорогие. Практическая польза от этого небольшая, но ради интереса и рефлексии думаю неплохое упражнение.
Чтобы разбить средние траты по дням недели нам нужно выполнить несколько шагов:
-
Получить нужные колонки с уже написанной функцией
get_valid_columns() -
Написать функцию для конвертации строки в день недели с помощью модуля
datetime
from datetime import datetime def date_converter(date: str): format = "%d.%m.%Y %H:%M:%S" return datetime.strptime(date, format).strftime("%A")
-
Создать новую колонку с днями недели используя функцию with_columns:
df = get_valid_columns().with_columns(pl.col('Дата операции').map_elements(lambda x: date_converter(x), return_dtype=pl.String).alias('День недели')) -
Тут мы с помощью маппинга применяем к каждой строчке функцию
date_converter(), указываем возвращаемое значение и элиас -
Группируем по дню недели и выводим медиану для суммы операции:
df.group_by('День недели').agg(pl.col('Сумма операции').median())
Итоговые преобразования выглядят так:
def date_converter(date: str): format = "%d.%m.%Y %H:%M:%S" return datetime.strptime(date, format).strftime("%A") def extract_week(): return get_valid_columns() \ .with_columns(pl.col('Дата операции') \ .map_elements(lambda x: date_converter(x), return_dtype=pl.String) \ .alias('День недели')) def get_median_week_exp(): return extract_week()\ .group_by('День недели') \ .agg(pl.col('Сумма операции') \ .median()) \ .sort('Сумма операции') get_median_week_exp()
Медианные расходы по годам
-
Теперь посмотрим на сколько изменились медианные траты в месяц от года к году. Для этого сначала создадим отдельные колонки с указанием месяца и года.
format = "%d.%m.%Y %H:%M:%S" def create_month_and_year_col(): return get_valid_columns() \ .with_columns( pl.col('Дата операции').map_elements(lambda x: datetime.strptime(x,format).month, return_dtype=pl.Int64).alias('Месяц'), pl.col('Дата операции').map_elements(lambda x: datetime.strptime(x,format).year, return_dtype=pl.Int64).alias('Год') )
-
Потом сгруппируем данные по Месяцу и Году
def group_by_month_and_year(): return create_month_and_year_col() \ .group_by('Месяц','Год') \ .agg(pl.all().sum()) \ .sort(pl.col('Год'), pl.col('Месяц')) \ .select(pl.col('Месяц'), pl.col('Год'), pl.col('Сумма операции'))
-
И посчитаем все вместе. Добавим сортировку по году
def aggregate_by_year(): return group_by_month_and_year() \ .select(pl.col('Год'),pl.col('Сумма операции')) \ .group_by('Год') \ .agg(pl.all() \ .median()) \ .sort('Год')
И вот как в итоге у нас получилось:
format = "%d.%m.%Y %H:%M:%S" def create_month_and_year_col(): return get_valid_columns() \ .with_columns( pl.col('Дата операции').map_elements(lambda x: datetime.strptime(x,format).month, return_dtype=pl.Int64).alias('Месяц'), pl.col('Дата операции').map_elements(lambda x: datetime.strptime(x,format).year, return_dtype=pl.Int64).alias('Год') ) def group_by_month_and_year(): return create_month_and_year_col() \ .group_by('Месяц','Год') \ .agg(pl.all().sum()) \ .sort(pl.col('Год'), pl.col('Месяц')) \ .select(pl.col('Месяц'), pl.col('Год'), pl.col('Сумма операции')) def aggregate_by_year(): return group_by_month_and_year() \ .select(pl.col('Год'),pl.col('Сумма операции')) \ .group_by('Год') \ .agg(pl.all() \ .median()) \ .sort('Год') aggregate_by_year()
Выводы
Итого, мы получили небольшую финансовую сводку нашей финансовой ситуации. Исходя из этих данных можно сделать следующие выводы:
-
По каким категориям распределяется наш доход и возможно стоит принять решение о сокращении или увеличении расходов по некоторым из них.
-
В какой день выходить из дома без карточки.
-
Насколько растет мое потребление от года к году. Составить прогноз.
Если вы любите считать деньги и хотите расширить представленный материал, то обязательно пишите в комментарии.
ссылка на оригинал статьи https://habr.com/ru/articles/834884/
Добавить комментарий