Cong-Truong-202 / BIU-DATA

0 stars 0 forks source link

Identify products with low stock levels #5

Open Cong-Truong-202 opened 3 months ago

Cong-Truong-202 commented 3 months ago

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

Đọc dữ liệu từ các tệp CSV

products_df = pd.read_csv("products.csv") orders_df = pd.read_csv("orders.csv") orderdetails_df = pd.read_csv("orderdetail.csv")

=================================================================================================

----------------------------------XÁC ĐỊNH MẶC HÀNG CẦN NHẬP LOẠI I ------------------------------

Sản phẩm có mức tồn kho thấp hơn mức tồn kho an toàn cần nhập mặt hàng này

để đảm bảo việc vận hành của cửa hàng

================================================================================================

Công thức tính tồn kho an toàn

Phương pháp độ lệch chuẩn với biến động về nhu cầu hàng hóa

Điểm Z Độ lệch chuẩn của nhu cầu Căn bậc hai của Thời gian giao hàng trung bình

----------------Tính nhu cầu trung bình cho 1 tuần => độ lệch chuẩn ----------------------------

Nhóm xác định chu kỳ phân tích là trong 1 tuần 7 ngày

Chuyển đổi cột 'orderDate' sang kiểu dữ liệu datetime

orders_df['orderDate'] = pd.to_datetime(orders_df['orderDate'])

Hợp nhất các bảng orders và orderdetail

merged_df = orders_df.merge(orderdetails_df, on='orderNumber')

Nhóm dữ liệu theo productCode và tuần, tính tổng số lượng đặt hàng

grouped_data = merged_df.groupby(["productCode", pd.Grouper(key='orderDate', freq='W')])["quantityOrdered"].sum().reset_index()

Tính giá trị trung bình đặt hàng cho mỗi nhóm

average_orders = grouped_data.groupby("productCode")["quantityOrdered"].mean().reset_index()

Hợp bảng products_df với average_orders theo productCode => safetystock_df

safetystock_df = pd.merge(products_df, average_orders, on="productCode", how="inner")

Rename column

safetystock_df.rename(columns={"quantityOrdered": "averageOrder"}, inplace=True)

-------------------------Tính toán độ lệch chuẩn nhu cầu-----------------------------------

Tính độ lệch chuẩn cho từng sản phẩm

standard_deviation_of_demand_per_product = grouped_data.groupby("productCode")["quantityOrdered"].std().reset_index()

Thêm một cột mới vào DataFrame để lưu trữ độ lệch chuẩn

safetystock_df["standardDeviation"] = standard_deviation_of_demand_per_product["quantityOrdered"]

=======================================

Thêm cột mới quantityInStock từ products_df vào DataFrame safetystock_df

safetystock_df = safetystock_df.merge(products_df[['productCode', 'quantityInStock']], how='left', on='productCode')

-----------------Thời gian giao hàng (giả định)------------------------

Giá trị trung bình được tính theo tuần nên mục này lead_time =7 => 1 (tuần)

lead_time = 7

-----------------Xác định mức xác định lượng hàng dự trữ an toàn-------------------------------

cần được giữ để đạt được mức dịch vụ mong muốn

Nhóm muốn mức dịch vụ mong muốn 95.05% nghĩa là 95.05% đơn hàng có thể được đáp ứng đầy đủ từ kho hàng.

Z = 1.65

Tạo DataFrame mới để lưu trữ mức tồn kho an toàn cho mỗi sản phẩm

safety_stock_data = []

Lặp qua từng sản phẩm để tính toán mức tồn kho an toàn tương ứng

for index, row in safetystock_df.iterrows(): product_code = row["productCode"] average_order = row["averageOrder"] standard_deviation = row["standardDeviation"]

# Tính toán mức tồn kho an toàn
safety_stock = Z * standard_deviation * math.sqrt(lead_time)

# Thêm dữ liệu vào danh sách safety_stock_data
safety_stock_data.append({"productCode": product_code, "averageOrder": average_order, "safetyStock": safety_stock})

Tạo DataFrame từ dữ liệu vừa tính toán được

safety_stock_df = pd.DataFrame(safety_stock_data)

Merge DataFrame safetystock_df với safety_stock_df để thêm cột 'safetyStock'

safetystock_df = pd.merge(safetystock_df, safety_stock_df[['productCode', 'safetyStock']], on='productCode', how='left')

