Monday, 13 October 2025

Machine Learning: Nearest Neighbor (NN) algorithm for stock transfers between warehouses

 

๐Ÿญ Scenario: Nearest Neighbor Algorithm for Warehouse Stock Transfer

Background

A company, GrapheneTech, distributes graphene sheets across 5 regional warehouses in Southeast Asia:

WarehouseLocationAverage Daily Demand (units)Average Lead Time (days)Current Inventory (units)
W1Kuala Lumpur952200
W2Penang75170
W3Johor902110
W4Singapore120350
W5Bangkok605300

Problem

  • Warehouse W4 (Singapore) is facing a stock shortage because of sudden demand increase.

  • The replenishment lead time from the supplier is 7 days, which is too slow.

  • The company wants to transfer stocks from another warehouse temporarily to maintain W4’s 95% service level.

But which warehouse should W4 get help from?


Step 1: Define the Features for Similarity

Each warehouse is described by quantitative features that influence stock movement feasibility:

FeatureMeaning
DDAverage daily demand
LLLead time from supplier
SSCurrent stock level
DistDist
Transportation distance (km) from W4

Suppose distances from W4 are:

From → W4Distance (km)
W1350
W2600
W3250
W51400

Step 2: Represent Each Warehouse as a Feature Vector

Each warehouse = [D,L,S,Dist][D, L, S, Dist]

WarehouseVector [D,L,S,Dist][D, L, S, Dist]
W1[95, 2, 200, 350]
W2[75, 1, 70, 600]
W3[90, 2, 110, 250]
W5[60, 5, 300, 1400]
W4 (Target)[120, 3, 50, 0]

Step 3: Apply Nearest Neighbor (Euclidean Distance)

We compute the “distance” between W4 and every other warehouse:

d(Wi,W4)=(DiD4)2+(LiL4)2+(SiS4)2+(Disti0)2d(W_i, W4) = \sqrt{(D_i - D_4)^2 + (L_i - L_4)^2 + (S_i - S_4)^2 + (Dist_i - 0)^2}

Let’s calculate digit by digit for clarity:


For W1:381.7


For W2:602.0


For W3:258.8


For W5:1423.4


Step 4: Find the Nearest Neighbor

WarehouseDistance to W4Rank
W3 (Johor)258.8๐Ÿฅ‡ Nearest
W1381.72
W2602.03
W51423.44

Nearest Neighbor = W3 (Johor)


Step 5: Decision and Action

Since W3 is most similar and geographically close:

  • W3 can transfer 40 units of graphene sheets to W4 immediately.

  • This transfer minimizes cost and maintains regional balance.


Step 6: Result

Warehouse    Inventory Before    Transfer    Inventory After
W3        110        −40            70
W4        50        +40            90
  • W4’s shortage problem solved.

  • W3 still has sufficient inventory for its demand.


๐Ÿง  Interpretation

The nearest neighbor algorithm here:

  • Quantifies warehouse similarity (in demand, stock, lead time, and distance).

  • Chooses the most appropriate source warehouse for emergency stock transfer.

  • Avoids manual guesswork or arbitrary selection.






Python Code


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# --- Step 1: Define warehouse data ---
data = {
    "Warehouse": ["W1", "W2", "W3", "W5"],   # W4 is the target
    "Demand": [95, 75, 90, 60],
    "LeadTime": [2, 1, 2, 5],
    "Stock": [200, 70, 110, 300],
    "DistanceToW4": [350, 600, 250, 1400]  # distance from each to W4
}

warehouses = pd.DataFrame(data)

# Target warehouse (W4)
target = np.array([120, 3, 50, 0])  # Demand, LeadTime, Stock, Distance
target_name = "W4"

# --- Step 2: Compute Euclidean distances ---
def euclidean_distance(row, target):
    return np.sqrt(((row - target) ** 2).sum())

features = warehouses[["Demand", "LeadTime", "Stock", "DistanceToW4"]].values
warehouses["NN_Distance"] = [euclidean_distance(row, target) for row in features]

# --- Step 3: Find nearest neighbor ---
nearest = warehouses.loc[warehouses["NN_Distance"].idxmin()]

print("Nearest warehouse to W4 (for stock transfer):")
print(nearest[["Warehouse", "NN_Distance"]])

