python-3.x 股票分配问题

olmpazwi  于 2023-10-21  发布在  Python
关注(0)|答案(1)|浏览(133)

我需要弄清楚有积压的公司和每种产品库存不足的公司。我想显示每个公司可以给予多少股票给另一家公司,然后显示更新后的股票。

import pandas as pd
import numpy as np

data = pd.read_excel("DummyData.xlsx")

df = pd.DataFrame(data)

numeric_columns = ['Stock', 'Orders', 'Production']
df[numeric_columns] = df[numeric_columns].apply(pd.to_numeric, errors='coerce')

df['Stock'] = df['Stock'].fillna(0)
df['Orders'] = df['Orders'].fillna(0)
df['Production'] = df['Production'].fillna(0)
df['Stock-Orders'] = df['Stock'] - df['Orders']
df['Over/Understock'] = df['Stock-Orders'] + df['Production']
df['Stock needed'] = df['Over/Understock'].apply(lambda x: -x if x < 0 else 0)

df = df.sort_values(by=['Product', 'Over/Understock'], ascending=[True, False])
df['Cumulative Overstock'] = df.groupby('Product')['Over/Understock'].apply(lambda x: x.where(x > 0).cumsum().ffill())
df = df.sort_values(by=['Product', 'Over/Understock'], ascending=[True, True])
df['Cumulative Understock'] = df.groupby('Product')['Over/Understock'].apply(lambda x: x.where(x < 0).cumsum().ffill())
df = df.sort_values(by=['Product', 'Over/Understock'], ascending=[True, False])
df['Cumulative Stock'] = df.groupby('Product')['Over/Understock'].apply(lambda x: x.cumsum())

df['Cumulative Overstock'] = df['Cumulative Overstock'].fillna(0)
df['Cumulative Understock'] = df['Cumulative Understock'].fillna(0)
df['Remaining Cumulative Stock'] = df['Cumulative Stock'].fillna(0)

# Adding a 'Rank' column based on the sorted order within each product group
df['Rank'] = df.groupby('Product').cumcount() + 1

df['Status'] = df.apply(
    lambda row: 'Enough' if row['Stock needed'] <= row['Cumulative Overstock'] else 'Not enough',
    axis=1
)

df = df[['Product', 'Company Name', 'Stock', 'Orders', 'Production', 'Stock-Orders', 'Over/Understock',
         'Rank', 'Stock needed', 'Cumulative Overstock', 'Cumulative Understock', 'Remaining Cumulative Stock', 'Status']]

# Sort the DataFrame by Company Name and Cumulative Understock in descending order
df = df.sort_values(by=['Product', 'Rank'], ascending=[True, True])

# Add columns for Giving Companies
unique_companies = df['Company Name'].unique()
giving_columns = [f'Allocation Comp {i + 1}' for i in range(len(unique_companies))]
allocated_columns = [f'Allocated Stock {i + 1}' for i in range(len(unique_companies))]
df[giving_columns] = ''
df[allocated_columns] = 0  # Initialize allocated values to 0

# Function to find giving companies and their allocated values
def find_giving_companies(row):
    if row['Stock needed'] <= 0:
        return [('', 0)] * len(unique_companies)

    giving_companies = []
    remaining_stock_needed = row['Stock needed']

    # Iterate through ranks to find giving companies
    for rank in range(1, row['Rank'] + 1):
        giving_company_row = df[(df['Product'] == row['Product']) & (df['Rank'] == rank)]
        
        if not giving_company_row.empty:
            giving_company = giving_company_row['Company Name'].values
            available_stock = giving_company_row['Over/Understock'].values

            if giving_company.size > 0 and available_stock.size > 0 and giving_company[0] != row['Company Name'] and available_stock[0] > 0:
                # Check if this giving company can cover all remaining stock needed
                if available_stock[0] >= remaining_stock_needed:
                    giving_companies.append((giving_company[0], remaining_stock_needed))
                    remaining_stock_needed = 0
                    break
                else:
                    giving_companies.append((giving_company[0], available_stock[0]))
                    remaining_stock_needed -= available_stock[0]

    # Pad the list with empty strings and zeros if needed
    giving_companies.extend([('', 0)] * (len(unique_companies) - len(giving_companies)))

    return giving_companies[:len(unique_companies)]

# Lists to store giving companies and their allocated values
giving_company_list = []

# Apply the function to each row
for i, row in df.iterrows():
    giving_companies = find_giving_companies(row)
    giving_company_list.append(giving_companies)

