サプライ・チェイン最適化のためのデータ生成

ここでは,サプライ・チェイン最適化で用いる基本的なランダムデータを生成する.生成されたデータは,csvファイルやExcelのファイルとして保管され,様々な最適化システムで用いられる.

WebアプリのためのExcelデータの生成

Webアプリで用いるExcelのデータをcsvファイルから生成する.

需要予測データ

  • 需要データ: demand_with_promo
  • プロモーションデータ: promo

から

  • 需要予測用のExcelデータ: forecast_small.xlsx

を生成する.

folder = "../data/"
fns = ["demand_with_promo", "promo"]
sheet_name =["demand_with_promo", "promo"]

df ={}
for fn in fns:
    df[fn] = pd.read_csv(folder+fn+".csv", index_col=0)
    df[fn] = df[fn].iloc[:100,:]

with pd.ExcelWriter('forecast_small.xlsx') as writer:
    for i,fn in enumerate(fns):
        df[fn].to_excel(writer, sheet_name=sheet_name[i], index=False)

SCBASデータ

  • 需要データ: demand
  • 製品データ: prod_for_scbas

から

  • SCBAS用のExcelデータ: scbas.xlsx

を生成する.

folder = "../data/"
fns = ["demand", "prod_for_scbas"]
df ={}
for fn in fns:
    df[fn] = pd.read_csv(folder+fn+".csv", index_col=0)
with pd.ExcelWriter('scbas.xlsx') as writer:
    for fn in fns:
        df[fn].to_excel(writer, sheet_name=fn)

MELOS-GFデータ

  • 施設データ: melos-gf
  • 移動時間データ: time

から

  • MELOS-GF用のExcelデータ: melos-gf.xlsx

を生成する.

folder = "../data/melos/"
fns = ["melos-gf", "time"]
df ={}
for fn in fns:
    df[fn] = pd.read_csv(folder+fn+".csv",index_col=0)
with pd.ExcelWriter('melos-gf.xlsx') as writer:
    for fn in fns:
        df[fn].to_excel(writer, sheet_name=fn, index=False)

MELOSデータ

  • 顧客データ: Cust
  • 製品データ: Prod
  • 需要データ: demand
  • 倉庫データ: DC
  • 工場データ: Plnt
  • 工場・製品データ: Plnt-Prod
  • 移動時間データ: time

から

  • MELOS用のExcelデータ: melos.xlsx

を生成する.

folder = "../data/"
fns = ["Cust", "Prod", "demand", "DC", "Plnt", "Plnt-Prod", "time"]
df ={}
for fn in fns:
    df[fn] = pd.read_csv(folder+fn+".csv", index_col=0)
with pd.ExcelWriter('melos.xlsx') as writer:
    for fn in fns:
        df[fn].to_excel(writer, sheet_name=fn, index=False)

MESSAデータ

  • 在庫地点(段階)データ: ssa01
  • 部品展開表データ: ssa_bom01

から

  • MESSA用のExcelデータ: messa.xlsx

を生成する.

folder = "../data/bom/"
fns = ["ssa01", "ssa_bom01"]
sheet_name =["stage", "bom"]
df ={}
for fn in fns:
    df[fn] = pd.read_csv(folder+fn+".csv", index_col=0)
with pd.ExcelWriter('messa.xlsx') as writer:
    for i,fn in enumerate(fns):
        df[fn].to_excel(writer, sheet_name=sheet_name[i], index=False)

OptSeqデータ

  • act: 作業データ
  • res: 資源データ
  • mode: モードデータ
  • act_mode: 作業・モードデータ
  • mode_res: モード・資源データ
  • temp: 時間制約データ
  • non_res : 再生不能資源の右辺定数と制約の向きを表すデータ
  • non_lhs : 再生不能資源の項(係数、作業、モードの組)を表すデータ
  • state : 状態データ

から

  • OptSeq用のExcelデータ: optseq.xlsx

を生成する.