Tạo một cột mới để lưu trữ thông tin về việc mức tồn kho hiện tại có thấp hơn mức tồn kho an toàn không

safetystock_df["belowSafetyStock"] = safetystock_df["quantityInStock_x"] < safetystock_df["safetyStock"]

Xuất kết quả ra file CSV mới

safetystock_df.to_csv('safetystock_df.csv', index=False)

Hiển thị biểu đồ của lượng đặt hàng trung bình

plt.figure(figsize=(10, 6)) plt.scatter(safetystock_df['productCode'], safetystock_df['averageOrder']) plt.xlabel('Product Code') plt.ylabel('Average Order') plt.title('Biểu đồ thể hiện lượng đặt hàng trung bình hàng tuần') plt.show()

Hiển thị biểu đồ cho tồn kho an toàn

plt.figure(figsize=(10, 6)) plt.scatter(safetystock_df['productCode'], safetystock_df['safetyStock']) plt.xlabel('Product Code') plt.ylabel('Safety Stock') plt.title('Biểu đồ thể hiện mức tồn kho an toàn') plt.show()

Tạo biểu đồ so sánh các cột với mức tồn kho an toàn

below_safety_stock_products = safetystock_df[safetystock_df["belowSafetyStock"]]

Chuẩn bị dữ liệu cho biểu đồ cột nhóm

product_codes = below_safety_stock_products['productCode'] quantity_in_stock = below_safety_stock_products['quantityInStock_x'] safety_stock = below_safety_stock_products['safetyStock']

x = np.arange(len(product_codes)) # vị trí cho các nhóm width = 0.35 # chiều rộng của mỗi thanh

fig, ax = plt.subplots(figsize=(12, 6)) bars1 = ax.bar(x - width/2, quantity_in_stock, width, label='Quantity In Stock', color='blue') bars2 = ax.bar(x + width/2, safety_stock, width, label='Safety Stock', color='orange')

ax.set_xlabel('Product Code') ax.set_ylabel('Quantity') ax.set_title('Biểu đồ thể hiện các sản phẩm có mức tồn kho thấp hơn mức tồn kho an toàn') ax.set_xticks(x) ax.set_xticklabels(product_codes, rotation=90) ax.legend()

def add_labels(bars): for bar in bars: height = bar.get_height() ax.annotate('{}'.format(height), xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3), textcoords="offset points", ha='center', va='bottom')

add_labels(bars1) add_labels(bars2)

plt.tight_layout() plt.show()

=================================================================================================

----------------------------------XÁC ĐỊNH MẶC HÀNG CẦN NHẬP LOẠI II ------------------------------

Sản phẩm có mức tồn kho thấp hơn mức tồn kho an toàn cần nhập mặt hàng này

để đảm bảo việc vận hành của cửa hàng

================================================================================================

Công thức tính tồn kho an toàn

Phương pháp độ lệch chuẩn với biến động về nhu cầu hàng hóa

Điểm Z Độ lệch chuẩn của nhu cầu Căn bậc hai của Thời gian giao hàng trung bình

----------------Tính nhu cầu trung bình cho 1 tuần => độ lệch chuẩn ----------------------------

Nhóm xác định chu kỳ phân tích là trong 1 tuần 7 ngày

-------------------------Tính toán độ lệch chuẩn nhu cầu-----------------------------------

-----------------Thời gian giao hàng (giả định)------------------------

Giá trị trung bình được tính theo tuần nên mục này lead_time =7 => 1 (tuần)

lead_time = 7

-----------------Xác định mức xác định lượng hàng dự trữ an toàn-------------------------------

cần được giữ để đạt được mức dịch vụ mong muốn

Nhóm muốn mức dịch vụ mong muốn 99.00% nghĩa là 99.00% đơn hàng có thể được đáp ứng đầy đủ từ kho hàng.

Z2 = 2.326

Sắp xếp sản phẩm theo lượng đặt hàng trung bình hàng tuần từ cao đến thấp

top_products = average_orders.sort_values(by='quantityOrdered', ascending=False).head(20)

Lọc dữ liệu của top 20 sản phẩm từ grouped_data

top_grouped_data = grouped_data[grouped_data['productCode'].isin(top_products['productCode'])]

Tính standard_deviation cho top 20 sản phẩm