# Update the DataFrame with giving companies and their allocated values
for i, comp_list in enumerate(giving_company_list):
    for j, (comp, value) in enumerate(comp_list):
        allocated_stock_col = f'Allocated Stock {j + 1}'
        allocation_comp_col = f'Allocation Comp {j + 1}'

        if value < 0 and comp in df['Company Name'].values:
            # Set negative value for giving company in their row
            giving_company_row = df[(df['Product'] == df.at[i, 'Product']) & (df['Company Name'] == comp)].index
            if not giving_company_row.empty:
                df.at[giving_company_row[0], allocated_stock_col] = value

        # Set positive value for receiving company
        df.at[i, allocated_stock_col] = value
        df.at[i, allocation_comp_col] = comp
        df.at[i, f'Allocated Stock {j + 1}'] = value  # Set negative value for giving company

df['Stock needed after Allocation'] = df.apply(lambda row: row['Stock needed'] - row[allocated_columns].sum() if row['Status'] == 'Not enough' else 0, axis=1)
df['Stock needed after Allocation'] = df.apply(lambda row: -row['Stock needed after Allocation'] if row['Stock needed after Allocation'] > 0 else 0, axis=1)

df

enter image description here这是我创建的Python代码和输出表。
我知道要包括的是一个更新的新的过剩/库存不足列。假设公司B首先将库存赠送给公司A,然后我想更新新的“库存过剩/不足”列,以便公司B的库存比以前少。我现在想使用这个更新的列为下一个需要股票的公司。我想用等级来区分每一列的优先级。因此,排名越高,他们从其他公司获得的股票就越多。
1.超越等级去寻找给予的公司
1.检查给予公司是否有足够的库存
1.检查该给予公司是否可以覆盖所有剩余库存4.,计算新的超额/不足价值
1.使用此新的高/低值检查公司是否仍有足够的库存
1.检查下一家公司的库存是否足够
直到每种产品的库存尽可能地分配。
我尝试了很多方法,但似乎都不起作用。我想它不起作用,因为我需要在给予公司的行分配的值,以及,但我不设法做到这一点..
我希望我的意图是明确的-如果没有随时问:)

gorkyyrv

gorkyyrv1#

下面是我如何从概念上解决这个问题。作为简化,我将生成简化的随机数据,其中"quantity"将是我们试图设置为0的单个值。正值表示库存剩余,负值表示库存需求。公司的“优先级”越高,他们就越有可能满足自己的需求,而不太可能将剩余的资金交给其他人。希望你能看到如何将这种策略转化为你的数据。
首先,我将定义两个小的效用方法,这将帮助我们找到并优先考虑有库存需求和盈余的公司。

def get_givers(companies):
    givers = filter(lambda c: c["quantity"] > 0, companies)
    return sorted(givers, key=lambda c: (c["priority"], -c["quantity"]))

def get_receivers(companies):
    receivers = filter(lambda c: c["quantity"] < 0, companies)
    return sorted(receivers, key=lambda c: (-c["priority"], c["quantity"]))

现在让我们生成一些数据:

##------------------------
## Generate some interesting data
##------------------------
givers, receivers = [], []
while not (givers and receivers):
    companies = [
        {
            "name": f"corp_{i}",
            "priority": random.randint(-10,10),
            "quantity": random.randint(-100,100)
        }
        for i in range(10)
    ]
    givers, receivers = get_givers(companies), get_receivers(companies)
##------------------------

现在,让我们对候选giversreceivers进行验证。请注意,每次我们进行交易时,给予者的数量可能会低于手头有更多库存的同行,对于接受者也是如此。因此,在每笔交易之后,我们将重新评估谁是最佳的交易候选人。这只是我对如何公平分配股票的解释,可能还有其他解释。

print("Companies at Start:")
for company in companies:
    print(f"\t{company}")

##------------------------
## as long as there are companies with stock to give and companies with needs
##------------------------
print("Transactions:")
while givers and receivers:
    giver = givers[0] # the current lowest priority company with the most overage
    receiver = receivers[0] # the current highest priority company with the most need

    amount_available_to_give = giver["quantity"]
    amount_needed_to_get = -receiver["quantity"]
    amount = min(amount_available_to_give, amount_needed_to_get)
    print(f"\t{giver['name']} has {amount_available_to_give}, {receiver['name']} needs {amount_needed_to_get} --> transaction: {amount}")

    receiver["quantity"] += amount
    giver["quantity"] -= amount

    ##------------------------
    ## re-find "best" givers and receivers
    ##------------------------
    givers, receivers = get_givers(givers), get_receivers(receivers)
    ##------------------------