folder = "../data/optseq/"
name ="ex22_"
fns = ["act","mode", "res", "act_mode", "mode_res", "temp", "non_res", "non_lhs", "state" ]
df ={}
for i in fns:
    fn =name+i
    df[fn] = pd.read_csv(folder+fn+".csv", index_col=1)
    df[fn].drop("Unnamed: 0", axis=1, inplace=True)
with pd.ExcelWriter('optseq.xlsx') as writer:
    for i in fns:
        fn =name+i
        df[fn].to_excel(writer, sheet_name=i)

METROデータ

  • node: 作業データ
  • job: 資源データ
  • vehicle: モードデータ
  • shipment: 作業・モードデータ
  • break: モード・資源データ
  • 移動時間データ: time

から

  • METRO用のExcelデータ: metro.xlsx

を生成する.

folder = "../data/metroIV/"
fns = ["node", "job", "vehicle", "shipment", "break", "time"]
df ={}
for fn in fns:
    if fn =="break":
        df[fn] = pd.read_csv(folder+fn+".csv", index_col=1)
    else:
        df[fn] = pd.read_csv(folder+fn+"02.csv", index_col=1)
    df[fn].drop("Unnamed: 0", axis=1, inplace=True)
with pd.ExcelWriter('metro.xlsx') as writer:
    for fn in fns:
        df[fn].to_excel(writer, sheet_name=fn)

OptShiftデータ

  • period : 期間データフ
  • break : 休憩データ
  • day : 日データ
  • job : ジョブデータ
  • staff : スタッフデータ
  • requirement : 必要人数データ

から

  • OptShift用のExcelデータ: optshift.xlsx

を生成する.

folder = "../data/shift/"
fns = ["period", "break", "day", "job", "staff", "requirement"]
df ={}
for fn in fns:
    df[fn] = pd.read_csv(folder+fn+".csv", index_col=1)
    df[fn].drop("Unnamed: 0", axis=1, inplace=True)
with pd.ExcelWriter('optshift.xlsx') as writer:
    for fn in fns:
        df[fn].to_excel(writer, sheet_name=fn)

OptLotデータ

  • lotprod: 製品データ
  • production : 生産情報データ
  • bom : 部品展開表データ
  • plnt-demand : 工場における(期別・製品別の)需要を入れたデータ
  • resource : 資源データ

から

  • OptLot用のExcelデータ: optlot.xlsx

を生成する.

SENDOデータ

  • DC: 施設(倉庫)データ
  • od: 需要(OD)データ

から

  • SENDO用のExcelデータ: sendo.xlsx

を生成する.

顧客データのランダム生成関数 generate_cust

日本の郵便番号データからランダムに地点をサンプリングすることによって、仮想の顧客データを生成する。 社名はFakeパッケージを用いて生成する。 配送計画問題の例題を作成する場合は、あまり遠い地点を選ばないように、都道府県名を引数 prefecture で指定する。 例えば、ロジスティクス・ネットワーク設計モデルやサービスネットワーク設計モデルにおいては、日本全国からランダムに選択し、配送計画モデルにおいては1つの県から選択する。

引数:

  • num_locations: 地点数
  • random_seed: 乱数の種(同じ問題例が欲しい場合には、同じ種を与える。)
  • prefecture: 都道府県名(例えば"千葉県"のような文字列で与える。)省略するか空白の文字列の場合には、日本全国から選択する。
  • no_island: 元になる郵便番号データから離島を除いたものを使う場合 True (既定値)

返値:

  • ランダムに生成された顧客データ

データの列で必須なものは,名前 (name) と緯度・経度 (lat, lon; latitude, Longitudeの略) があれば良いが、リアリティを出すために,郵便番号と住所情報も付加されているが,最適化で必要な列は以下のものだけである.

顧客データの列:

  • name: 名称
  • lat: 緯度
  • lon: 経度

generate_cust[source]

generate_cust(num_locations=10, random_seed=1, prefecture=None, no_island=True)

顧客データをランダムに生成する関数

generate_cust の使用例