top_standard_deviation = top_grouped_data.groupby("productCode")["quantityOrdered"].std().reset_index()

Merge DataFrame products_df với top_products để chỉ lấy thông tin của top sản phẩm

top_products_df = pd.merge(products_df, top_products[['productCode', 'quantityOrdered']], on='productCode', how='inner')

Tính toán tồn kho an toàn cho các sản phẩm top

safety_stock_data_top = []

for index, row in top_products_df.iterrows(): product_code = row["productCode"] average_order = row["quantityOrdered"]

# Lấy standard_deviation tương ứng với sản phẩm hiện tại
product_std = top_standard_deviation[top_standard_deviation['productCode'] == product_code]['quantityOrdered'].iloc[0]

# Tính toán mức tồn kho an toàn
safety_stock_top = Z2 * product_std * math.sqrt(lead_time)

# Thêm dữ liệu vào danh sách safety_stock_data_top
safety_stock_data_top.append({"productCode": product_code, "averageOrder": average_order, "safetyStock": safety_stock_top})

Tạo DataFrame từ dữ liệu vừa tính toán được

safetyStock2_df = pd.DataFrame(safety_stock_data_top)

Merge DataFrame products_df với safetyStock2_df để thêm cột 'safetyStock'

safetyStock2_df = pd.merge(top_products_df, safetyStock2_df[['productCode', 'safetyStock']], on='productCode', how='left')

Tạo một cột mới để lưu trữ thông tin về việc mức tồn kho hiện tại có thấp hơn mức tồn kho an toàn không

safetyStock2_df["belowSafetyStock"] = safetyStock2_df["quantityInStock"] < safetyStock2_df["safetyStock"]

Xuất kết quả ra file CSV mới

safetyStock2_df.to_csv('safetyStock2_df.csv', index=False)

Chuẩn bị dữ liệu

product_codes = safetyStock2_df['productCode'] quantity_in_stock = safetyStock2_df['quantityInStock'] safety_stock = safetyStock2_df['safetyStock']

Thiết lập vị trí cho các cột

x = np.arange(len(product_codes)) # vị trí cho các nhóm width = 0.35 # chiều rộng của mỗi cột

Vẽ biểu đồ cột

fig, ax = plt.subplots(figsize=(12, 6)) bars1 = ax.bar(x - width/2, quantity_in_stock, width, label='Quantity In Stock', color='blue') bars2 = ax.bar(x + width/2, safety_stock, width, label='Safety Stock', color='orange')

Thiết lập nhãn và tiêu đề

ax.set_xlabel('Product Code') ax.set_ylabel('Quantity') ax.set_title('Biểu đồ thể hiện tồn kho và tồn kho an toàn của TOP 20') ax.set_xticks(x) ax.set_xticklabels(product_codes, rotation=90) # Xoay nhãn trục x cho dễ đọc ax.legend()

Hiển thị giá trị trên các cột

def add_labels(bars): for bar in bars: height = bar.get_height() ax.annotate('{}'.format(height), xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3), # 3 points vertical offset textcoords="offset points", ha='center', va='bottom')

add_labels(bars1) add_labels(bars2)

Hiển thị biểu đồ

plt.tight_layout() plt.show()

Lọc các sản phẩm dưới mức tồn kho an toàn

below_safety_stock_df = safetyStock2_df[safetyStock2_df["belowSafetyStock"]]

Biểu đồ thể hiện so sánh mức tồn kho so với mức tồn kho an toàn

Chuẩn bị dữ liệu cho biểu đồ cột

product_codes = below_safety_stock_df['productCode'] quantity_in_stock = below_safety_stock_df['quantityInStock'] safety_stock = below_safety_stock_df['safetyStock']

Thiết lập vị trí cho các cột

x = np.arange(len(product_codes)) # vị trí cho các nhóm width = 0.35 # chiều rộng của mỗi cột

Vẽ biểu đồ cột

fig, ax = plt.subplots(figsize=(12, 6)) bars1 = ax.bar(x - width/2, quantity_in_stock, width, label='Quantity In Stock', color='blue') bars2 = ax.bar(x + width/2, safety_stock, width, label='Safety Stock', color='orange')

Thiết lập nhãn và tiêu đề