##------------------------

print("Companies at End:")
for company in companies:
    print(f"\t{company}")

这应该会产生类似于:

Companies at Start:
        {'name': 'corp_0', 'priority': -3, 'quantity': -42}
        {'name': 'corp_1', 'priority': 10, 'quantity': -17}
        {'name': 'corp_2', 'priority': 8, 'quantity': -31}
        {'name': 'corp_3', 'priority': -9, 'quantity': 28}
        {'name': 'corp_4', 'priority': 3, 'quantity': -14}
        {'name': 'corp_5', 'priority': 0, 'quantity': 28}
        {'name': 'corp_6', 'priority': 9, 'quantity': 38}
        {'name': 'corp_7', 'priority': 1, 'quantity': 92}
        {'name': 'corp_8', 'priority': -9, 'quantity': -1}
        {'name': 'corp_9', 'priority': -9, 'quantity': 28}
        {'name': 'corp_10', 'priority': 7, 'quantity': -56}
        {'name': 'corp_11', 'priority': -7, 'quantity': -44}
        {'name': 'corp_12', 'priority': -8, 'quantity': 74}
        {'name': 'corp_13', 'priority': -10, 'quantity': -1}
        {'name': 'corp_14', 'priority': -4, 'quantity': -6}
        {'name': 'corp_15', 'priority': 8, 'quantity': 69}
        {'name': 'corp_16', 'priority': 10, 'quantity': 86}
        {'name': 'corp_17', 'priority': 6, 'quantity': -87}
        {'name': 'corp_18', 'priority': -6, 'quantity': 55}
        {'name': 'corp_19', 'priority': -8, 'quantity': -75}
Transactions:
        corp_3 has 28, corp_1 needs 17 --> transaction: 17
        corp_9 has 28, corp_2 needs 31 --> transaction: 28
        corp_3 has 11, corp_2 needs 3 --> transaction: 3
        corp_3 has 8, corp_10 needs 56 --> transaction: 8
        corp_12 has 74, corp_10 needs 48 --> transaction: 48
        corp_12 has 26, corp_17 needs 87 --> transaction: 26
        corp_18 has 55, corp_17 needs 61 --> transaction: 55
        corp_5 has 28, corp_17 needs 6 --> transaction: 6
        corp_5 has 22, corp_4 needs 14 --> transaction: 14
        corp_5 has 8, corp_0 needs 42 --> transaction: 8
        corp_7 has 92, corp_0 needs 34 --> transaction: 34
        corp_7 has 58, corp_14 needs 6 --> transaction: 6
        corp_7 has 52, corp_11 needs 44 --> transaction: 44
        corp_7 has 8, corp_19 needs 75 --> transaction: 8
        corp_15 has 69, corp_19 needs 67 --> transaction: 67
        corp_15 has 2, corp_8 needs 1 --> transaction: 1
        corp_15 has 1, corp_13 needs 1 --> transaction: 1
Companies at End:
        {'name': 'corp_0', 'priority': -3, 'quantity': 0}
        {'name': 'corp_1', 'priority': 10, 'quantity': 0}
        {'name': 'corp_2', 'priority': 8, 'quantity': 0}
        {'name': 'corp_3', 'priority': -9, 'quantity': 0}
        {'name': 'corp_4', 'priority': 3, 'quantity': 0}
        {'name': 'corp_5', 'priority': 0, 'quantity': 0}
        {'name': 'corp_6', 'priority': 9, 'quantity': 38}
        {'name': 'corp_7', 'priority': 1, 'quantity': 0}
        {'name': 'corp_8', 'priority': -9, 'quantity': 0}
        {'name': 'corp_9', 'priority': -9, 'quantity': 0}
        {'name': 'corp_10', 'priority': 7, 'quantity': 0}
        {'name': 'corp_11', 'priority': -7, 'quantity': 0}
        {'name': 'corp_12', 'priority': -8, 'quantity': 0}
        {'name': 'corp_13', 'priority': -10, 'quantity': 0}
        {'name': 'corp_14', 'priority': -4, 'quantity': 0}
        {'name': 'corp_15', 'priority': 8, 'quantity': 0}
        {'name': 'corp_16', 'priority': 10, 'quantity': 86}
        {'name': 'corp_17', 'priority': 6, 'quantity': 0}
        {'name': 'corp_18', 'priority': -6, 'quantity': 0}
        {'name': 'corp_19', 'priority': -8, 'quantity': 0}

相关问题