cust_df = generate_cust(num_locations = 1000, random_seed = 1, prefecture = None, no_island=True)
#cust_df.to_csv(folder+"case/cust100.csv")
cust_df.head()
zip 都道府県 市区町村 大字 lat lon name
0 6330253 奈良県 宇陀市 榛原萩原 34.538739 135.951724 合同会社前田建設 第 31 支店
1 4670014 愛知県 名古屋市瑞穂区 白羽根町 35.127132 136.937726 有限会社阿部運輸 第 69 支店
2 9860103 宮城県 石巻市 中島 38.533093 141.335295 株式会社村上印刷 第 51 支店
3 893333 北海道 中川郡本別町 山手町 43.128300 143.616592 佐藤印刷合同会社 第 20 支店
4 3220041 栃木県 鹿沼市 三幸町 36.560454 139.742275 合同会社青木水産 第 85 支店

地点間の距離が小さい顧客同士を列挙する関数 enumerate_near_points

同じ緯度・経度をもつ点があると,不具合を起こす場合があるので,事前に確認する関数を準備しておく.

引数:

  • cust_df: 顧客データフレーム
  • max_dis: 緯度経度を座標としたときの直線距離の上限;この値以下の地点の対を列挙する.

返値:

  • 近い点同士の情報を入れたデータフレーム

enumerate_near_points[source]

enumerate_near_points(cust_df, max_dis:float)

地点間の距離が小さい顧客同士を列挙する関数 enumerate_near_points

df = enumerate_near_points(cust_df, 0.001)
df.head()
point1 point2 Euclidean distance Great circle distance
0 合同会社山崎情報 第 93 支店 有限会社佐藤水産 第 57 支店 0.0 0.0 km
1 株式会社藤原鉱業 第 54 支店 長谷川鉱業有限会社 第 25 支店 0.0 0.0 km
2 長谷川水産株式会社 第 98 支店 有限会社田中銀行 第 40 支店 0.0 0.0 km
3 合同会社林電気 第 86 支店 株式会社田中水産 第 40 支店 0.0 0.0 km
4 斎藤食品合同会社 第 66 支店 有限会社山下鉱業 第 49 支店 0.0 0.0 km

顧客データの読み込み

顧客データをランダムに生成すると、リアリティがないデータになる危険性が高い。 日本全体にまんべんなく散りばめた顧客データが欲しい場合には、あらかじめ準備されたデータを用いる。 ここでは、各県の県庁所在地に顧客がいると仮定したデータを用いる。

ファイル名はCust.csvであり、データの列は、名前 (name) と緯度・経度 (lat, lon; latitude, longitudeの略) である。

cust_df = pd.read_csv(folder+"Cust.csv", index_col="id")
cust_df.head()
name lat lon
id
1 札幌市 43.06417 141.34694
2 青森市 40.82444 140.74000
3 盛岡市 39.70361 141.15250
4 仙台市 38.26889 140.87194
5 秋田市 39.71861 140.10250

ProfileReportの作成

pandas_profilingでデータフレームのレポートを作成する.

https://pandas-profiling.github.io/pandas-profiling/docs/master/rtd/index.html

使用例

profile = ProfileReport(large_dataset, minimal=True)
profile.to_file("output.html")
profile = ProfileReport(cust_df, minimal=True)
profile



 

顧客の可視化関数 plot_cust

可視化モジュールPlotlyを使うと、顧客を地図上に表示できる。

引数:

  • cust_df: 顧客データフレーム
  • weight: 顧客の重み(需要量や売上)を表す配列;この量によって点の大きさを変えて描画する. (既定値はNoneで,その場合には同じ大きさで描画する.)

返値:

  • fig: Plotlyの図オブジェクト

plot_cust[source]

plot_cust(cust_df, weight=None)

顧客データフレームを入れると、PlotlyのFigureオブジェクトに地図を入れて返す関数

plot_cust 関数の使用例

上のplot_cust関数の適用例を示す。

total_demand_df = pd.read_csv(folder+"total_demand.csv")
demand_df = pd.pivot_table(total_demand_df, index="cust",values="demand")
cust_df = pd.read_csv(folder+"Cust.csv")
fig = plot_cust(cust_df, demand_df.demand)
plotly.offline.plot(fig);