ax.set_xlabel('Product Code') ax.set_ylabel('Quantity') ax.set_title('Biểu dồ thể hiện mức tồn kho thấp hơn mức tồn kho an toàn ') ax.set_xticks(x) ax.set_xticklabels(product_codes, rotation=90) # Xoay nhãn trục x cho dễ đọc ax.legend()

Hiển thị giá trị trên các cột

def add_labels(bars): for bar in bars: height = bar.get_height() ax.annotate('{}'.format(height), xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3), textcoords="offset points", ha='center', va='bottom')

add_labels(bars1) add_labels(bars2)

Hiển thị biểu đồ

plt.tight_layout() plt.show()

Lọc các sản phẩm dưới mức tồn kho an toàn từ DataFrame safetystock_df

below_safety_stock_products_type1 = safetystock_df[safetystock_df["belowSafetyStock"]]

Lọc các sản phẩm dưới mức tồn kho an toàn từ DataFrame safetyStock2_df

below_safety_stock_products_type2 = safetyStock2_df[safetyStock2_df["belowSafetyStock"]]

Đưa ra số lượng từng sản phẩm dưới mức tồn kho an toàn của 2 loại dạng list

products_below_safety_stock_type1 = below_safety_stock_products_type1[['productCode', 'quantityInStock_x', 'safetyStock']] products_below_safety_stock_type2 = below_safety_stock_products_type2[['productCode', 'quantityInStock', 'safetyStock']]

Đổi tên các cột của products_below_safety_stock_type2 để đồng nhất với products_below_safety_stock_type1

products_below_safety_stock_type2 = products_below_safety_stock_type2.rename(columns={'quantityInStock': 'quantityInStock_x'})

Xác định các sản phẩm trùng lặp

duplicate_products = products_below_safety_stock_type1['productCode'][products_below_safety_stock_type1['productCode'].isin(products_below_safety_stock_type2['productCode'])]

Loại bỏ các sản phẩm từ loại 1 nếu chúng trùng với sản phẩm từ loại 2

products_below_safety_stock_type1 = products_below_safety_stock_type1[~products_below_safety_stock_type1['productCode'].isin(duplicate_products)]

Kết hợp cả hai loại sản phẩm dưới mức tồn kho an toàn vào một DataFrame

combined_products_below_safety_stock = pd.concat([products_below_safety_stock_type1, products_below_safety_stock_type2])

Tính số lượng cần nhập

combined_products_below_safety_stock['quantityToOrder'] = combined_products_below_safety_stock['safetyStock'] - combined_products_below_safety_stock['quantityInStock_x']

Lọc chỉ lấy cột productCode, safetyStock, và quantityToOrder

final_df = combined_products_below_safety_stock[['productCode', 'safetyStock', 'quantityToOrder']]

Loại bỏ các hàng có giá trị quantityToOrder âm hoặc bằng không

final_df = final_df[final_df['quantityToOrder'] > 0]

Hiển thị bảng kết quả

print(final_df.to_string(index=False))

Thông báo về các sản phẩm trùng lặp

if not duplicate_products.empty: duplicate_products_str = ", ".join(duplicate_products.astype(str)) # Chuyển đổi giá trị thành chuỗi print("Các sản phẩm trùng lặp là:", duplicate_products_str) else: print("Không có sản phẩm trùng lặp.")

Chuẩn bị dữ liệu cho biểu đồ

product_codes = final_df['productCode'] quantity_to_order = final_df['quantityToOrder']

Thiết lập vị trí cho các thanh

x = np.arange(len(product_codes)) width = 0.35

Vẽ biểu đồ cột

fig, ax = plt.subplots(figsize=(12, 6)) bars = ax.bar(x, quantity_to_order, width, label='Quantity To Order', color='green')

Thiết lập nhãn và tiêu đề

ax.set_xlabel('Product Code') ax.set_ylabel('Quantity To Order') ax.set_title('Biểu đồ thể hiện số lượng cần nhập của các sản phẩm dưới mức tồn kho an toàn') ax.set_xticks(x) ax.set_xticklabels(product_codes, rotation=90) ax.legend()

Hiển thị giá trị trên các thanh

def add_labels(bars): for bar in bars: height = bar.get_height() ax.annotate('{}'.format(height), xy=(bar.get_x() + bar.get_width() / 2, height), xytext=(0, 3), textcoords="offset points", ha='center', va='bottom')

add_labels(bars)

Hiển thị biểu đồ

plt.tight_layout() plt.show()