SCMOPTは様々なシステム(モジュール)を有機的に結合したものである.ここでは,様々なモジュールで使用する共通部品を定義する.
import toml
output_file = "secrets.toml"
with open("serviceAccountKey.json") as json_file:
json_text = json_file.read()
config = {"textkey": json_text}
toml_config = toml.dumps(config)
with open(output_file, "w") as target:
target.write(toml_config)
Geocodingのためのデータ
以下から入手可能な全国の町丁目レベル(190,165件)の住所データをもとに緯度・経度の辞書を準備する.
https://github.com/geolonia/japanese-addresses
また,郵便番号データから緯度・経度と住所が得られるような辞書も準備する.
import pickle
with open('geocode.dump', 'wb') as f:
pickle.dump(pref_dic, f)
import pickle
with open('../data/geocode.dump', 'rb') as f:
pref_dic = pickle.load(f)
pref_dic["千葉県"]["八千代市"]['勝田台一丁目']
import pickle
with open('../data/zipcode.dump', 'rb') as f:
zip_dic = pickle.load(f)
zip_dic[2760049]
wb = make_excel_geocoding()
wb.save("geocoding-templete.xlsx")
wb = load_workbook("geocoding-templete.xlsx")
ws = wb.active
for i, row in enumerate(ws.iter_rows(min_row=2)):
#inf = zip_dic[int(row[0].value)]
#print(inf) #dropdown list で選択+書き込み
D = pref_dic
for j, cell in enumerate(row[1:]):
#print(j, cell.value)
if cell.value is not None:
try:
D = D[cell.value] #dic
except:
print(D)
#候補を示す
if isinstance(D, tuple):
ws.cell(i+2,6).value = D[0]
ws.cell(i+2,7).value = D[1]
else:
break
wb.save("geocoding-ex1.xlsx")
address ="千葉県八千代市緑が丘一丁目"
address_split(address)
wb = load_workbook("geocoding-ex1.xlsx")
wb = fill_separate_address(wb)
wb.save("geocoding-ex3.xlsx")
print( time_delta( dt.datetime(2020,1,2,10,0), dt.datetime(2020,1,1,0,0)) )
print( time_delta( dt.time(10,0), dt.time(11,0)) )
print( time_delta( dt.time(12,0), dt.time(6,0)) )
print( add_seconds( dt.datetime(2020,1,1,10,0), 1000) )
print( add_seconds( dt.time(10,0), 1000) )
地点(顧客)間の距離と移動時間の計算関数 compute_durations
OSRMを必要とする.
引数:
- cust_df: 顧客データフレーム(名称と緯度・経度情報をもつデータフレーム)
- plnt_df: 工場データフレーム(オプション;既定値 None)
- toll: 有料道路が使用可のときTrue(既定値 True)
- ferry: フェリーが使用可のときTrue(既定値 True) (TODO: OSRMの前処理時に,car.luaファイルを以下を修正する必要がある.)
excludable = Sequence {
Set {'toll'},
Set {'motorway'},
Set {'ferry'},
Set {'ferry', 'toll'})
},
- host: ホスト名;既定値は "localhost"
返値:
- durations: 地点間の移動時間(計算に失敗した場合には大きな数字が入っている.)
- distances: 地点間の道路距離(計算に失敗した場合には大きな数字が入っている.)
- node_df: 点のデータフレーム(顧客もしくは顧客と工場を結合したもの)
# cust_df = pd.read_csv(folder+"Cust.csv")
# durations, distances, node_df = compute_durations(cust_df, toll=True, host="localhost")
# print(durations[0])
cust_df = pd.read_csv(folder+"Cust.csv")
durations, distances, node_df = compute_durations(cust_df, toll=False, host=host)
print(sum(durations[0]))
time_df = make_time_df(node_df, durations, distances)
time_df.head()
#time_df.to_csv(folder + "melos/time.csv")
time_df = pd.read_csv(folder + "melos/time.csv")
durations, distances = make_durations(time_df)
distances
n_legends = 12
x = np.arange(0, 1, .01)
y = np.random.rand(n_legends, 100) + \
np.arange(n_legends).reshape(-1, 1)
colors = get_colorpalette('pastel', n_legends)
data = [
go.Scatter(
x=x, y=y[i], name=f'Legend {i}',
marker={'color':colors[i]})
for i in range(n_legends)]
fig = go.Figure(data=data)
#plotly.offline.plot(fig);
グラフクラス SCMGraph
サプライ・チェインのためのグラフクラス
SCMGraphクラスは,networkXの有向グラフクラスDiGraphから派生したものであり,以下のメソッドが追加されている.
- random_directed_tree(n=1, seed=None):ランダムな有向木を生成する.引数は点数n(既定値1)と擬似乱数の種seed(既定値None).- layered_network(num_in_layer=None, p=0.5, seed=None): ランダムな層型の有向グラフを生成する. 引数num_in_layerは,各層内の点数を入れたリストで既定値は[1,1],pは枝の発生確率で既定値は0.5,seedは擬似乱数の種である.
- layout(): 有向グラフを描画する際の座標を返す関数.返値は点の名称をキーとし,点のx,y座標を値とした辞書.
- down_order(): 閉路を含まない有向グラフに対して,供給地点側から需要地点側の順番で点を返すジェネレータ関数.
- up_order(): 閉路を含まない有向グラフに対して,需要地点側から供給地点側の順番で点を返すジェネレータ関数.
- dp_order(): 有向木に対して,葉から順番に点を生成するジェネレータ関数. 安全在庫配置問題に対する動的最適化で用いる.
- bfs(start): 点startを開始点として,広がり優先探索で点を生成するジェネレータ関数.
- find_ancestors(): 各点から到達可能な点の集合(自分自身を含む)を保持するリスト.点の順序はup_orderとする.
%matplotlib inline
G = SCMGraph()
G.layered_network(num_in_layer=[3, 2, 3], p=0.4, seed=123)
pos = G.layout()
nx.draw(G, pos=pos, with_labels=True, node_color="Yellow")
print("up order")
for i in G.up_order():
print(i, end=" ")
print("down order")
for i in G.down_order():
print(i, end=" ")
print("dp order")
for i in G.dp_order():
print(i, end=" ")
G.remove_edge(0, 3)
for i in G.dp_order():
print(i, end=" ")
print("bfs")
for i in G.bfs(1):
print(i, end=" ")
print("ancestor")
G.find_ancestors()
pos
net = pyvis.network.Network(height='500px', width='800px', directed = True, notebook = True,
bgcolor='#ffffff', font_color=False, layout=True, heading='Sample')
level =[]
pos = G.layout()
for i in pos:
x,y = pos[i]
level.append(x)
for i in G.nodes():
net.add_node(i, label=f"node{i}", level=level[i], shape="box", color="yellow")
#net.add_node(i, label=f"node{i}", x=pos[i][1], y=pos[i][0], shape="box", color="yellow")
for (i,j) in G.edges():
net.add_edge(i,j, value=i*j, title=f"Edge{i},{j}",color="green", dashes=False, selectionWidth=10, arrowStrikethrough=False)
net.show("example.html")
G = SCMGraph()
G.random_directed_tree(10, seed=1)
pos = G.layout()
nx.draw(G, pos=pos, with_labels=True, node_color="Yellow")