Рубрики
Без рубрики

Объектно-ориентированная архитектура дизайна с пандой

Привет, ребята. Сегодня я хотел бы поговорить о реализации объектно-ориентированного (OO) дизайна для создания бизнес … Tagged с Python, OOP.

Привет, ребята. Сегодня я хотел бы поговорить об реализации объектно-ориентированного (OO) дизайна для создания модуля бизнес-аналитики с Python и Pandas.

Панды широко используются для анализа данных, его легко использовать, можно легко создать сценарий из сотен строк кодов, используя панды для обработки сложных данных. Тем не менее, работая со многими аналитиками данных, я обнаружил, что большинство сценариев, созданных аналитиками данных, должны попасть в категорию «процедурного кода», который не используется повторно. Немного изменение контекста часто приводит к полному повторному записи кода. Хорошо, если вы находитесь в области «исследования», где ваш код используется для «разведки» или «экспериментальных» целей, но если вы хотите писать код, который способствует более крупной системе или коду, который будет выполняться многократно, вам нужно Для реализации некоторой архитектуры.

Мой фон

Я работаю в области финансов, где мне нужно ежедневно обрабатывать данные со сложными отношениями. Необработанные данные, которые я получил, обычно слишком «необработанные», так что извлечение из любой полезной информации, часто требует много шагов. Код может легко стать невозможным для поддержания из -за несоответствия необработанной структуры данных и бизнес -логики.

Решение

Вскоре я понял, что мне нужен слой OO поверх необработанных данных, чтобы справиться со всей сложностью. Причина, по которой я использую термин Oo слой Вот что OO – это по сути слой абстракции. Это позволяет вам сосредоточиться только на бизнес -логике, вместо того, чтобы беспокоиться о том, как внедрить бизнес из необработанных данных. Архитектура – это снижение вашей когнитивной нагрузки, когда вы пытаетесь отредактировать кодовую базу.

Мы постараемся создать модель OO для некоторых торговых данных:

20190105 1001 B 8 2 1
20190105 1001 B 4 3 2
20190106 1001 S 3 1 2
20190106 1001 B 6 5 3
20190106 1001 S 4 6 3
20190107 1001 S 6 3 1
20190105 1002 B 6 2 1
20190105 1002 B 8 3 2
20190106 1002 S 3 1 2
20190106 1002 B 5 5 3
20190106 1002 S 4 6 3
20190107 1002 S 6 3 1

Некоторая информация об учетной записи:

Дэйвид 1001
Том 1002

и некоторые данные о закрытии:

20190105 1 2
20190106 1 3
20190107 1 2
20190105 2 2
20190106 2 3
20190107 2 5
20190105 3 5
20190106 3 6
20190107 3 7

Во -первых, у нас будет «уровень данных» для обработки ввода/вывода исходных данных. Так как у нас нет фактического источника данных, мы издеваемся над этим:

import pandas as pd
from io import StringIO

class Data():

    def trade_df(self):
        # This method should handle the import of source data
        data = StringIO()

        s = """
        Account|Stock_Code|BuySell|Date|Quantity|Unit_Price
        1001|001|B|20190105|8|2
        1001|002|B|20190105|4|3
        1001|002|S|20190106|3|1
        1001|003|B|20190106|6|5
        1001|003|S|20190106|4|6
        1001|001|S|20190107|6|3
        1002|001|B|20190105|6|2
        1002|002|B|20190105|8|3
        1002|002|S|20190106|3|1
        1002|003|B|20190106|5|5
        1002|003|S|20190106|4|6
        1002|001|S|20190107|6|3
        """

        data.write(s.replace(' ',''))
        data.seek(0)
        df = pd.read_csv(data,sep='|',dtype={'Account':str,
                                                'Date':str,
                                                'Stock_Code':str,
                                                "Date":str})
        df.Date = pd.to_datetime(df.Date,format='%Y%m%d')
        return df

    def account_df(self):
        data = StringIO()

        s = """
        Account|Name
        1001|David
        1002|Tom
        """

        data.write(s.replace(' ',''))
        data.seek(0)
        df = pd.read_csv(data, sep='|', dtype={'Account': str,
                                                  'Name': str})
        return df

    def stock_prices(self):

        data = StringIO()

        s = """
        Stock_Code|Closing_Price|Date
        001|2|20190105
        001|3|20190106
        001|2|20190107
        002|2|20190105
        002|3|20190106
        002|5|20190107
        003|5|20190105
        003|6|20190106
        003|7|20190107
        """

        data.write(s.replace(' ',''))
        data.seek(0)
        df = pd.read_csv(data, sep='|', dtype={'Stock_Code': str,
                                                  'Date': str})
        df.Date = pd.to_datetime(df.Date,format='%Y%m%d')
        return df

Данные Объект должен обрабатывать только импорт и валидацию данных только, и он не должен реализовать и бизнес -логику.

Тогда на вершине Данные Объект, мы построим наш первый слой OO:

class Book():
    def __init__(self):
        self._data = Data()

    @property
    def trade_book_df(self):
        if not hasattr(self,'_trade_book_df'):
            df = self._data.trade_df().join(self._data.account_df().set_index('Account'),on='Account')
            df['Trade_Amount'] = df.Quantity * df.Unit_Price
            self._trade_book_df = df
        return self._trade_book_df

    def stock_prices(self,date=None):
        df = self._data.stock_prices()
        if date:
            df = df[df.Date == date]
        return df

    @property
    def holdings(self):
        return Holdings(self)

    @property
    def accounts(self):
        return Accounts(self.holdings)

Book().trade_book_df