# --- Step 4: Optional: simulate transfer ---
transfer_qty = 40
warehouses.loc[warehouses["Warehouse"] == nearest["Warehouse"], "Stock"] -= transfer_qty
w4_stock_after = 50 + transfer_qty

print("\nAfter transfer:")
print(f"{nearest['Warehouse']} new stock: {int(warehouses.loc[warehouses['Warehouse']==nearest['Warehouse'],'Stock'])}")
print(f"W4 new stock: {w4_stock_after}")

# --- Step 5: Visualization ---
plt.figure(figsize=(8,6))
plt.scatter(warehouses["DistanceToW4"], warehouses["Stock"], color="skyblue", s=100, label="Other Warehouses")

# Highlight nearest neighbor
plt.scatter(nearest["DistanceToW4"], nearest["Stock"], color="orange", s=200, edgecolors="black", label=f"Nearest: {nearest['Warehouse']}")

# Target warehouse (W4)
plt.scatter(0, 50, color="red", s=200, marker="*", label="Target: W4")

# Labels
for _, row in warehouses.iterrows():
    plt.text(row["DistanceToW4"]+10, row["Stock"]+5, row["Warehouse"], fontsize=10)

plt.text(10, 50+10, "W4", color="red", fontsize=11, weight="bold")

plt.title("Graphene Warehouse Stock vs Distance (Nearest Neighbor Transfer)")
plt.xlabel("Distance to W4 (km)")
plt.ylabel("Current Stock (units)")
plt.legend()
plt.grid(True, linestyle="--", alpha=0.6)
plt.tight_layout()
plt.show()


Sunday, 12 October 2025

Experiment: Performing ABC Analysis to Classify Inventory Items by Importance

๐ŸŽฏ Objective:

To classify inventory items into A, B, and C categories based on their annual consumption value, and analyze how focusing control on ‘A’ items can improve inventory efficiency.


๐Ÿงฉ Background Theory:

  • ABC analysis is based on the Pareto principle (80/20 rule):

    • “A” items = ~20% of items contributing ~80% of total value

    • “B” items = ~30% of items contributing ~15% of total value

    • “C” items = ~50% of items contributing ~5% of total value

It helps inventory managers prioritize control, forecasting, and stock review.


๐Ÿงฎ Given Data (for Experiment):

Create a sample dataset of 10–15 inventory items with:

ItemAnnual Demand (units)Unit Cost (USD)
I11,00010
I250050
I3300100
I4100200
I51,2005
I680020
I715080
I860015
I9100300
I1040025

(You can randomize or expand this for larger experiments.)


๐Ÿงญ Experimental Procedure:

  1. Step 1 — Calculate Annual Consumption Value (ACV):

  2. Step 2 — Rank Items by ACV:
    Sort the list in descending order (highest to lowest ACV).

  3. Step 3 — Compute Cumulative % of Total Value and Items:

  4. Step 4 — Classify Items:

    • Class A: Cumulative value up to ~80%

    • Class B: Next ~15%

    • Class C: Remaining ~5%

  5. Step 5 — Plot ABC Curve (optional but powerful):
    Plot:

    • X-axis: Cumulative % of items

    • Y-axis: Cumulative % of value

    → The curve will show steep rise for A items and flat for C items.

  6. Step 6 — Analysis & Decision:

    • How many items fall in A/B/C groups?

    • What % of value does each represent?

    • Suggest control policies:

      • A items: tight control, frequent review, accurate forecasting

      • B items: moderate control

      • C items: simple periodic review, bulk orders


๐Ÿ“ˆ Expected Results:

  • Roughly 2–3 items (20%) in Class A contribute ~80% of total value.

  • 3–4 items (30%) in Class B contribute ~15%.

  • Remaining items (50%) in Class C contribute ~5%.


๐Ÿ” Evaluation / Discussion:

  • Did the results follow the 80/20 rule?

  • What control strategies would reduce total inventory cost?

  • How would misclassification affect stockouts or overstock?


๐Ÿ’ก Extension Ideas (Optional):

  • Repeat using real company data.

  • Combine with XYZ analysis (demand variability).

  • Simulate reordering frequency and service levels by class.








Python Code by Chat GPT

# ๐Ÿงช ABC Analysis Experiment for Inventory Management
import pandas as pd
import matplotlib.pyplot as plt

