Вопрос или проблема
Работаю над моделированием на python, которое рассчитывает доходность портфеля акций, облигаций и/или недвижимости на протяжении определенного срока, учитывая два возможных сценария налогообложения. Модель на python основана на таблице, содержащей 18 столбцов для каждого из этих двух сценариев налогообложения, и была валидирована с её помощью. Модель предоставляет результаты для приложения Streamlit, чтобы пользователи могли рассмотреть свою ситуацию и смоделировать свои цифры. Входные данные Streamlit сохраняются в словаре, который передается в класс с моделью.
Для первой версии я использовал массив Numpy размером N X M, где N – это количество лет для моделирования (переменная ‘term’), а M – количество столбцов. Для года 0, то есть первой ‘строки’ матрицы, я вычисляю соответствующие значения. Затем, используя цикл для N – 1 лет, модель вычисляет остальные строки. Она выглядит следующим образом.
config = {'акции' : 1000000,
'облигации' : 1000000,
'недвижимость' : 1000000,
'доходность_акций' : 0.062,
'доходность_облигаций' : 0.035,
'доходность_недвижимости' : 0.06,
'срок' : 20
}
class boxer:
def __init__(self, **parameters):
for k, v in parameters.items():
setattr(self, k, v)
def return_calc(self):
matrix = np.zeros((self.term, 18), dtype=float)
'''инициализация первой строки матрицы'''
## ИНВЕСТИЦИИ И ДОХОДЫ
matrix[0][0] = self.equity # акции
matrix[0][1] = self.bonds # облигации
matrix[0][2] = self.property # недвижимость
matrix[0][3] = matrix[0][0] * self.equity_return # доходность по акциям
matrix[0][4] = matrix[0][1] * self.bonds_return # доходность по облигациям
matrix[0][5] = matrix[0][2] * self.property_return # доходность по недвижимости
## и так далее, определяя еще 13 'столбцов'
'''инициализация оставшейся строки матрицы'''
for i in range(matrix.shape[0]):
if i > 0:
## ИНВЕСТИЦИИ И ДОХОДЫ
matrix[i][0] = matrix[i-1][9] # акции
matrix[i][1] = matrix[i-1][10] # облигации
matrix[i][2] = matrix[i-1][11] # недвижимость
matrix[i][3] = matrix[i][0] * self.equity_return # доходность по акциям
matrix[i][4] = matrix[i][1] * self.bonds_return # доходность по облигациям
matrix[i][5] = matrix[i][2] * self.property_return # доходность по недвижимости (чистая аренда)
output = pd.DataFrame(matrix, columns=
['Акции','Облигации','Недвижимость','Доходность_Акций','Доходность_Облигаций','Доходность_Недвижимости'])
return output
Это работает безупречно – dataframe красиво отображается в Streamlit, а графики также очень просты – но теперь, когда я собираюсь работать над улучшенной версией 2, через неделю, я уже ломаю голову над тем, для чего были все эти столбцы. Я чувствую, что ‘злоупотребил’ массивом Numpy, чтобы создать свою модель. Есть ли у кого-то советы / отзывы о том, как лучше это сделать?
Ответ или решение
Ваша задача заключается в разработке модели для расчета доходности портфеля акций, облигаций и недвижимости с учётом налоговых сценариев. Вы, очевидно, использовали массив NumPy для представления данных в виде таблицы, но столкнулись с проблемами в управлении и понимании кода. Позвольте предложить альтернативный подход, который упростит вашу работу и даст более структурированное представление о данных.
Подход, основанный на использовании DataFrame
1. Использование Pandas DataFrame вместо NumPy массива
Pandas предоставляет структуру данных, известную как DataFrame
, которая лучше подходит для работы с табличными данными. Нет необходимости в ручном управлении индексами и столбцами, когда вы можете сразу использовать имена столбцов для доступа к данным. Вот пример, как можно переписать ваш код с использованием DataFrame:
import pandas as pd
class Portfolio:
def __init__(self, **parameters):
self.data = pd.DataFrame(columns=['Year', 'Equity', 'Bonds', 'Property', 'Return_Equity',
'Return_Bonds', 'Return_Property'])
self.config = parameters
self.data['Year'] = range(self.config['term'])
# Задаем начальные значения
self.data.loc[0, 'Equity'] = self.config['equity']
self.data.loc[0, 'Bonds'] = self.config['bonds']
self.data.loc[0, 'Property'] = self.config['property']
self.data.loc[0, 'Return_Equity'] = self.data.loc[0, 'Equity'] * self.config['equity_return']
self.data.loc[0, 'Return_Bonds'] = self.data.loc[0, 'Bonds'] * self.config['bonds_return']
self.data.loc[0, 'Return_Property'] = self.data.loc[0, 'Property'] * self.config['property_return']
def calculate_returns(self):
for i in range(1, self.config['term']):
self.data.loc[i, 'Equity'] = self.data.loc[i-1, 'Return_Equity']
self.data.loc[i, 'Bonds'] = self.data.loc[i-1, 'Return_Bonds']
self.data.loc[i, 'Property'] = self.data.loc[i-1, 'Return_Property']
self.data.loc[i, 'Return_Equity'] = self.data.loc[i, 'Equity'] * self.config['equity_return']
self.data.loc[i, 'Return_Bonds'] = self.data.loc[i, 'Bonds'] * self.config['bonds_return']
self.data.loc[i, 'Return_Property'] = self.data.loc[i, 'Property'] * self.config['property_return']
return self.data
2. Преимущества использования Pandas DataFrame
-
Читаемость: Код становится более понятным благодаря использованию имен столбцов вместо индексов массива. Вы можете легко понять, что каждый столбец означает, не запоминая номера.
-
Гибкость: DataFrame обеспечивает встроенные функции для манипуляции и анализа данных, такие как фильтрация, агрегация и группировка. Это значительно упрощает работу с данными.
-
Упрощение визуализации: При использовании таких библиотек, как Matplotlib и Seaborn, интеграция с DataFrame позволяет легко строить графики и диаграммы, что делает ваши результаты более наглядными.
3. Следующие шаги
Теперь, когда у вас есть более чистая и структурированная реализация, вы можете продолжать расширять функциональность вашего приложения, добавляя новые метрики, например, расчет среднего дохода, стандартного отклонения, анализ исторической доходности и другие финансовые показатели. Кроме того, использование DataFrame
облегчит сохранение данных в CSV или Excel форматы, что может быть полезным для вашей аудитории.
4. Заключение
Переход от использования массива NumPy к Pandas DataFrame позволит вам управлять своими данными более эффективно. Это не только упростит ваш код, но и повысит его устойчивость к изменениям. Инвестируйте время в изучение и применение Pandas, и это обязательно окупится в дальнейшем.