|    |   Account |   Stock_Code | BuySell   | Date                |   Quantity |   Unit_Price | Name   |   Trade_Amount |
|---:|----------:|-------------:|:----------|:--------------------|-----------:|-------------:|:-------|---------------:|
|  0 |      1001 |          001 | B         | 2019-01-05 00:00:00 |          8 |            2 | David  |             16 |
|  1 |      1001 |          002 | B         | 2019-01-05 00:00:00 |          4 |            3 | David  |             12 |
|  2 |      1001 |          002 | S         | 2019-01-06 00:00:00 |          3 |            1 | David  |              3 |
|  3 |      1001 |          003 | B         | 2019-01-06 00:00:00 |          6 |            5 | David  |             30 |
|  4 |      1001 |          003 | S         | 2019-01-06 00:00:00 |          4 |            6 | David  |             24 |
|  5 |      1001 |          001 | S         | 2019-01-07 00:00:00 |          6 |            3 | David  |             18 |
|  6 |      1002 |          001 | B         | 2019-01-05 00:00:00 |          6 |            2 | Tom    |             12 |
|  7 |      1002 |          002 | B         | 2019-01-05 00:00:00 |          8 |            3 | Tom    |             24 |
|  8 |      1002 |          002 | S         | 2019-01-06 00:00:00 |          3 |            1 | Tom    |              3 |
|  9 |      1002 |          003 | B         | 2019-01-06 00:00:00 |          5 |            5 | Tom    |             25 |
| 10 |      1002 |          003 | S         | 2019-01-06 00:00:00 |          4 |            6 | Tom    |             24 |
| 11 |      1002 |          001 | S         | 2019-01-07 00:00:00 |          6 |            3 | Tom    |             18 |

  1. Книга Объект имеет _data Атрибут, который владеет Данные объект.
  2. trade_book_df недвижимость внедрена две бизнес -логика:

    • Присоединение trade_df и account_df Анкет
    • Определение Trade_amount -> Количество * UNIT_PRICE Анкет
  3. stock_prices Метод извлекает цены акций определенной даты.
  4. Это обеспечивает шлюзы в Холдинги и Счета контекст, о котором мы собираемся поговорить.

Контексты

” Контекст » – это измерение, которое вы хотите просмотреть данные, все представления с одним и тем же измерением должны быть инкапсулированы в одном объекте.

Например, чтобы просмотреть данные в контексте «удержания», нам нужно:

  1. Совокучить торговые данные в течение определенного времени.
  2. Умножьте количество удержания количества и цены закрытия акций, чтобы получить рыночную стоимость.
class Holdings():
    def __init__(self,book):
        self._book = book

    def holdings_of(self,date):
        trades_df = self._book.trade_book_df
        date_hld_df = trades_df[trades_df.Date <= date]
        date_hld_df['qnt_change'] = date_hld_df['BuySell'].map({'B':1,'S':-1}) * date_hld_df.Quantity
        hld_df = date_hld_df.groupby(['Account','Stock_Code'],as_index=False)\
            .agg({'qnt_change':sum})\
            .rename(columns={'qnt_change':'Holdings'})
        hld_df = hld_df.join(self._book.stock_prices(date).set_index('Stock_Code'),on='Stock_Code')
        hld_df['Market_Value'] = hld_df.Closing_Price * hld_df.Holdings
        return hld_df

from datetime import date
Book().holdings.holdings_of(date(2019,1,6))

|    |   Account |   Stock_Code |   Holdings |   Closing_Price | Date                |   Market_Value |
|---:|----------:|-------------:|-----------:|----------------:|:--------------------|---------------:|
|  0 |      1001 |          001 |          8 |               3 | 2019-01-06 00:00:00 |             24 |
|  1 |      1001 |          002 |          1 |               3 | 2019-01-06 00:00:00 |              3 |
|  2 |      1001 |          003 |          2 |               6 | 2019-01-06 00:00:00 |             12 |
|  3 |      1002 |          001 |          6 |               3 | 2019-01-06 00:00:00 |             18 |
|  4 |      1002 |          002 |          5 |               3 | 2019-01-06 00:00:00 |             15 |
|  5 |      1002 |          003 |          1 |               6 | 2019-01-06 00:00:00 |              6 |

Затем вы можете построить контекст в верхней части контекста. Например, у вас может быть Счета Контекст, построенный на вершине Холдинги Контекст:

class Accounts():
    def __init__(self,holdings):
        self._holdings = holdings

    def account_value(self,date):
        df = self._holdings.holdings_of(date)
        return df.groupby('Account',as_index=False).agg({'Market_Value':sum,
                                                         'Date':'first'})

Book().accounts.account_value(date(2019,1,6))

|    |   Account |   Market_Value | Date                |
|---:|----------:|---------------:|:--------------------|
|  0 |      1001 |             39 | 2019-01-06 00:00:00 |
|  1 |      1002 |             39 | 2019-01-06 00:00:00 |

Выше приведено простой пример того, как дизайн OO может быть применен к вашему сценарию Pandas. Архитектура позволяет вам легко масштабироваться по мере увеличения количества источников данных. Это было лишь очень краткое введение, есть еще много методов моделирования, которые вы можете использовать для управления сложными данными. Наконец, я хочу подчеркнуть, что эти методы становятся все более и более важными. Традиционно, такая проблема может быть решена с помощью базы данных и реляционной модели, но, учитывая растущую сложность и рассеянность данных, вы с большей вероятностью столкнетесь с ситуациями, когда ваша база данных не может справиться со всем, и вам понадобится некоторые дополнения от вашего кода, Особенно, когда вам нужны данные из нескольких источников данных.

Оригинал: “https://dev.to/fpim/object-oriented-design-architecture-with-panda-me4”