# --- Step 1: Create Sample Inventory Data ---
data = {
    "Item": ["I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8", "I9", "I10"],
    "Annual_Demand": [1000, 500, 300, 100, 1200, 800, 150, 600, 100, 400],
    "Unit_Cost": [10, 50, 100, 200, 5, 20, 80, 15, 300, 25]
}

df = pd.DataFrame(data)

# --- Step 2: Compute Annual Consumption Value (ACV) ---
df["Annual_Value"] = df["Annual_Demand"] * df["Unit_Cost"]

# --- Step 3: Sort by Annual Value Descending ---
df = df.sort_values(by="Annual_Value", ascending=False).reset_index(drop=True)

# --- Step 4: Compute Cumulative Percentages ---
df["Cumulative_Value"] = df["Annual_Value"].cumsum()
df["Cumulative_Value_Percent"] = 100 * df["Cumulative_Value"] / df["Annual_Value"].sum()
df["Cumulative_Item_Percent"] = 100 * (df.index + 1) / len(df)

# --- Step 5: Classify A, B, C ---
def classify(row):
    if row["Cumulative_Value_Percent"] <= 80:
        return "A"
    elif row["Cumulative_Value_Percent"] <= 95:
        return "B"
    else:
        return "C"

df["Class"] = df.apply(classify, axis=1)

# --- Display the ABC Table ---
print("=== ABC Analysis Results ===")
print(df[["Item", "Annual_Demand", "Unit_Cost", "Annual_Value",
          "Cumulative_Value_Percent", "Class"]])

# --- Step 6: Plot the ABC Curve ---
plt.figure(figsize=(8,5))
plt.plot(df["Cumulative_Item_Percent"], df["Cumulative_Value_Percent"],
         marker='o', linestyle='-', color='blue')

# Add grid and labels
plt.title("ABC Analysis for Graphene Inventory")
plt.xlabel("Cumulative % of Items")
plt.ylabel("Cumulative % of Value")
plt.grid(True)

# Annotate A, B, C zones
plt.axhline(y=80, color='green', linestyle='--', label='A/B boundary (80%)')
plt.axhline(y=95, color='orange', linestyle='--', label='B/C boundary (95%)')
plt.legend()

plt.show()







Thursday, 9 October 2025

Linear Programming for Inventory Scenario Which Maximize Profit While Facing Constraints

Problem Statement

A retail store stocks two products: Product A (tablets) and Product B (smartwatches). The objective is to maximize profit by determining the optimal number of units to stock, subject to storage and budget constraints.Decision Variables
  • ( x ): Number of units of Product A.
  • ( y ): Number of units of Product B.
Objective FunctionMaximize profit, where each unit of Product A and Product B yields $300:
Maximize Z = 300x + 300yConstraintsStorage Constraint: The warehouse has 600 square feet. Product A requires 4 square feet per unit, and Product B requires 6 square feet per unit.                          
    
4x+6y600

Budget Constraint: The budget is $30,000. Product A costs $300 per unit, and Product B costs $200 per unit.

x+200y30,000

Non-negativity Constraints:

x0,y0
Step-by-Step SolutionWe’ll solve this using the graphical method by identifying the feasible region, finding its vertices, and evaluating the objective function at each vertex to determine the maximum profit.Step 1: Graph the ConstraintsConvert the inequalities to equalities to find the boundary lines:
  1. Storage Constraint:
    2x + 3y = 300
    • When
      x = 0
      :
      3y = 300 \implies y = 100
      . Point: ( (0, 100) ).
    • When
      y = 0
      :
      2x = 300 \implies x = 150
      . Point: ( (150, 0) ).
  2. Budget Constraint:
    3x + 2y = 300
    • When
      x = 0
      :
      2y = 300 \implies y = 150
      . Point: ( (0, 150) ).
    • When
      y = 0
      :
      3x = 300 \implies x = 100
      . Point: ( (100, 0) ).
Step 2: Find the Intersection of ConstraintsTo find the "middle" point where the constraints intersect:




2x+3y=300
3x+2y=300

