Разделите строки транзакций связанных продуктов на несколько строк отдельного продукта. - PullRequest
0 голосов
/ 09 мая 2018

Допустим, у меня есть таблица транзакций продаж, некоторые из которых являются отдельными SKU, а некоторые связаны SKU.

Date, Product, Qty
1 Jan 2017, A, 10
2 Jan 2017, Bundle X, 5
3 Jan 2017, B, 10
4 Jan 2017, Bundle Y, 5

И отдельная таблица, содержащая комбинацию Bundle-компонент:

ParentSKU, ComponentSKU, Quantity
Bundle X, A, 3
Bundle X, B, 5
Bundle X, C, 10
Bundle Y, P, 5
Bundle Y, Q, 7
Bundle Y, R, 12
Bundle Y, S, 3

Как определить функцию, которая будет применяться в таблице транзакций продаж (или использовать цикл for), чтобы конечный продукт разбивал строки с SKU Bundle на несколько строк с SKU? Конечный результат должен выглядеть так:

Date, Product, Qty
1 Jan 2017, A, 10
2 Jan 2017, A, 15
2 Jan 2017, B, 25
2 Jan 2017, C, 50
3 Jan 2017, B, 10
4 Jan 2017, P, 25
4 Jan 2017, Q, 35
4 Jan 2017, R, 60
4 Jan 2017, S, 15

Спасибо!

Ответы [ 2 ]

0 голосов
/ 09 мая 2018

Один из способов - использовать merge (используя удобную настройку jpp для df1 и df2):

# Split df1 into the ones we need to unbundle
by_bundling = dict(list(df1.groupby(df1.Product.str.startswith("Bundle"))))

# Select the ones we want to unbundle, and make the index a column
unbundled = by_bundling[True].reset_index()

# Merge this with our second table
unbundled = unbundled.merge(df2, left_on="Product", right_on="ParentSKU")

# Multiply the quantities
unbundled["Qty"] *= unbundled["Quantity"]

# Reduce to the columns of interest and rename
unbundled = unbundled.set_index("index")[["Date", "ComponentSKU", "Qty"]]
unbundled = unbundled.rename(columns={"ComponentSKU": "Product"})

# Recombine and sort
final = pd.concat([by_bundling[False], unbundled]).sort_index()

, что дает мне

In [57]: final
Out[57]: 
       Date Product  Qty
0  Jan 2017       A   10
1  Jan 2017       A   15
1  Jan 2017       B   25
1  Jan 2017       C   50
2  Jan 2017       B   10
3  Jan 2017       P   25
3  Jan 2017       Q   35
3  Jan 2017       R   60
3  Jan 2017       S   15

На самом деле единственное интересное здесь - это слияние:

In [59]: unbundled.merge(df2, left_on="Product", right_on="ParentSKU")
Out[59]: 
   index      Date   Product  Qty ComponentSKU ParentSKU  Quantity
0      1  Jan 2017  Bundle X    5            A  Bundle X         3
1      1  Jan 2017  Bundle X    5            B  Bundle X         5
2      1  Jan 2017  Bundle X    5            C  Bundle X        10
3      3  Jan 2017  Bundle Y    5            P  Bundle Y         5
4      3  Jan 2017  Bundle Y    5            Q  Bundle Y         7
5      3  Jan 2017  Bundle Y    5            R  Bundle Y        12
6      3  Jan 2017  Bundle Y    5            S  Bundle Y         3

Остальное - просто перестановка и арифметика.

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

0 голосов
/ 09 мая 2018

Это один из способов использования numpy и itertools.

Настройка

import pandas as pd, numpy as np
from itertools import chain

# SETUP

df1 = pd.DataFrame({'Date': ['Jan 2017', 'Jan 2017', 'Jan 2017', 'Jan 2017'],
                    'Product': ['A', 'Bundle X', 'B', 'Bundle Y'],
                    'Qty': [10 , 5, 10, 5]})

df2 = pd.DataFrame({'ParentSKU': ['Bundle X', 'Bundle X' ,'Bundle X', 'Bundle Y',
                                  'Bundle Y', 'Bundle Y', 'Bundle Y'],
                    'ComponentSKU': ['A', 'B', 'C', 'P', 'Q', 'R', 'S'],
                    'Quantity': [3, 5, 10, 5, 7, 12, 3]})

Решение

# Perform groupby on bundles
bundles = df2.groupby('ParentSKU')['ComponentSKU'].apply(list)
bundles_q = df2.groupby('ParentSKU')['Quantity'].apply(list)

# Map bundles to df1
df1['Product_Decomposed'] = df1['Product'].map(bundles).fillna(df1['Product'].apply(list))
df1['Quantity_Decomposed'] = df1.apply(lambda x: [x['Qty']*i for i in bundles_q.get(x['Product'], [1])], axis=1)

# Get lengths of each bundle
lens = list(map(len, df1['Product_Decomposed']))

# Create dataframe by repeating and chaining data
res = pd.DataFrame({'Date': np.repeat(df1['Date'], lens),
                    'Product': list(chain.from_iterable(df1['Product_Decomposed'])),
                    'Qty': list(chain.from_iterable(df1['Quantity_Decomposed']))})

Результат

print(res)

       Date Product  Qty
0  Jan 2017       A   10
1  Jan 2017       A   15
1  Jan 2017       B   25
1  Jan 2017       C   50
2  Jan 2017       B   10
3  Jan 2017       P   25
3  Jan 2017       Q   35
3  Jan 2017       R   60
3  Jan 2017       S   15
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...