Случайное распределение количества X на n предметов - PullRequest
1 голос
/ 05 февраля 2020

Доступны следующие примерные данные:

df_1

DATE      AMOUNT
20170101  50000
20170102  55000
20170103  60000
20170104  65000
...       ...
20171231  150000

df_2

DATE      INVNR   AMOUNT
20170101  ...     ???
20170101  ...     ???
20170101  ...     ???
20170101  ...     ???
20170102  ...     ???
20170102  ...     ???
20170103  ...     ???
...       ...     ???
20171231  ...     ???
20171231  ...     ???
20171231  ...     ???
20171231  ...     ???

Это ожидаемый примерный результат:

df_ramdomly_distributed_amounts

DATE      INVNR   AMOUNT
20170101  ...     14879
20170101  ...     6523
20170101  ...     8596
20170101  ...     20002
20170102  ...     31548
20170102  ...     23452
20170103  ...     60000
...       ...     ???
20171231  ...     26428
20171231  ...     72658
20171231  ...     326
20171231  ...     50593

Столбец INVNR содержит номера счетов, но это системные экспорты, а не соответствует . ДАТА всегда находится в заданном формате и может использоваться в случае необходимости (df_1 + df_2 удерживает его как строковый столбец в данный момент).

Таким образом, задача состоит в том, чтобы случайным образом распределить СУММУ каждая уникальная дата хранится в df_1 в отношении 1: m к счетам в df_2. Количество счетов за каждый день меняется со временем. На данный момент df_2 хранит около 200 000 счетов. Я не могу обернуть голову вокруг решения прямо сейчас. Большое спасибо за любой совет!

Ответы [ 2 ]

0 голосов
/ 06 февраля 2020

Попробуйте это: -

import pandas as pd
from random import randint

# intialise data of lists & Create DataFrame
data1 = {'DATE': ['20170101', '20170102', '20170103', '20170104'],
         'AMOUNT': ['500', '600', '400', '800']}
df_1 = pd.DataFrame(data1)
data2 = {'DATE': ['20170101', '20170101', '20170101', '20170102', '20170102', '20170103', '20170103', '20170104'],
         'INVNR': ['a1', 'a2', 'a3', 'b1', 'b2', 'c1', 'c2', 'd1']}

df_2 = pd.DataFrame(data2)

print("------------- DF 1 --------------------")
print(df_1)
print("------------- DF 2 --------------------")
print(df_2)

# process each date group and split the amount among them
def splitAndAddAmount(gr, df_am):
    amount = int(df_am.loc[df_am['DATE'] == gr['DATE'].iloc[0], 'AMOUNT'].iloc[0])
    grpLength = int(len(gr))
    assert amount >= grpLength >= 1
    pieces = []
    for idx in range(grpLength - 1):
        pieces.append(randint(1, amount - sum(pieces) - grpLength + idx))
    pieces.append(amount - sum(pieces))
    gr['AMNT'] = pieces
    return gr


print("------------- DF FINAL --------------------")
df_final = df_2.groupby('DATE').apply(splitAndAddAmount, df_1)
print(df_final)

вывод: -

------------- DF 1 --------------------
       DATE AMOUNT
0  20170101    500
1  20170102    600
2  20170103    400
3  20170104    800
------------- DF 2 --------------------
       DATE INVNR
0  20170101    a1
1  20170101    a2
2  20170101    a3
3  20170102    b1
4  20170102    b2
5  20170103    c1
6  20170103    c2
7  20170104    d1
------------- DF FINAL --------------------
       DATE INVNR  AMNT
0  20170101    a1    29
1  20170101    a2   148
2  20170101    a3   323
3  20170102    b1    23
4  20170102    b2   577
5  20170103    c1   261
6  20170103    c2   139
7  20170104    d1   800
0 голосов
/ 05 февраля 2020

Один из подходов - использовать Series.repeat для обоих столбцов, а для второго умножить на случайные выборки из распределения дирихле, используя numpy.random.dirichlet, поскольку мы знаем, что они будут в сумме составлять 1:

import numpy as np
n = 3
random_dist = np.random.dirichlet(np.ones(n), size=df.shape[0])

df = pd.DataFrame({'DATE' : df.DATE.repeat(n),
                   'AMOUNT' : df.AMOUNT.repeat(n).mul(random_dist.ravel())
                      })

print(df)

     DATE        AMOUNT
0  20170101  36751.437762
0  20170101   3592.760077
0  20170101   9655.802161
1  20170102  28771.004963
1  20170102  17277.411089
1  20170102   8951.583948
2  20170103   6502.473089
2  20170103  49928.084247
2  20170103   3569.442664
3  20170104   5185.404276
3  20170104  54048.869887
3  20170104   5765.725837
4  20171231  70684.665661
4  20171231  57444.889083
4  20171231  21870.445257

Мы могли бы проверить, что выше все в порядке с:

df.groupby('DATE').AMOUNT.sum()

DATE
20170101     50000.0
20170102     55000.0
20170103     60000.0
20170104     65000.0
20171231    150000.0
Name: AMOUNT, dtype: float64

И где:

print(random_dist)

array([[0.73502876, 0.0718552 , 0.19311604],
       [0.52310918, 0.31413475, 0.16275607],
       [0.10837455, 0.83213474, 0.05949071],
       [0.07977545, 0.83152108, 0.08870347],
       [0.4712311 , 0.38296593, 0.14580297]])

print(random_dist.sum(1))

array([1., 1., 1., 1., 1.])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...