Solve simultaneously:
  • Multiply (1) by 2:
    4x + 6y = 600
  • Multiply (2) by 3:
    9x + 6y = 900
  • Subtract:
    (9x + 6y) - (4x + 6y) = 900 - 600
    5x = 300 \implies x = 60
  • Substitute
    x = 60
    into (2):
    3(60) + 2y = 300 \implies 180 + 2y = 300 \implies 2y = 120 \implies y = 60
    .
Intersection point: ( (60, 60) ).Step 3: Define the Feasible RegionThe feasible region is where both constraints and non-negativity conditions are satisfied:
  • 2x + 3y 300
  • 3x + 2y 300
  • x0,y0

  • Find vertices of the feasible region:
    • Origin: ( (0, 0) ).
    • Storage intercept (x = 0): ( (0, 100) ) from
      2(0) + 3y = 300
      .
    • Budget intercept (y = 0): ( (100, 0) ) from
      3x + 2(0) = 300
      .
    • Intersection: ( (60, 60) ).
    The feasible region is a quadrilateral with vertices: ( (0, 0) ), ( (0, 100) ), ( (60, 60) ), ( (100, 0) ).Step 4: Evaluate the Objective FunctionEvaluate
    Z = 300x + 300y
    at each vertex:
    1. (0, 0):
      Z = 300(0) + 300(0) = 0
    2. (0, 100):
      Z = 300(0) + 300(100) = 30,000
    3. (100, 0):
      Z = 300(100) + 300(0) = 30,000
    4. (60, 60):
      Z = 300(60) + 300(60) = 18,000 + 18,000 = 36,000
    The maximum value of
    Z = 36,000
    occurs at ( (60, 60) ).
    Final AnswerThe store should stock 60 units of Product A and 60 units of Product B to maximize profit, yielding a profit of $36,000. This solution is at the intersection of the storage and budget constraints, ensuring the optimal point is in the "middle" and both constraints actively shape the feasible region without the budget constraint being stricter.





    Python Code from Grok
    import numpy as np
    import matplotlib.pyplot as plt
    
    # Define the range for x (Product A)
    x = np.linspace(0, 200, 400)
    
    # Constraint 1: Storage (2x + 3y <= 300)
    y1 = (300 - 2 * x) / 3
    
    # Constraint 2: Budget (3x + 2y <= 300)
    y2 = (300 - 3 * x) / 2
    
    # Objective function at optimal point Z = 36,000 (at x=60, y=60)
    # Z = 300x + 300y => y = -x + Z/300
    y_opt = -x + 36000 / 300  # Z = 36,000
    
    # Plotting
    plt.figure(figsize=(10, 8))
    
    # Plot constraints
    plt.plot(x, y1, label='2x + 3y = 300 (Storage)', color='blue')
    plt.plot(x, y2, label='3x + 2y = 300 (Budget)', color='green')
    
    # Fill feasible region (y <= min(y1, y2) and y >= 0)
    y_feasible = np.minimum(y1, y2)
    plt.fill_between(x, 0, y_feasible, where=(y_feasible >= 0), color='gray', alpha=0.3, label='Feasible Region')
    
    # Plot objective function at optimal point
    plt.plot(x, y_opt, '--', label='Z = 300x + 300y = 36,000 (Optimal)', color='red')
    
    # Plot vertices
    vertices = [(0, 0), (0, 100), (60, 60), (100, 0)]
    for vertex in vertices:
        plt.plot(vertex[0], vertex[1], 'ro')  # Red dots for vertices
        plt.text(vertex[0] + 2, vertex[1] + 2, f'({vertex[0]}, {vertex[1]})', fontsize=10)
    
    # Highlight optimal point
    optimal = (60, 60)
    plt.plot(optimal[0], optimal[1], 'y*', markersize=15, label='Optimal Point (60, 60)')
    
    # Set labels and limits
    plt.xlabel('Units of Product A (x)')
    plt.ylabel('Units of Product B (y)')
    plt.title('Linear Programming: Inventory Management')
    plt.xlim(-10, 160)
    plt.ylim(-10, 160)
    plt.grid(True)
    plt.legend()
    
    # Show plot
    plt.show()












    Machine Learning: Nearest Neighbor (NN) algorithm for stock transfers between warehouses

      ๐Ÿญ Scenario: Nearest Neighbor Algorithm for Warehouse Stock Transfer Background A company, GrapheneTech , distributes graphene sheets a...