|
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 103,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import pandas as pd\n",
|
|
"import numpy as np\n",
|
|
"import os\n",
|
|
"import sumolib\n",
|
|
"import random\n",
|
|
"from tqdm import tqdm\n",
|
|
"from datetime import datetime"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# A. 이동류 매칭"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 104,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_match1():\n",
|
|
" '''\n",
|
|
" 신호 DB에는 매 초마다 이동류정보가 업데이트 된다. 그리고 이 이동류정보를 매 5초마다 불러와서 사용하게 된다.\n",
|
|
" '../Data/tables/move/'에는 5초마다의 이동류정보가 저장되어 있다.\n",
|
|
"\n",
|
|
" return : 통합된 이동류정보\n",
|
|
" - 모든 inter_no(교차로번호)에 대한 A, B링 현시별 이동류정보\n",
|
|
"\n",
|
|
" match1을 만드는 데 시간이 소요되므로 한 번 만들어서 저장해두고 저장해둔 것을 쓴다.\n",
|
|
" '''\n",
|
|
" # [이동류번호] 불러오기 (약 1분의 소요시간)\n",
|
|
" path_move = '../Data/tables/move/'\n",
|
|
" csv_moves = os.listdir(path_move)\n",
|
|
" moves = [pd.read_csv(path_move + csv_move, index_col=0) for csv_move in tqdm(csv_moves)]\n",
|
|
" match1 = pd.concat(moves).drop_duplicates().sort_values(by=['inter_no','phas_A','phas_B']).reset_index(drop=True)\n",
|
|
" match1.to_csv('../Intermediates/match1.csv')\n",
|
|
" return match1"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 105,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_match2(match1):\n",
|
|
" '''\n",
|
|
" match1을 계층화함.\n",
|
|
" - match1의 컬럼 : inter_no, phas_A, phas_B, move_A, move_B\n",
|
|
" - match2의 컬럼 : inter_no, phase_no, ring_type, move_no\n",
|
|
" '''\n",
|
|
" # 계층화 (inter_no, phas_A, phas_B, move_A, move_B) -> ('inter_no', 'phase_no', 'ring_type', 'move_no')\n",
|
|
" matchA = match1[['inter_no', 'phas_A', 'move_A']].copy()\n",
|
|
" matchA.columns = ['inter_no', 'phase_no', 'move_no']\n",
|
|
" matchA['ring_type'] = 'A'\n",
|
|
" matchB = match1[['inter_no', 'phas_B', 'move_B']].copy()\n",
|
|
" matchB.columns = ['inter_no', 'phase_no', 'move_no']\n",
|
|
" matchB['ring_type'] = 'B'\n",
|
|
" match2 = pd.concat([matchA, matchB]).drop_duplicates()\n",
|
|
" match2 = match2[['inter_no', 'phase_no', 'ring_type', 'move_no']]\n",
|
|
" match2 = match2.sort_values(by=list(match2.columns))\n",
|
|
" return match2"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 106,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_match3(match2):\n",
|
|
" '''\n",
|
|
" 각 movement들에 방향(진입방향, 진출방향)을 매칭시켜 추가함.\n",
|
|
" - match2의 컬럼 : inter_no, phase_no, ring_type, move_no\n",
|
|
" - match3의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir\n",
|
|
"\n",
|
|
" nema : \n",
|
|
" - 컬럼 : move_no, inc_dir, out_dir\n",
|
|
" - 모든 종류의 이동류번호에 대하여 진입방향과 진출방향을 매칭시키는 테이블\n",
|
|
" - 이동류번호 : 1 ~ 16, 17, 18, 21\n",
|
|
" - 진입, 진출방향(8방위) : 동, 서, 남, 북, 북동, 북서, 남동, 남서\n",
|
|
" '''\n",
|
|
" # nema 정보 불러오기 및 병합\n",
|
|
" nema = pd.read_csv('../Data/tables/nema.csv', encoding='cp949')\n",
|
|
" match3 = pd.merge(match2, nema, how='left', on='move_no').drop_duplicates()\n",
|
|
" return match3"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 107,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_match4(match3):\n",
|
|
" '''\n",
|
|
" 방위각 정보를 매칭시켜 추가함.\n",
|
|
" - match3의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir\n",
|
|
" - match4의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle\n",
|
|
"\n",
|
|
" angle_original : \n",
|
|
" - 컬럼 : inter_no, angle_Aj, angle_Bj (j : 1 ~ 8)\n",
|
|
" - 모든 종류의 이동류번호에 대하여 진입방향과 진출방향을 매칭시키는 테이블\n",
|
|
" - 이동류번호 : 1 ~ 16, 17, 18, 21\n",
|
|
" - 진입, 진출방향(8방위) : 동, 서, 남, 북, 북동, 북서, 남동, 남서\n",
|
|
" '''\n",
|
|
"\n",
|
|
" # 방위각 정보 불러오기\n",
|
|
" dtype_dict = {f'angle_{alph}{j}':'str' for alph in ['A', 'B'] for j in range(1,9)}\n",
|
|
" angle_original = pd.read_csv('../Data/tables/angle.csv', index_col=0, dtype = dtype_dict)\n",
|
|
"\n",
|
|
" # 계층화\n",
|
|
" angle = []\n",
|
|
" for i, row in angle_original.iterrows():\n",
|
|
" angle_codes = row[[f'angle_{alph}{j}' for alph in ['A', 'B'] for j in range(1,9)]]\n",
|
|
" new = pd.DataFrame({'inter_no':[row.inter_no] * 16, 'phase_no':list(range(1, 9))*2, 'ring_type':['A'] * 8 + ['B'] * 8, 'angle_code':angle_codes.to_list()})\n",
|
|
" angle.append(new)\n",
|
|
" angle = pd.concat(angle)\n",
|
|
" angle = angle.dropna().reset_index(drop=True)\n",
|
|
"\n",
|
|
" # 병합\n",
|
|
" six_chars = angle.angle_code.apply(lambda x:len(x)==6)\n",
|
|
" angle.loc[six_chars,'inc_angle'] = angle.angle_code.apply(lambda x:x[:3])\n",
|
|
" angle.loc[six_chars,'out_angle'] = angle.angle_code.apply(lambda x:x[3:])\n",
|
|
" angle = angle.drop('angle_code', axis=1)\n",
|
|
" match4 = pd.merge(match3, angle, how='left', left_on=['inter_no', 'phase_no', 'ring_type'],\n",
|
|
" right_on=['inter_no', 'phase_no', 'ring_type']).drop_duplicates()\n",
|
|
" return match4"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 108,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_match5(match4):\n",
|
|
" '''\n",
|
|
" 진입엣지id, 진출엣지id, 노드id를 추가함 (주교차로).\n",
|
|
" - match4의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle\n",
|
|
" - match5의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle, inc_edge, out_edge, node_id\n",
|
|
" \n",
|
|
" 사용된 데이터 : \n",
|
|
" (1) net\n",
|
|
" - 성남시 정자동 부근의 샘플 네트워크\n",
|
|
" (2) inter_node\n",
|
|
" - 교차로번호와 노드id를 매칭시키는 테이블.\n",
|
|
" - parent/child 정보도 포함되어 있음\n",
|
|
" - 컬럼 : inter_no, node_id, inter_type\n",
|
|
" (3) inter_info\n",
|
|
" - 교차로 정보. 여기에서는 위도와 경도가 쓰임.\n",
|
|
" - 컬럼 : inter_no, inter_name, inter_lat, inter_lon, group_no, main_phase_no\n",
|
|
"\n",
|
|
" 진입엣지id, 진출엣지id를 얻는 과정 :\n",
|
|
" - match5 = match4.copy()의 각 열을 순회하면서 아래 과정을 반복함.\n",
|
|
" * 진입에 대해서만 서술하겠지만 진출도 마찬가지로 설명될 수 있음\n",
|
|
" - 해당 행의 교차로정보로부터 노드ID를 얻어내고, 해당 노드에 대한 모든 진출엣지id를 inc_edges에 저장.\n",
|
|
" * inc_edge(진입엣지) : incoming edge, out_edge(진출엣지) : outgoing_edge\n",
|
|
" - inc_edges의 모든 진입엣지에 대하여 진입방향(inc_dires, 2차원 단위벡터)을 얻어냄.\n",
|
|
" - 해당 행의 진입각으로부터 그에 대응되는 진입각방향(단위벡터)를 얻어냄.\n",
|
|
" - 주어진 진입각방향에 대하여 내적이 가장 작은 진입방향에 대한 진입엣지를 inc_edge_id로 지정함.\n",
|
|
" '''\n",
|
|
"\n",
|
|
" # 네트워크 불러오기 \n",
|
|
" net = sumolib.net.readNet('../Data/networks/sn.net.xml')\n",
|
|
" # 교차로-노드 매칭 정보 불러오기\n",
|
|
" inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
|
|
" # 교차로정보(위, 경도) 불러오기\n",
|
|
" inter_info = pd.read_csv('../Data/tables/inter_info.csv', index_col=0)\n",
|
|
"\n",
|
|
" # parent node만 가져옴.\n",
|
|
" inter_node1 = inter_node[inter_node.inter_type == 'parent'].drop('inter_type', axis=1)\n",
|
|
" inter_info1 = inter_info[['inter_no', 'inter_lat', 'inter_lon']]\n",
|
|
" inter = pd.merge(inter_node1, inter_info1, how='left', left_on=['inter_no'],\n",
|
|
" right_on=['inter_no']).drop_duplicates()\n",
|
|
"\n",
|
|
" inter2node = dict(zip(inter['inter_no'], inter['node_id']))\n",
|
|
"\n",
|
|
" match5 = match4.copy()\n",
|
|
" # 진입진출ID 매칭\n",
|
|
" for index, row in match5.iterrows():\n",
|
|
" node_id = inter2node[row.inter_no]\n",
|
|
" node = net.getNode(node_id)\n",
|
|
" # 교차로의 모든 (from / to) edges\n",
|
|
" inc_edges = [edge for edge in node.getIncoming() if edge.getFunction() == ''] # incoming edges\n",
|
|
" out_edges = [edge for edge in node.getOutgoing() if edge.getFunction() == ''] # outgoing edges\n",
|
|
" # 교차로의 모든 (from / to) directions\n",
|
|
" inc_dirs = []\n",
|
|
" for inc_edge in inc_edges:\n",
|
|
" start = inc_edge.getShape()[-2]\n",
|
|
" end = inc_edge.getShape()[-1]\n",
|
|
" inc_dir = np.array(end) - np.array(start)\n",
|
|
" inc_dir = inc_dir / (inc_dir ** 2).sum() ** 0.5\n",
|
|
" inc_dirs.append(inc_dir)\n",
|
|
" out_dirs = []\n",
|
|
" for out_edge in out_edges:\n",
|
|
" start = out_edge.getShape()[0]\n",
|
|
" end = out_edge.getShape()[1]\n",
|
|
" out_dir = np.array(end) - np.array(start)\n",
|
|
" out_dir = out_dir / (out_dir ** 2).sum() ** 0.5\n",
|
|
" out_dirs.append(out_dir)\n",
|
|
" # 진입각, 진출각 불러오기\n",
|
|
" if not pd.isna(row.inc_angle):\n",
|
|
" inc_angle = int(row.inc_angle)\n",
|
|
" out_angle = int(row.out_angle)\n",
|
|
" # 방위각을 일반각으로 가공, 라디안 변환, 단위벡터로 변환\n",
|
|
" inc_angle = (-90 - inc_angle) % 360\n",
|
|
" inc_angle = inc_angle * np.pi / 180.\n",
|
|
" inc_dir_true = np.array([np.cos(inc_angle), np.sin(inc_angle)])\n",
|
|
" out_angle = (90 - out_angle) % 360\n",
|
|
" out_angle = out_angle * np.pi / 180.\n",
|
|
" out_dir_true = np.array([np.cos(out_angle), np.sin(out_angle)])\n",
|
|
" # 매칭 엣지 반환\n",
|
|
" inc_index = np.array([np.dot(inc_dir, inc_dir_true) for inc_dir in inc_dirs]).argmax()\n",
|
|
" out_index = np.array([np.dot(out_dir, out_dir_true) for out_dir in out_dirs]).argmax()\n",
|
|
" inc_edge_id = inc_edges[inc_index].getID()\n",
|
|
" out_edge_id = out_edges[out_index].getID()\n",
|
|
" match5.at[index, 'inc_edge'] = inc_edge_id\n",
|
|
" match5.at[index, 'out_edge'] = out_edge_id\n",
|
|
" match5['node_id'] = match5['inter_no'].map(inter2node)\n",
|
|
" match5 = match5.sort_values(by=['inter_no','phase_no','ring_type']).reset_index(drop=True)\n",
|
|
" return match5"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 109,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_match6(match5):\n",
|
|
" '''\n",
|
|
" 진입엣지id, 진출엣지id, 노드id를 추가함 (부교차로).\n",
|
|
" - match6의 컬럼 : inter_no, phase_no, ring_type, move_no, inc_dir, out_dir, inc_angle, out_angle, inc_edge, out_edge, node_id\n",
|
|
" \n",
|
|
" 사용된 데이터 : \n",
|
|
" (1) inter_node\n",
|
|
" - 교차로번호와 노드id를 매칭시키는 테이블.\n",
|
|
" - parent/child 정보도 포함되어 있음\n",
|
|
" - 컬럼 : inter_no, node_id, inter_type\n",
|
|
" (2) uturn (유턴정보)\n",
|
|
" - 컬럼 : parent_id, child_id, direction, condition, inc_edge, out_edge\n",
|
|
" - parent_id, child_id : 주교차로id, 유턴교차로id\n",
|
|
" - direction : 주교차로에 대한 유턴노드의 상대적인 위치(방향)\n",
|
|
" - condition : 좌회전시, 직진시, 직좌시, 보행신호시 중 하나\n",
|
|
" - inc_edge, out_edge : 유턴에 대한 진입진출엣지\n",
|
|
" (3) coord (연동교차로정보)\n",
|
|
" - 컬럼 : parent_id, child_id, phase_no, ring_type, inc_edge, out_edge\n",
|
|
" - parent_id, child_id : 주교차로id, 연동교차로id\n",
|
|
" - 나머지 컬럼 : 각 (현시, 링)별 진입진출엣지\n",
|
|
"\n",
|
|
" 설명 :\n",
|
|
" - match5는 주교차로에 대해서만 진입엣지id, 진출엣지id, 노드id를 추가했었음.\n",
|
|
" 여기에서 uturn, coord를 사용해서 부교차로들(유턴교차로, 연동교차로)에 대해서도 해당 값들을 부여함.\n",
|
|
" 유턴교차로 :\n",
|
|
" - directions를 정북기준 시계방향의 8방위로 정함.\n",
|
|
" - 이를 통해 진입방향이 주어진 경우에 좌회전, 직진, 보행 등에 대한 (진입방향, 진출방향)을 얻어낼 수 있음.\n",
|
|
" - 예) 진입방향(direction)이 '북'일 때, \n",
|
|
" - 직진 : (북, 남)\n",
|
|
" * 남 : directions[(ind + 4) % len(directions)]\n",
|
|
" - 좌회전 : (북, 동)\n",
|
|
" * 동 : directions[(ind + 2) % len(directions)]\n",
|
|
" - 보행 : (서, 동)\n",
|
|
" * 서 : directions[(ind - 2) % len(directions)]\n",
|
|
" - uturn의 각 행을 순회하면서 아래 과정을 반복함\n",
|
|
" - match5에서 parent_id에 해당하는 행들을 가져옴(cmatch).\n",
|
|
" - condition 별로 진입방향, 진출방향A, 진출방향B 정함.\n",
|
|
" - 상술한 directions를 활용하여 정함.\n",
|
|
" - (진입방향, 진출방향A, 진출방향B)을 고려하여 (현시, 링) 별로 진입엣지id, 진출엣지id를 정함.\n",
|
|
" - ex) cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
|
|
" - 순회하면서 만든 cmatch를 cmatchs라는 리스트에 저장함.\n",
|
|
"\n",
|
|
" 연동교차로 :\n",
|
|
" - 연동교차로의 경우 coord에 (현시, 링)별 진입엣지ID, 진출엣지ID가 명시되어 있음.\n",
|
|
" - 'inc_dir', 'out_dir', 'inc_angle','out_angle'와 같은 열들은 np.nan을 지정해놓음.\n",
|
|
" - 이 열들은, 사실상 다음 스텝부터는 사용되지 않는 열들이기 때문에 np.nan으로 지정해놓아도 문제없음.\n",
|
|
"\n",
|
|
" match6 :\n",
|
|
" - 이렇게 얻은 match5, cmatchs, coord를 모두 pd.concat하여 match6을 얻어냄.\n",
|
|
" '''\n",
|
|
"\n",
|
|
" inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
|
|
" node2inter = dict(zip(inter_node['node_id'], inter_node['inter_no']))\n",
|
|
"\n",
|
|
" uturn = pd.read_csv('../Data/tables/child_uturn.csv')\n",
|
|
" coord = pd.read_csv('../Data/tables/child_coord.csv')\n",
|
|
" child_ids = inter_node[inter_node.inter_type=='child'].node_id.unique()\n",
|
|
" ch2pa = {} # child to parent\n",
|
|
" for child_id in child_ids:\n",
|
|
" parent_no = inter_node[inter_node.node_id==child_id].inter_no.iloc[0]\n",
|
|
" sub_inter_node = inter_node[inter_node.inter_no==parent_no]\n",
|
|
" ch2pa[child_id] = sub_inter_node[sub_inter_node.inter_type=='parent'].iloc[0].node_id\n",
|
|
" directions = ['북', '북동', '동', '남동', '남', '남서', '서', '북서'] # 정북기준 시계방향으로 8방향\n",
|
|
"\n",
|
|
" # 각 uturn node에 대하여 (inc_edge_id, out_edge_id) 부여\n",
|
|
" cmatches = []\n",
|
|
" for _, row in uturn.iterrows():\n",
|
|
" child_id = row.child_id\n",
|
|
" parent_id = row.parent_id\n",
|
|
" direction = row.direction\n",
|
|
" condition = row.condition\n",
|
|
" inc_edge_id = row.inc_edge\n",
|
|
" out_edge_id = row.out_edge\n",
|
|
" # match5에서 parent_id에 해당하는 행들을 가져옴\n",
|
|
" cmatch = match5.copy()[match5.node_id==parent_id] # match dataframe for a child node\n",
|
|
" cmatch = cmatch.sort_values(by=['phase_no', 'ring_type']).reset_index(drop=True)\n",
|
|
" cmatch['node_id'] = child_id\n",
|
|
" cmatch[['inc_edge', 'out_edge']] = np.nan\n",
|
|
"\n",
|
|
" # condition 별로 inc_dire, out_dire_A, out_dire_B를 정함\n",
|
|
" ind = directions.index(direction)\n",
|
|
" if condition == \"좌회전시\":\n",
|
|
" inc_dire = direction\n",
|
|
" out_dire_A = out_dire_B = directions[(ind + 2) % len(directions)]\n",
|
|
" elif condition == \"직진시\":\n",
|
|
" inc_dire = direction\n",
|
|
" out_dire_A = out_dire_B = directions[(ind + 4) % len(directions)]\n",
|
|
" elif condition == \"보행신호시\":\n",
|
|
" inc_dire = directions[(ind + 2) % len(directions)]\n",
|
|
" out_dire_A = directions[(ind - 2) % len(directions)]\n",
|
|
" out_dire_B = directions[(ind - 2) % len(directions)]\n",
|
|
"\n",
|
|
" # (inc_dire, out_dire_A, out_dire_B) 별로 inc_edge_id, out_edge_id를 정함\n",
|
|
" if condition == '보행신호시':\n",
|
|
" cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
|
|
" cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_B), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
|
|
" # 이동류번호가 17(보행신호)이면서 유턴노드방향으로 가는 신호가 없으면 (inc_edge_id, out_edge_id)를 부여한다.\n",
|
|
" cmatch.loc[(cmatch.move_no==17) & (cmatch.out_dir!=direction), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
|
|
" else: # '직진시', '좌회전시'\n",
|
|
" cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
|
|
" cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_B), ['inc_edge', 'out_edge']] = [inc_edge_id, out_edge_id]\n",
|
|
" # 유턴신호의 이동류번호를 19로 부여한다.\n",
|
|
" cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_A), 'move_no'] = 19\n",
|
|
" cmatch.loc[(cmatch.inc_dir==inc_dire) & (cmatch.out_dir==out_dire_B), 'move_no'] = 19\n",
|
|
" cmatches.append(cmatch)\n",
|
|
"\n",
|
|
" # 각 coordination node에 대하여 (inc_edge_id, out_edge_id) 부여\n",
|
|
" coord['inter_no'] = coord['parent_id'].map(node2inter)\n",
|
|
" coord = coord.rename(columns={'child_id':'node_id'})\n",
|
|
" coord[['inc_dir', 'out_dir', 'inc_angle','out_angle']] = np.nan\n",
|
|
" coord['move_no'] = 20\n",
|
|
" coord = coord[['inter_no', 'phase_no', 'ring_type', 'move_no', 'inc_dir', 'out_dir', 'inc_angle','out_angle', 'inc_edge', 'out_edge', 'node_id']]\n",
|
|
" \n",
|
|
" # display(coord)\n",
|
|
" cmatches = pd.concat(cmatches)\n",
|
|
" match6 = pd.concat([match5, cmatches, coord]).drop_duplicates().sort_values(by=['inter_no', 'node_id', 'phase_no', 'ring_type'])\n",
|
|
" match6.to_csv('../Intermediates/match6.csv')\n",
|
|
" return match6"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 110,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_matching(match6):\n",
|
|
" '''\n",
|
|
" 이동류 매칭 : 각 교차로에 대하여, 가능한 모든 이동류 (1~18, 21)에 대한 진입·진출엣지ID를 지정한다.\n",
|
|
" 모든 이동류에 대해 지정하므로, 시차제시 이전과 다른 이동류가 등장하더라도 항상 진입·진출 엣지 ID를 지정할 수 있다. \n",
|
|
" - matching의 컬럼 : inter_no, move_no, inc_dir, out_dir, inc_edge, out_edge, node_id\n",
|
|
" \n",
|
|
" 설명 : \n",
|
|
" - 필요한 리스트, 딕셔너리 등을 정의\n",
|
|
" (1) 가능한 (진입방향, 진출방향) 목록 [리스트]\n",
|
|
" (2) 각 교차로별 방향 목록 : pdires (possible directions) [딕셔너리]\n",
|
|
" (3) 각 (교차로, 진입방향) 별 진입id 목록 : inc2id (incoming direction to incoming edge_id) [딕셔너리]\n",
|
|
" (4) 각 (교차로, 진출방향) 별 진출id 목록 : out2id (outgoing direction to outgoing edge_id) [딕셔너리]\n",
|
|
" (5) 각 교차로별 가능한 (진입방향, 진출방향) 목록 : pflow (possible flows) [딕셔너리]\n",
|
|
" - matching은 빈 리스트로 지정.\n",
|
|
" - 모든 노드id에 대하여 다음 과정을 반복\n",
|
|
" - 해당 노드id에 대한 모든 가능한 (진입방향, 진출방향)에 대하여 다음 과정을 반복\n",
|
|
" - (노드id, 진입방향)으로부터 진입엣지id를 얻어냄. 마찬가지로 진출엣지id도 얻어냄\n",
|
|
" - 얻어낸 정보를 바탕으로 한 행(new_row)을 만들고 이것을 matching에 append\n",
|
|
" '''\n",
|
|
"\n",
|
|
" match7 = match6.copy()\n",
|
|
" match7 = match7[['inter_no', 'move_no', 'inc_dir', 'out_dir', 'inc_edge', 'out_edge', 'node_id']]\n",
|
|
" inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
|
|
" nema = pd.read_csv('../Data/tables/nema.csv', encoding='cp949')\n",
|
|
"\n",
|
|
" parent_ids = sorted(inter_node[inter_node.inter_type=='parent'].node_id.unique())\n",
|
|
" child_ids = sorted(inter_node[inter_node.inter_type=='child'].node_id.unique())\n",
|
|
"\n",
|
|
" # (1) 가능한 (진입방향, 진출방향) 목록 \n",
|
|
" flows = nema.dropna().apply(lambda row: (row['inc_dir'], row['out_dir']), axis=1).tolist()\n",
|
|
" # (2) 각 교차로별 방향 목록 : pdires (possible directions)\n",
|
|
" pdires = {}\n",
|
|
" for node_id in parent_ids:\n",
|
|
" dires = match7[match7.node_id == node_id][['inc_dir','out_dir']].values.flatten()\n",
|
|
" dires = {dire for dire in dires if type(dire)==str}\n",
|
|
" pdires[node_id] = dires\n",
|
|
" # (3) 각 (교차로, 진입방향) 별 진입id 목록 : inc2id (incoming direction to incoming edge_id)\n",
|
|
" inc2id = {}\n",
|
|
" for node_id in parent_ids:\n",
|
|
" for inc_dir in pdires[node_id]:\n",
|
|
" df = match7[(match7.node_id==node_id) & (match7.inc_dir==inc_dir)]\n",
|
|
" inc2id[(node_id, inc_dir)] = df.inc_edge.iloc[0]\n",
|
|
" # (4) 각 (교차로, 진출방향) 별 진출id 목록 : out2id (outgoing direction to outgoing edge_id)\n",
|
|
" out2id = {}\n",
|
|
" for node_id in parent_ids:\n",
|
|
" for out_dir in pdires[node_id]:\n",
|
|
" df = match7[(match7.node_id==node_id) & (match7.out_dir==out_dir)]\n",
|
|
" out2id[(node_id, out_dir)] = df.out_edge.iloc[0]\n",
|
|
" # (5) 각 교차로별 가능한 (진입방향, 진출방향) 목록 : pflow (possible flows)\n",
|
|
" pflow = {}\n",
|
|
" for node_id in parent_ids:\n",
|
|
" pflow[node_id] = [flow for flow in flows if set(flow).issubset(pdires[node_id])]\n",
|
|
" # (6) 가능한 이동류에 대하여 진입id, 진출id 배정 : matching\n",
|
|
" node2inter = dict(zip(match7['node_id'], match7['inter_no']))\n",
|
|
" dires_right = ['북', '서', '남', '동', '북'] # ex (북, 서), (서, 남) 등은 우회전 flow\n",
|
|
" matching = []\n",
|
|
" for node_id in parent_ids:\n",
|
|
" inter_no = node2inter[node_id]\n",
|
|
" # 좌회전과 직진(1 ~ 16)\n",
|
|
" for (inc_dir, out_dir) in pflow[node_id]:\n",
|
|
" move_no = nema[(nema.inc_dir==inc_dir) & (nema.out_dir==out_dir)].move_no.iloc[0]\n",
|
|
" inc_edge = inc2id[(node_id, inc_dir)]\n",
|
|
" out_edge = out2id[(node_id, out_dir)]\n",
|
|
" new_row = pd.DataFrame({'inter_no':[inter_no], 'move_no':[move_no],\n",
|
|
" 'inc_dir':[inc_dir], 'out_dir':[out_dir],\n",
|
|
" 'inc_edge':[inc_edge], 'out_edge':[out_edge], 'node_id':[node_id]})\n",
|
|
" matching.append(new_row)\n",
|
|
" # 보행신호(17), 전적색(18)\n",
|
|
" new_row = pd.DataFrame({'inter_no':[inter_no] * 2, 'move_no':[17, 18],\n",
|
|
" 'inc_dir':[None]*2, 'out_dir':[None]*2,\n",
|
|
" 'inc_edge':[None]*2, 'out_edge':[None]*2, 'node_id':[node_id]*2})\n",
|
|
" matching.append(new_row)\n",
|
|
" # 신호우회전(21)\n",
|
|
" for d in range(len(dires_right)-1):\n",
|
|
" inc_dir = dires_right[d]\n",
|
|
" out_dir = dires_right[d+1]\n",
|
|
" if {inc_dir, out_dir}.issubset(pdires[node_id]):\n",
|
|
" inc_edge = inc2id[(node_id, inc_dir)]\n",
|
|
" out_edge = out2id[(node_id, out_dir)]\n",
|
|
" new_row = pd.DataFrame({'inter_no':[inter_no], 'move_no':[21],\n",
|
|
" 'inc_dir':[inc_dir], 'out_dir':[out_dir],\n",
|
|
" 'inc_edge':[inc_edge], 'out_edge':[out_edge], 'node_id':[node_id]})\n",
|
|
" matching.append(new_row)\n",
|
|
" matching.append(match7[match7.node_id.isin(child_ids)])\n",
|
|
" matching = pd.concat(matching)\n",
|
|
" matching = matching.dropna().sort_values(by=['inter_no', 'node_id', 'move_no']).reset_index(drop=True)\n",
|
|
" matching['move_no'] = matching['move_no'].astype(int)\n",
|
|
" matching.to_csv('../Intermediates/matching.csv')\n",
|
|
" return matching"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 111,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"match1 = pd.read_csv('../Intermediates/match1.csv', index_col=0)\n",
|
|
"match2 = make_match2(match1)\n",
|
|
"match3 = make_match3(match2)\n",
|
|
"match4 = make_match4(match3)\n",
|
|
"match5 = make_match5(match4)\n",
|
|
"match6 = make_match6(match5)\n",
|
|
"matching = make_matching(match6)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# B. 5초 간격으로 이동류번호 수집"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 112,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# 5초 단위로 이동류번호 저장 및 신호이력에서 유닉스시각 가져와서 표시, 한시간동안의 데이터만 보관\n",
|
|
"midnight = int(datetime(2024, 1, 5, 0, 0, 0).timestamp())\n",
|
|
"next_day = int(datetime(2024, 1, 6, 0, 0, 0).timestamp())\n",
|
|
"fsecs = range(midnight, next_day, 5) # fsecs : unix time by Five SECondS\n",
|
|
"fmins = range(midnight, next_day, 300) # fmins : unix time by Five MINuteS"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 113,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def save_movement():\n",
|
|
" # time2move = dict(zip(fsecs,moves)) # move : 어느 순간의 이동류정보\n",
|
|
" history = pd.read_csv('../Data/tables/history.csv', index_col=0)\n",
|
|
"\n",
|
|
" time2movement = {} # movement : 어느 순간의, 그 순간으로부터 한시간 동안의 (교차로번호 + 현시별이동류번호 + 시작시간)\n",
|
|
" # - 아래 절차를 5초마다 반복\n",
|
|
" for fsec in tqdm(fsecs): # fsec : unix time by Five SECond\n",
|
|
" # 1. 상태 테이블 조회해서 전체 데이터중 필요데이터(교차로번호, A링 현시번호, A링 이동류번호, B링 현시번호, B링 이동류번호)만 수집 : A\n",
|
|
" # move = time2move[fsec]\n",
|
|
" move = pd.read_csv(f'../Data/tables/move/move_{fsec}.csv', index_col=0)\n",
|
|
" # 2. 이력 테이블 조회해서 교차로별로 유닉스시간 최대인 데이터(교차로변호, 종료유닉스타임)만 수집 : B\n",
|
|
" recent_histories = [group.iloc[-1:] for _, group in history[history['end_unix'] < fsec].groupby('inter_no')] # 교차로별로 유닉스시간이 최대인 행들\n",
|
|
" if not recent_histories:\n",
|
|
" rhistory = pd.DataFrame({'inter_no':[], 'end_unix':[]}) # recent history\n",
|
|
" else:\n",
|
|
" rhistory = pd.concat(recent_histories)\n",
|
|
" recent_unix = rhistory[['inter_no', 'end_unix']]\n",
|
|
" # 3. 상태 테이블 조회정보(A)와 이력 테이블 조회정보(B) 조인(키값 : 교차로번호) : C\n",
|
|
" move = pd.merge(move, recent_unix, how='left', on='inter_no')\n",
|
|
" move['end_unix'] = move['end_unix'].fillna(0).astype(int)\n",
|
|
" move = move.drop_duplicates()\n",
|
|
" # 4. C데이터 프레임에 신규 컬럼(시작 유닉스타임) 생성 후 종료유닉스 타임 값 입력, 종료 유닉스 타임 컬럼 제거\n",
|
|
" move = move.rename(columns = {'end_unix':'start_unix'})\n",
|
|
" # 5. 이동류 이력정보 READ\n",
|
|
" # - CSV 파일로 서버에 저장된 이동류정보를 읽어옴(파일이 없는 경우에는 데이터가 없는 프레임 D 생성)\n",
|
|
" try:\n",
|
|
" if isinstance(movement, pd.DataFrame): # movement가 존재할 경우 그걸 그대로 씀.\n",
|
|
" pass\n",
|
|
" else: \n",
|
|
" movement = pd.DataFrame()\n",
|
|
" except NameError: # movement가 존재하지 않는 경우 생성\n",
|
|
" movement = pd.DataFrame()\n",
|
|
" # 6. 이동류 이력정보 데이터테이블(D)에 C데이터 add\n",
|
|
" movement = pd.concat([movement, move])\n",
|
|
" # 7. D데이터 프레임에서 중복데이터 제거(교차로번호, 시작 유닉스타임, A링 현시번호, B링 현시번호 같은 행은 제거)\n",
|
|
" movement = movement.drop_duplicates(['inter_no','phas_A','phas_B','start_unix'])\n",
|
|
" # 8. D데이터 보관 시간 기준시간을 시작 유닉스 타임의 최대값 - 3600을 값으로 산출하고, 보관 시간 기준시간보다 작은 시작 유닉스 타임을 가진 행은 모두 제거(1시간 데이터만 보관)\n",
|
|
" movement = movement[movement.start_unix > fsec - 3600]\n",
|
|
" movement = movement.sort_values(by=['start_unix','inter_no','phas_A','phas_B']).reset_index(drop=True)\n",
|
|
"\n",
|
|
" time2movement[fsec] = movement\n",
|
|
" movement.to_csv(f'../Intermediates/movement/movement_{fsec}.csv')\n",
|
|
"# save_movement()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# C. 5분 간격으로 신호이력 수집 및 통합테이블 생성"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 114,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"m = 30\n",
|
|
"midnight = int(datetime(2024, 1, 5, 0, 0, 0).timestamp())\n",
|
|
"next_day = int(datetime(2024, 1, 6, 0, 0, 0).timestamp())\n",
|
|
"fmins = range(midnight, next_day, 300)\n",
|
|
"\n",
|
|
"# 현재시각\n",
|
|
"present_time = fmins[m]\n",
|
|
"\n",
|
|
"plan = pd.read_csv('../Data/tables/plan.csv', index_col=0)\n",
|
|
"history = pd.read_csv('../Data/tables/history.csv', index_col=0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 115,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_splits(plan):\n",
|
|
" # split, isplit : A,B 분리 혹은 통합시 사용될 수 있는 딕셔너리 \n",
|
|
" splits = {} # splits maps (inter_no, start_hour, start_minute) to split \n",
|
|
" for i, row in plan.iterrows():\n",
|
|
" inter_no = row.inter_no\n",
|
|
" start_hour = row.start_hour\n",
|
|
" start_minute = row.start_minute\n",
|
|
" cycle = row.cycle\n",
|
|
" cums_A = row[[f'dura_A{j}' for j in range(1,9)]].cumsum()\n",
|
|
" cums_B = row[[f'dura_B{j}' for j in range(1,9)]].cumsum()\n",
|
|
" splits[(inter_no, start_hour, start_minute)] = {} # split maps (phas_A, phas_B) to k\n",
|
|
" k = 0\n",
|
|
" for t in range(cycle):\n",
|
|
" new_phas_A = len(cums_A[cums_A < t]) + 1\n",
|
|
" new_phas_B = len(cums_B[cums_B < t]) + 1\n",
|
|
" if k == 0 or ((new_phas_A, new_phas_B) != (phas_A, phas_B)):\n",
|
|
" k += 1\n",
|
|
" phas_A = new_phas_A\n",
|
|
" phas_B = new_phas_B\n",
|
|
" splits[(inter_no, start_hour, start_minute)][(phas_A, phas_B)] = k\n",
|
|
"\n",
|
|
" isplits = {} # the inverse of splits\n",
|
|
" for i in splits:\n",
|
|
" isplits[i] = {splits[i][k]:k for k in splits[i]} # isplit maps k to (phas_A, phas_B)\n",
|
|
" return splits, isplits\n",
|
|
"splits, isplits = make_splits(plan)\n",
|
|
"\n",
|
|
"def make_timetable(plan):\n",
|
|
" # timetable\n",
|
|
" timetable = plan[['start_hour', 'start_minute']].drop_duplicates()\n",
|
|
" timetable['start_seconds'] = midnight + timetable['start_hour'] * 3600 + timetable['start_minute'] * 60\n",
|
|
" return timetable\n",
|
|
"timetable = make_timetable(plan)\n",
|
|
"\n",
|
|
"# inter2node\n",
|
|
"inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
|
|
"inter_node = inter_node[inter_node.inter_type=='parent']\n",
|
|
"inter2node = dict(zip(inter_node['inter_no'], inter_node['node_id']))\n",
|
|
"\n",
|
|
"hours = np.array(range(midnight - 7200, next_day + 1, 3600)) # 정각에 해당하는 시각들 목록"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 116,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def calculate_DS(rhist, curr_unix, hours, timetable):\n",
|
|
" program_starts = np.array(timetable.start_seconds)\n",
|
|
" idx = (program_starts <= present_time).sum() - 1\n",
|
|
" program_start = program_starts[idx]\n",
|
|
" if list(hours[hours <= curr_unix]):\n",
|
|
" ghour_lt_curr_unix = hours[hours <= curr_unix].max() # the greatest hour less than or equal to curr_unix\n",
|
|
" else:\n",
|
|
" ghour_lt_curr_unix = program_start\n",
|
|
" start_unixes = rhist.start_unix.unique()\n",
|
|
" start_unixes_lt_ghour = np.sort(start_unixes[start_unixes < ghour_lt_curr_unix]) # start unixes less than ghour_lt_curr_unix\n",
|
|
" # 기준유닉스(base_unix) : curr_unix보다 작은 hour 중에서 가장 큰 값으로부터 다섯 번째로 작은 start_unix\n",
|
|
" if len(start_unixes_lt_ghour) > 5:\n",
|
|
" base_unix = start_unixes_lt_ghour[-5]\n",
|
|
" # start_unixes_lt_ghour의 길이가 5 미만일 경우에는 맨 앞 start_unix로 base_unix를 지정\n",
|
|
" else:\n",
|
|
" base_unix = rhist.start_unix.min()\n",
|
|
" D_n = curr_unix - base_unix\n",
|
|
" S_n_durs = rhist[(rhist.start_unix > base_unix) & (rhist.start_unix <= curr_unix)] \\\n",
|
|
" [[f'dura_{alph}{j}' for alph in ['A', 'B'] for j in range(1,9)]]\n",
|
|
" S_n = S_n_durs.values.sum() // 2\n",
|
|
" return D_n, S_n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 117,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def load_prow(timetable, inter_no, time):\n",
|
|
" '''\n",
|
|
" load planned row\n",
|
|
" '''\n",
|
|
" # 프로그램 시작시각\n",
|
|
" program_starts = np.array(timetable.start_seconds)\n",
|
|
" idx = (program_starts <= time).sum() - 1\n",
|
|
" program_start = program_starts[idx]\n",
|
|
"\n",
|
|
" # 최근 프로그램 시작시각에 대한 신호계획\n",
|
|
" start_hour = timetable.iloc[idx].start_hour\n",
|
|
" start_minute = timetable.iloc[idx].start_minute\n",
|
|
" prow = plan[(plan.inter_no==inter_no) & (plan.start_hour==start_hour) & (plan.start_minute==start_minute)] # planned row\n",
|
|
" return program_start, prow"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 118,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_rhistory(history, present_time, adder):\n",
|
|
" # 1. 조회시점의 유닉스 타임 이전의 신호이력 수집\n",
|
|
" rhistory = history.copy() # recent history\n",
|
|
" rhistory = rhistory[(rhistory.end_unix <= present_time) & (rhistory.end_unix > present_time - 9000)] # 두 시간 반 전부터 현재까지의 신호이력을 가져옴. 9000 = 3600 * 2.5\n",
|
|
"\n",
|
|
" # rhistory에 모든 교차로번호가 존재하지 않으면 해당 교차로번호에 대한 신호이력을 추가함 (at 최근 프로그램 시작시각)\n",
|
|
" whole_inter_nos = sorted(history.inter_no.unique())\n",
|
|
" recent_inter_nos = sorted(rhistory.inter_no.unique())\n",
|
|
" if not whole_inter_nos==recent_inter_nos:\n",
|
|
" for inter_no in set(whole_inter_nos) - set(recent_inter_nos):\n",
|
|
" program_start, prow = load_prow(timetable, inter_no, present_time - 9000)\n",
|
|
" cycle = prow.cycle.iloc[0]\n",
|
|
" row1 = prow.drop(['start_hour', 'start_minute'], axis=1).copy()\n",
|
|
" row2 = prow.drop(['start_hour', 'start_minute'], axis=1).copy()\n",
|
|
" # prow에서 필요한 부분을 rhistory에 추가\n",
|
|
" row1['end_unix'] = program_start\n",
|
|
" row2['end_unix'] = program_start + cycle\n",
|
|
" rhistory = pd.concat([rhistory, row1, row2]).reset_index(drop=True)\n",
|
|
"\n",
|
|
" for inter_no in set(whole_inter_nos):\n",
|
|
" program_start, prow = load_prow(timetable, inter_no, present_time)\n",
|
|
" cycle = prow.cycle.iloc[0]\n",
|
|
" row3 = prow.drop(['start_hour', 'start_minute'], axis=1).copy()\n",
|
|
" # prow에서 필요한 부분을 rhistory에 추가\n",
|
|
" row3['end_unix'] = present_time + adder\n",
|
|
" rhistory = pd.concat([rhistory, row3]).reset_index(drop=True)\n",
|
|
"\n",
|
|
"\n",
|
|
" # 2. 시작 유닉스 타임컬럼 생성 후 종류 유닉스 타임에서 현시별 현시기간 컬럼의 합을 뺀 값으로 입력\n",
|
|
" # - 현시시간의 합을 뺀 시간의 +- 10초 이내에 이전 주기정보가 존재하면 그 유닉스 시간을 시작 유닉스시간 값으로 하고, 존재하지 않으면 현시시간의 합을 뺀 유닉스 시간을 시작 유닉스 시간으로 지정\n",
|
|
" for i, row in rhistory.iterrows():\n",
|
|
" inter_no = row.inter_no\n",
|
|
" end_unix = row.end_unix\n",
|
|
" elapsed_time = row[[f'dura_{alph}{j}' for alph in ['A', 'B'] for j in range(1,9)]].sum() // 2 # 현시시간 합\n",
|
|
" # 이전 유닉스 존재하지 않음 : 현시시간 합의 차\n",
|
|
" start_unix = end_unix - elapsed_time\n",
|
|
" pre_rows = history[:i] # previous rows\n",
|
|
" if inter_no in pre_rows.inter_no.unique(): # 이전 유닉스 존재\n",
|
|
" pre_unix = pre_rows[pre_rows.inter_no == inter_no]['end_unix'].iloc[-1] # previous unix time\n",
|
|
" # 이전 유닉스 존재, abs < 10 : 이전 유닉스\n",
|
|
" if abs(pre_unix - start_unix) < 10:\n",
|
|
" start_unix = pre_unix\n",
|
|
" # 이전 유닉스 존재, abs >=10 : 현시시간 합의 차\n",
|
|
" else:\n",
|
|
" pass\n",
|
|
" rhistory.loc[i, 'start_unix'] = start_unix \n",
|
|
" rhistory[rhistory.isna()] = 0\n",
|
|
" rhistory['start_unix'] = rhistory['start_unix'].astype(int)\n",
|
|
" rhistory = rhistory[['inter_no', 'start_unix'] + [f'dura_{alph}{j}' for alph in ['A', 'B'] for j in range(1,9)] + ['cycle']]\n",
|
|
" return rhistory\n",
|
|
"adder = 600\n",
|
|
"rhistory = make_rhistory(history, present_time, adder)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 119,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def processing(rhistory, hours):\n",
|
|
" rhists = []\n",
|
|
" for inter_no in sorted(rhistory.inter_no.unique()):\n",
|
|
" rhist = rhistory.copy()[rhistory.inter_no==inter_no]\n",
|
|
" rhist = rhist.drop_duplicates(subset=['start_unix']).reset_index(drop=True)\n",
|
|
"\n",
|
|
" # D_n 및 S_n 값 정의\n",
|
|
" rhist['D_n'] = 0 # D_n : 시간차이\n",
|
|
" rhist['S_n'] = 0 # S_n : 현시시간합\n",
|
|
" for n in range(len(rhist)):\n",
|
|
" curr_unix = rhist.iloc[n].start_unix # current start_unix\n",
|
|
" rhist.loc[n, ['D_n', 'S_n']] = calculate_DS(rhist, curr_unix, hours, timetable)\n",
|
|
"\n",
|
|
" # 이전시각, 현재시각\n",
|
|
" prev_unix = rhist.loc[0, 'start_unix'] # previous start_unix\n",
|
|
" curr_unix = rhist.loc[1, 'start_unix'] # current start_unix\n",
|
|
"\n",
|
|
" # rhist의 마지막 행에 도달할 때까지 반복\n",
|
|
" while True:\n",
|
|
" n = rhist[rhist.start_unix==curr_unix].index[0]\n",
|
|
" cycle = rhist.loc[n, 'cycle']\n",
|
|
" D_n = rhist.loc[n, 'D_n']\n",
|
|
" S_n = rhist.loc[n, 'S_n']\n",
|
|
" # 참값인 경우\n",
|
|
" if (abs(D_n - S_n) <= 5):\n",
|
|
" pass\n",
|
|
" # 참값이 아닌 경우\n",
|
|
" else:\n",
|
|
" # 2-1-1. 결측치 처리 : 인접한 두 start_unix의 차이가 계획된 주기의 두 배보다 크면 결측이 일어났다고 판단, 신호계획의 현시시간으로 \"대체\"\n",
|
|
" if curr_unix - prev_unix >= 2 * cycle:\n",
|
|
" # prev_unix를 계획된 주기만큼 늘려가면서 한 행씩 채워나간다.\n",
|
|
" # (curr_unix와의 차이가 계획된 주기보다 작거나 같아질 때까지)\n",
|
|
" while curr_unix - prev_unix > cycle:\n",
|
|
" prev_unix += cycle\n",
|
|
" # 신호 계획(prow) 불러오기\n",
|
|
" start_seconds = np.array(timetable.start_seconds)\n",
|
|
" idx = (start_seconds <= prev_unix).sum() - 1\n",
|
|
" start_hour = timetable.iloc[idx].start_hour\n",
|
|
" start_minute = timetable.iloc[idx].start_minute\n",
|
|
" prow = plan.copy()[(plan.inter_no==inter_no) & (plan.start_hour==start_hour) & (plan.start_minute==start_minute)] # planned row\n",
|
|
" # prow에서 필요한 부분을 rhist에 추가\n",
|
|
" prow['start_unix'] = prev_unix\n",
|
|
" prow = prow.drop(['start_hour', 'start_minute', 'offset'], axis=1)\n",
|
|
" cycle = prow.iloc[0].cycle\n",
|
|
" rhist = pd.concat([rhist, prow])\n",
|
|
" rhist = rhist.sort_values(by='start_unix').reset_index(drop=True)\n",
|
|
" n += 1\n",
|
|
"\n",
|
|
" # 2-1-2. 이상치 처리 : 비율에 따라 해당 행을 \"삭제\"(R_n <= 0.5) 또는 \"조정\"(R_n > 0.5)한다\n",
|
|
" R_n = (curr_unix - prev_unix) / cycle # R_n : 비율\n",
|
|
" # R_n이 0.5보다 작거나 같으면 해당 행을 삭제\n",
|
|
" if R_n <= 0.5:\n",
|
|
" rhist = rhist.drop(index=n).reset_index(drop=True)\n",
|
|
" if n >= rhist.index[-1]:\n",
|
|
" break\n",
|
|
" # 행삭제에 따른 curr_unix, R_n 재정의\n",
|
|
" curr_unix = rhist.loc[n, 'start_unix']\n",
|
|
" R_n = (curr_unix - prev_unix) / cycle # R_n : 비율\n",
|
|
"\n",
|
|
" # R_n이 0.5보다 크면 해당 행 조정 (비율을 유지한 채로 현시시간 대체)\n",
|
|
" if R_n > 0.5:\n",
|
|
" # 신호 계획(prow) 불러오기\n",
|
|
" start_seconds = np.array(timetable.start_seconds)\n",
|
|
" idx = (start_seconds <= curr_unix).sum() - 1\n",
|
|
" start_hour = timetable.iloc[idx].start_hour\n",
|
|
" start_minute = timetable.iloc[idx].start_minute\n",
|
|
" prow = plan[(plan.inter_no==inter_no) & (plan.start_hour==start_hour) & (plan.start_minute==start_minute)] # planned row\n",
|
|
" # 조정된 현시시간 (prow에 R_n을 곱하고 정수로 바꿈)\n",
|
|
" adjusted_dur = prow.copy()[[f'dura_{alph}{j}' for alph in ['A', 'B'] for j in range(1,9)]] * R_n\n",
|
|
" int_parts = adjusted_dur.iloc[0].apply(lambda x: int(x))\n",
|
|
" frac_parts = adjusted_dur.iloc[0] - int_parts\n",
|
|
" difference = round(adjusted_dur.iloc[0].sum()) - int_parts.sum()\n",
|
|
" for _ in range(difference): # 소수 부분이 가장 큰 상위 'difference'개의 값에 대해 올림 처리\n",
|
|
" max_frac_index = frac_parts.idxmax()\n",
|
|
" int_parts[max_frac_index] += 1\n",
|
|
" frac_parts[max_frac_index] = 0 # 이미 처리된 항목은 0으로 설정\n",
|
|
" # rhist에 조정된 현시시간을 반영\n",
|
|
" rhist.loc[n, [f'dura_{alph}{j}' for alph in ['A', 'B'] for j in range(1,9)]] = int_parts.values\n",
|
|
" rhist.loc[n, 'cycle'] = int_parts.sum().sum() // 2\n",
|
|
"\n",
|
|
" if n >= rhist.index[-1]:\n",
|
|
" break\n",
|
|
" prev_unix = curr_unix\n",
|
|
" curr_unix = rhist.loc[n+1, 'start_unix']\n",
|
|
"\n",
|
|
" # 생략해도 무방할 코드\n",
|
|
" rhist = rhist.reset_index(drop=True)\n",
|
|
" rhist = rhist.sort_values(by=['start_unix'])\n",
|
|
"\n",
|
|
" # D_n 및 S_n 값 재정의\n",
|
|
" for n in range(len(rhist)):\n",
|
|
" curr_unix = rhist.iloc[n].start_unix # current start_unix\n",
|
|
" rhist.loc[n, ['D_n', 'S_n']] = calculate_DS(rhist, curr_unix, hours, timetable)\n",
|
|
" rhists.append(rhist)\n",
|
|
" rhists = pd.concat(rhists).sort_values(by=['start_unix','inter_no'])\n",
|
|
" rhists = rhists[rhists.start_unix >= present_time - 3600]\n",
|
|
" rhists = rhists.drop(columns=['D_n', 'S_n'])\n",
|
|
" return rhists\n",
|
|
"rhists = processing(rhistory, hours)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 120,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_hrhists(rhists, isplits, timetable):\n",
|
|
" # 계층화된 형태로 변환\n",
|
|
" hrhists = [] # hierarchied recent history\n",
|
|
" for i, row in rhists.iterrows():\n",
|
|
" inter_no = row.inter_no\n",
|
|
" start_unix = row.start_unix\n",
|
|
"\n",
|
|
" ind = (timetable['start_seconds'] <= row.start_unix).sum() - 1\n",
|
|
" start_hour = timetable.iloc[ind].start_hour\n",
|
|
" start_minute = timetable.iloc[ind].start_minute\n",
|
|
" isplit = isplits[(inter_no, start_hour, start_minute)]\n",
|
|
" phas_As = [isplit[j][0] for j in isplit.keys()]\n",
|
|
" phas_Bs = [isplit[j][1] for j in isplit.keys()]\n",
|
|
" durs_A = row[[f'dura_A{j}' for j in range(1,9)]]\n",
|
|
" durs_B = row[[f'dura_B{j}' for j in range(1,9)]]\n",
|
|
" durations = []\n",
|
|
" for j in range(1, len(isplit)+1):\n",
|
|
" ja = isplit[j][0]\n",
|
|
" jb = isplit[j][1]\n",
|
|
" if ja == jb:\n",
|
|
" durations.append(min(durs_A[ja-1], durs_B[jb-1]))\n",
|
|
" else:\n",
|
|
" durations.append(abs(durs_A[ja-1] - durs_B[ja-1]))\n",
|
|
" new_rows = pd.DataFrame({'inter_no':[inter_no] * len(durations), 'start_unix':[start_unix] * len(durations),\n",
|
|
" 'phas_A':phas_As, 'phas_B':phas_Bs, 'duration':durations})\n",
|
|
" hrhists.append(new_rows)\n",
|
|
" hrhists = pd.concat(hrhists)\n",
|
|
" hrhists = hrhists.sort_values(by = ['start_unix', 'inter_no', 'phas_A', 'phas_B']).reset_index(drop=True)\n",
|
|
" return hrhists\n",
|
|
"hrhists = make_hrhists(rhists, isplits, timetable)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 121,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_movements():\n",
|
|
" movements_path = '../Intermediates/movement/'\n",
|
|
" movements_list = [pd.read_csv(movements_path + file, index_col=0) for file in tqdm(os.listdir(movements_path))]\n",
|
|
" movements = pd.concat(movements_list)\n",
|
|
" movements = movements.drop(columns=['start_unix'])\n",
|
|
" movements = movements.drop_duplicates()\n",
|
|
" movements = movements.sort_values(by=['inter_no', 'phas_A', 'phas_B'])\n",
|
|
" movements = movements.reset_index(drop=True)\n",
|
|
" movements.to_csv('../Intermediates/movements.csv')\n",
|
|
" return movements\n",
|
|
"movements = pd.read_csv('../Intermediates/movements.csv')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 122,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def update_movement(hrhists, movement, movements):\n",
|
|
" # 중복을 제거하고 (inter_no, start_unix) 쌍을 만듭니다.\n",
|
|
" hrhists_inter_unix = set(hrhists[['inter_no', 'start_unix']].drop_duplicates().itertuples(index=False, name=None))\n",
|
|
" movement_inter_unix = set(movement[['inter_no', 'start_unix']].drop_duplicates().itertuples(index=False, name=None))\n",
|
|
"\n",
|
|
" # hrhists에는 있지만 movement에는 없는 (inter_no, start_unix) 쌍을 찾습니다.\n",
|
|
" missing_in_movement = hrhists_inter_unix - movement_inter_unix\n",
|
|
"\n",
|
|
" # 새로운 행들을 생성합니다.\n",
|
|
" new_rows = []\n",
|
|
" if missing_in_movement:\n",
|
|
" for inter_no, start_unix in missing_in_movement:\n",
|
|
" # movements에서 해당 inter_no의 데이터를 찾습니다.\n",
|
|
" new_row = movements[movements['inter_no'] == inter_no].copy()\n",
|
|
" # start_unix 값을 설정합니다.\n",
|
|
" new_row['start_unix'] = start_unix\n",
|
|
" new_rows.append(new_row)\n",
|
|
"\n",
|
|
" # 새로운 데이터프레임을 생성하고 기존 movement 데이터프레임과 합칩니다.\n",
|
|
" new_movement = pd.concat(new_rows, ignore_index=True)\n",
|
|
" movement_updated = pd.concat([movement, new_movement], ignore_index=True)\n",
|
|
" else:\n",
|
|
" movement_updated = movement\n",
|
|
" return movement_updated\n",
|
|
"movement = pd.read_csv(f'../Intermediates/movement/movement_{present_time}.csv', index_col=0)\n",
|
|
"movement_updated = update_movement(hrhists, movement, movements)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 123,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def make_histid(present_time, movedur, inter2node):\n",
|
|
" # 이동류 매칭 테이블에서 진입id, 진출id를 가져와서 붙임.\n",
|
|
" for i, row in movedur.iterrows():\n",
|
|
" inter_no = row.inter_no\n",
|
|
" start_unix = row.start_unix\n",
|
|
" # incoming and outgoing edges A\n",
|
|
" move_A = row.move_A\n",
|
|
" if move_A in [17, 18]:\n",
|
|
" inc_edge_A = np.nan\n",
|
|
" out_edge_A = np.nan\n",
|
|
" else:\n",
|
|
" match_A = matching[(matching.inter_no == inter_no) & (matching.move_no == move_A)].iloc[0]\n",
|
|
" inc_edge_A = match_A.inc_edge\n",
|
|
" out_edge_A = match_A.out_edge\n",
|
|
" movedur.loc[i, ['inc_edge_A', 'out_edge_A']] = [inc_edge_A, out_edge_A]\n",
|
|
" # incoming and outgoing edges B\n",
|
|
" move_B = row.move_B\n",
|
|
" if move_B in [17, 18]:\n",
|
|
" inc_edge_B = np.nan\n",
|
|
" out_edge_B = np.nan\n",
|
|
" else:\n",
|
|
" match_B = matching[(matching.inter_no == inter_no) & (matching.move_no == move_B)].iloc[0]\n",
|
|
" inc_edge_B = match_B.inc_edge\n",
|
|
" out_edge_B = match_B.out_edge\n",
|
|
" movedur.loc[i, ['inc_edge_B', 'out_edge_B']] = [inc_edge_B, out_edge_B]\n",
|
|
"\n",
|
|
" # 이동류 컬럼 제거\n",
|
|
" movedur = movedur.drop(['move_A', 'move_B'], axis=1)\n",
|
|
"\n",
|
|
" histid = movedur.copy() # history with edge ids (incoming and outgoing edge ids)\n",
|
|
" histid['node_id'] = histid['inter_no'].map(inter2node)\n",
|
|
" histid = histid[['inter_no', 'node_id', 'start_unix', 'phas_A', 'phas_B', 'duration', 'inc_edge_A', 'out_edge_A', 'inc_edge_B', 'out_edge_B']]\n",
|
|
" histid_start = present_time - 1200\n",
|
|
" histid = histid[histid.start_unix > histid_start]\n",
|
|
" return histid\n",
|
|
"# movedur\n",
|
|
"movedur = pd.merge(movement_updated, hrhists, how='inner', on=['inter_no', 'start_unix', 'phas_A', 'phas_B']) # movements and durations\n",
|
|
"movedur = movedur.sort_values(by=['start_unix', 'inter_no', 'phas_A','phas_B'])\n",
|
|
"movedur = movedur[['inter_no', 'start_unix', 'phas_A', 'phas_B', 'move_A', 'move_B', 'duration']]\n",
|
|
"histid = make_histid(present_time, movedur, inter2node)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 124,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"2024-01-05 08:45:00\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>inter_no</th>\n",
|
|
" <th>node_id</th>\n",
|
|
" <th>start_unix</th>\n",
|
|
" <th>phas_A</th>\n",
|
|
" <th>phas_B</th>\n",
|
|
" <th>duration</th>\n",
|
|
" <th>inc_edge_A</th>\n",
|
|
" <th>out_edge_A</th>\n",
|
|
" <th>inc_edge_B</th>\n",
|
|
" <th>out_edge_B</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>1621</th>\n",
|
|
" <td>177</td>\n",
|
|
" <td>i2</td>\n",
|
|
" <td>1704410710</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>-571542809_01</td>\n",
|
|
" <td>571542811_01</td>\n",
|
|
" <td>571542811_02</td>\n",
|
|
" <td>571542809_01</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1622</th>\n",
|
|
" <td>177</td>\n",
|
|
" <td>i2</td>\n",
|
|
" <td>1704410710</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>25</td>\n",
|
|
" <td>571542811_02</td>\n",
|
|
" <td>571542107_01</td>\n",
|
|
" <td>-571542809_01</td>\n",
|
|
" <td>571542809_01</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1623</th>\n",
|
|
" <td>177</td>\n",
|
|
" <td>i2</td>\n",
|
|
" <td>1704410710</td>\n",
|
|
" <td>3</td>\n",
|
|
" <td>3</td>\n",
|
|
" <td>71</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1624</th>\n",
|
|
" <td>177</td>\n",
|
|
" <td>i2</td>\n",
|
|
" <td>1704410710</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>34</td>\n",
|
|
" <td>-571542809_01</td>\n",
|
|
" <td>571542811_01</td>\n",
|
|
" <td>571542107_02</td>\n",
|
|
" <td>571542809_01</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>876</th>\n",
|
|
" <td>176</td>\n",
|
|
" <td>i1</td>\n",
|
|
" <td>1704410720</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>37</td>\n",
|
|
" <td>-571542810_01</td>\n",
|
|
" <td>-571542797_02.99</td>\n",
|
|
" <td>571542797_02.99</td>\n",
|
|
" <td>571542810_01</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>...</th>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" <td>...</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1671</th>\n",
|
|
" <td>201</td>\n",
|
|
" <td>i8</td>\n",
|
|
" <td>1704412330</td>\n",
|
|
" <td>3</td>\n",
|
|
" <td>3</td>\n",
|
|
" <td>18</td>\n",
|
|
" <td>571500617_02</td>\n",
|
|
" <td>571500618_01</td>\n",
|
|
" <td>571500618_02</td>\n",
|
|
" <td>571500617_01</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1672</th>\n",
|
|
" <td>201</td>\n",
|
|
" <td>i8</td>\n",
|
|
" <td>1704412330</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>58</td>\n",
|
|
" <td>571500617_02</td>\n",
|
|
" <td>571500618_01</td>\n",
|
|
" <td>571500617_02</td>\n",
|
|
" <td>571500569_01</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1673</th>\n",
|
|
" <td>201</td>\n",
|
|
" <td>i8</td>\n",
|
|
" <td>1704412330</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>18</td>\n",
|
|
" <td>571500583_01</td>\n",
|
|
" <td>571500617_01</td>\n",
|
|
" <td>571500583_01</td>\n",
|
|
" <td>571500569_01</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1486</th>\n",
|
|
" <td>202</td>\n",
|
|
" <td>i9</td>\n",
|
|
" <td>1704412340</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>26</td>\n",
|
|
" <td>571510152_02</td>\n",
|
|
" <td>-571510152_01</td>\n",
|
|
" <td>571510152_01</td>\n",
|
|
" <td>571510152_01.65</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1487</th>\n",
|
|
" <td>202</td>\n",
|
|
" <td>i9</td>\n",
|
|
" <td>1704412340</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>64</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"<p>343 rows × 10 columns</p>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" inter_no node_id start_unix phas_A phas_B duration inc_edge_A \\\n",
|
|
"1621 177 i2 1704410710 1 1 40 -571542809_01 \n",
|
|
"1622 177 i2 1704410710 2 2 25 571542811_02 \n",
|
|
"1623 177 i2 1704410710 3 3 71 NaN \n",
|
|
"1624 177 i2 1704410710 4 4 34 -571542809_01 \n",
|
|
"876 176 i1 1704410720 1 1 37 -571542810_01 \n",
|
|
"... ... ... ... ... ... ... ... \n",
|
|
"1671 201 i8 1704412330 3 3 18 571500617_02 \n",
|
|
"1672 201 i8 1704412330 4 4 58 571500617_02 \n",
|
|
"1673 201 i8 1704412330 5 5 18 571500583_01 \n",
|
|
"1486 202 i9 1704412340 1 1 26 571510152_02 \n",
|
|
"1487 202 i9 1704412340 2 2 64 NaN \n",
|
|
"\n",
|
|
" out_edge_A inc_edge_B out_edge_B \n",
|
|
"1621 571542811_01 571542811_02 571542809_01 \n",
|
|
"1622 571542107_01 -571542809_01 571542809_01 \n",
|
|
"1623 NaN NaN NaN \n",
|
|
"1624 571542811_01 571542107_02 571542809_01 \n",
|
|
"876 -571542797_02.99 571542797_02.99 571542810_01 \n",
|
|
"... ... ... ... \n",
|
|
"1671 571500618_01 571500618_02 571500617_01 \n",
|
|
"1672 571500618_01 571500617_02 571500569_01 \n",
|
|
"1673 571500617_01 571500583_01 571500569_01 \n",
|
|
"1486 -571510152_01 571510152_01 571510152_01.65 \n",
|
|
"1487 NaN NaN NaN \n",
|
|
"\n",
|
|
"[343 rows x 10 columns]"
|
|
]
|
|
},
|
|
"execution_count": 124,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"def preprocess(m):\n",
|
|
" '''\n",
|
|
" 통합테이블(histid)를 만드는 함수\n",
|
|
"\n",
|
|
" input : m\n",
|
|
" - m ranges from 0 to 287, but 0 makes an error where 288 = 86400//300\n",
|
|
" - present_time = fmins[m] : 현재시점\n",
|
|
"\n",
|
|
" output : histid (통합테이블, HISTory with edge_IDs)\n",
|
|
" - 컬럼 : inter_no, node_id, start_unix, phas_A, phas_B, duration, inc_edge_A, out_edge_A, inc_edge_B, out_edge_B\n",
|
|
"\n",
|
|
" 주요 데이터, 중간산출물 및 결과물 :\n",
|
|
" # 데이터\n",
|
|
" - history : 신호이력 (inter_no, end_unix, dura_Aj, dura_Bj, cycle, offset)\n",
|
|
" - plan : 신호계획 (inter_no, start_hour, start_minute, dura_Aj, dura_Bj cycle, offset)\n",
|
|
" # 중간산출물\n",
|
|
" - rhists (recent history)\n",
|
|
" - history에서 현재 시각 이전의 데이터를 가져옴.\n",
|
|
" - end_unix를 start_unix로 변환\n",
|
|
" - 참값판단 프로세스(결측·이상치 처리)\n",
|
|
" - 컬럼 : inter_no, start_unix, dura_Aj, dura_Bj, cycle\n",
|
|
" - hrhists (hierarchized recent history)\n",
|
|
" - rhists를 계층화\n",
|
|
" - 컬럼 : inter_no, start_unix, phas_A, phas_B, duration\n",
|
|
" - movements\n",
|
|
" - 각 교차로에 대하여 현시별로 이동류를 정해놓음.\n",
|
|
" - join시 사용하기 위함.\n",
|
|
" - 한 번 만들어놓고 두고두고 사용함.\n",
|
|
" - 컬럼 : inter_no, phas_A, phas_B, move_A, move_B\n",
|
|
" - movement\n",
|
|
" - 현재 시점에서의 이동류정보\n",
|
|
" - 컬럼 : inter_no, phas_A, phas_B, move_A, move_B, start_unix\n",
|
|
" - movement_updated\n",
|
|
" - movement와 hrhists를 join하기 전에, movement에는 없지만 hrhists에는 있는 start_unix에 대한 이동류 정보를 가져와 movement에 붙임\n",
|
|
" - 이동류정보는 앞서 정의한 movements에서 가져옴.\n",
|
|
" - 컬럼 : inter_no, phas_A, phas_B, move_A, move_B, start_unix\n",
|
|
" - movedur\n",
|
|
" - hrhists와 movement_updated를 join\n",
|
|
" - 컬럼 : inter_no, phas_A, phas_B, move_A, move_B, start_unix, duration\n",
|
|
" # 결과 : histid\n",
|
|
" - 신호생성에 직접적으로 사용되는 데이터프레임\n",
|
|
" - 컬럼 : inter_no, node_id, start_unix, phas_A, phas_B, duration, inc_edge_A, out_edge_A, inc_edge_B, out_edge_B\n",
|
|
" - 한글컬럼 : 교차로번호, 노드id, 시작유닉스, A현시번호, B현시번호, 현시시간, 진입엣지(A), 진출엣지(A), 진입엣지(B), 진출엣지(B)\n",
|
|
" '''\n",
|
|
" midnight = int(datetime(2024, 1, 5, 0, 0, 0).timestamp())\n",
|
|
" next_day = int(datetime(2024, 1, 6, 0, 0, 0).timestamp())\n",
|
|
" fmins = range(midnight, next_day, 300) # fmins : unix time by Five MINuteS\n",
|
|
" # 현재시각\n",
|
|
" present_time = fmins[m]\n",
|
|
" print(datetime.fromtimestamp(present_time))\n",
|
|
" # 사용할 표준 테이블 목록\n",
|
|
" plan = pd.read_csv('../Data/tables/plan.csv', index_col=0)\n",
|
|
" history = pd.read_csv('../Data/tables/history.csv', index_col=0)\n",
|
|
" # 참고할 딕셔너리, 데이터프레임, 리스트 등 목록\n",
|
|
" splits, isplits = make_splits(plan)\n",
|
|
" timetable = make_timetable(plan)\n",
|
|
" inter_node = pd.read_csv('../Data/tables/inter_node.csv', index_col=0)\n",
|
|
" inter_node = inter_node[inter_node.inter_type=='parent']\n",
|
|
" inter2node = dict(zip(inter_node['inter_no'], inter_node['node_id']))\n",
|
|
" hours = np.array(range(midnight - 7200, next_day + 1, 3600)) # 정각에 해당하는 시각들 목록\n",
|
|
" # rhistory, rhists, hrhists\n",
|
|
" adder = 600\n",
|
|
" rhistory = make_rhistory(history, present_time, adder)\n",
|
|
" rhists = processing(rhistory, hours)\n",
|
|
" hrhists = make_hrhists(rhists, isplits, timetable)\n",
|
|
" # movements, movement, movement_updated\n",
|
|
" movements = pd.read_csv('../Intermediates/movements.csv')\n",
|
|
" movement = pd.read_csv(f'../Intermediates/movement/movement_{present_time}.csv', index_col=0)\n",
|
|
" movement_updated = update_movement(hrhists, movement, movements)\n",
|
|
" # movedur\n",
|
|
" movedur = pd.merge(movement_updated, hrhists, how='inner', on=['inter_no', 'start_unix', 'phas_A', 'phas_B']) # movements and durations\n",
|
|
" movedur = movedur.sort_values(by=['start_unix', 'inter_no', 'phas_A','phas_B'])\n",
|
|
" movedur = movedur[['inter_no', 'start_unix', 'phas_A', 'phas_B', 'move_A', 'move_B', 'duration']]\n",
|
|
" # histid\n",
|
|
" histid = make_histid(present_time, movedur, inter2node)\n",
|
|
" histid.to_csv(f'../Intermediates/histid/histid_{fmins[m]}.csv')\n",
|
|
" return histid\n",
|
|
"preprocess(105)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 125,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"1704411900\n",
|
|
"2024-01-05 08:45:00\n",
|
|
"175\n",
|
|
"1529\n",
|
|
"True True\n",
|
|
"176\n",
|
|
"1530\n",
|
|
"True True\n",
|
|
"177\n",
|
|
"1620\n",
|
|
"True True\n",
|
|
"178\n",
|
|
"1580\n",
|
|
"True True\n",
|
|
"201\n",
|
|
"1600\n",
|
|
"True True\n",
|
|
"202\n",
|
|
"1530\n",
|
|
"True True\n",
|
|
"206\n",
|
|
"1540\n",
|
|
"True True\n",
|
|
"210\n",
|
|
"1530\n",
|
|
"True True\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "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+OIL/eQnP9H8+fM77d+xY4dGjx4dccvPz5fD4dAbb7whSWpoaNDMmTM1atQo5efn65577un0ubxer1wul5566qlO++fPn9/p763s2bNH5eXluuaaa6Ka24oVK3TyyScrLy9P48eP1yuvvBLV47uD4AEAQDfdeOONGjt2rFauXNnpD8FJod9Q2rp1a8Rt/vz5OuOMMzRp0iRJ0sUXX6zx48dr27ZtWrt2re6991799a9/7fBc8+bN6/Ln5nft2qWKiooO7QsWLNBRRx2lpUuXdvun6iXp7bff1qWXXqrHH39cXq9XixYt0oUXXqjdu3d3+zm6g+ABAEA3paena926dTr77LO7/ZhgMKibb75Zd9xxhyTpgw8+0IYNGzR37lw5HA6NHDlS1113nR555JGIx23atEnr1q3r8vd5brnlFnk8ng7tTqdTK1as0OzZs6OYWehXbH/0ox+psLBQknT22WfrzDPP1H//939H9TwHQ/AAAKCdSy+9VP/4xz86tM+dO1dHHnlkVM+1dOlS5eTk6Mwzz5QkrV27VqeeemrEDwiedtpp2rhxY/h+MBjUnDlzdM8998jpdHZ4zk2bNunFF19UaWlph77S0lKdcMIJXdbzwAMPaNy4cRo9erQuuOACffbZZ5JCPwbX0tISMTYzM1MffPBBVPM9GIIHAABxdM8996isrCx8v76+XkcccUTEmBEjRqihoSF8f/78+TruuONUXFzc4fkCgYBmz56t++67T4MGDYqqlocfflgPP/ywVq9era1bt6qwsFBXXnmlJGnGjBn685//rPXr10sKBaSqqir5fL6o/sbBDDz4EAAA+r5HHnlEt912myTp888/1/Lly8Nf3Hz77bc1bNiwqJ/zzTff1I4dOzRt2rRwW0tLS4fvhwSDQTkcDknSunXr9Nhjj4W/iNrejTfeqHPOOUfFxcXaunVrVPX8/ve/17333hsOPr/85S81fPhw7du3T5MnT9Yf//hH/fSnP5XP59Ppp5+uadOmaciQIVH9jYMheAAAIOnyyy/X5ZdfLin0Ucull17a6TsO0XjkkUd00UUXacCArz9gGD58ePhdhTY+n0/f+MY35PP5dNFFF2nx4sUaOnRoh+dbsmSJqqurtXbt2h7Vs2XLFs2ePTvi45shQ4bos88+U05OjmbMmKEZM2aE+2bOnKlTTjmlR3+rKwQPAADiIBgMasmSJXrppZci2idNmqRbb71Vra2t4UCyZs0aTZ48WX/5y1/0ySef6Hvf+154/K5du/T666/rpZdeUk1NjT788MPwOxatra0KBAJyu916+umn9a1vfeuANY0cOVKVlZWaOHHiQev3+/1asWKFFixYEOXMD4zveAAAEAevv/66jDE66aSTItpPPfVUZWdna/78+WptbdWWLVt0//3369prr9U111yjPXv2yO/3h29nnHFG+LsZr732mnbu3Bnue/vtt+VyueT3+w8aOiTpkksu0dy5c7Vjxw5JoWuOvPzyy5KkvXv3asuWLZKkxsZGXX755briiiuUl5cX0/9eCB4AALTz2GOPRf0xy8yZM7Vq1arw/XXr1unEE0/sMM7hcKiqqkorVqzQEUccofPOO0933313+Bof8fSrX/1KEyZM0KRJk3TkkUfqW9/6lhobGyWFgsfUqVOVl5enSZMmacKECbr77rtjXoPDdHUFFAAAgBjjHQ8AAGANwQMAAFhD8AAAANYQPAAAgDUEDwAAYA3BAwAAWEPwAAAA1hA8AACANQQPAABgDcEDAABYQ/AAAADWEDwAAIA1/x+lki5K+V4s7wAAAABJRU5ErkJggg==",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"m = 105\n",
|
|
"present_time = fmins[m]\n",
|
|
"print(present_time)\n",
|
|
"histid = preprocess(m)\n",
|
|
"k = 0\n",
|
|
"for inter_no in sorted(histid.inter_no.unique()):\n",
|
|
" k += 1\n",
|
|
" df = histid[histid.inter_no==inter_no]\n",
|
|
" M = df.start_unix.max()\n",
|
|
" m = df.start_unix.min()\n",
|
|
" print(inter_no)\n",
|
|
" print(M - m)\n",
|
|
" plt.scatter([M, m], [k] * 2, c='y')\n",
|
|
" plt.scatter([present_time], [k], c='b')\n",
|
|
" plt.axvline(x=histid.start_unix.max(), c='r')\n",
|
|
" plt.axvline(x=histid.start_unix.min(), c='r')\n",
|
|
" print(m < present_time, present_time < M)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 126,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"2024-01-05 08:45:00\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAh4AAAHCCAYAAACg18CDAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/OQEPoAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA/x0lEQVR4nO3deXhU5eH28XuSwIRANghLCEkIS0FkE3DBjUUUapHWBX9CVSi2EOuWUjfADRUBX6WKrbRaBdSKWPc1gOKCBQUUREBFQSllkRjJwpaQzPP+QTNlkskyycwzc8L3c1252plzzpz7eYZkbs+cM+MyxhgBAABYEBXuAAAA4PhB8QAAANZQPAAAgDUUDwAAYA3FAwAAWEPxAAAA1lA8AACANRQPAABgDcUDAGoxcuRI3XbbbdUu/+ijjxQbG2sxEeBcFA/AEpfLpVdeeaXW9Tp27KiHHnoo5HkQGGOMysrK/P6Ul5eHOx7gGBQPAA2ycOFC9evXT82aNVNycrJuvPFGn+Vff/21RowYoRYtWiglJUVXX321Dhw44LNOYWGhJk2apJSUFDVv3lw///nPtXXr1jpn2LRpk9q3b69du3b53L9lyxadccYZfgufMUb/7//9P2VlZSk2NlYnnXSSli5dWu0+7rvvPjVp0sTvz+DBg6usv2vXLrVr105ffPFFnccBHA8oHgDq7c4779TUqVN1/fXXa926dXrnnXc0bNgw7/K9e/dq8ODBat++vVatWqVnn31Wb731lq666iqfx7nooou0YcMGvfrqq/rwww915MgRnXvuuTp06FCtGTwej6644grNmjVL7du3lyRt2LBBkyZNUt++fbVy5Uq/291zzz168MEHNWfOHH322WcaNGiQLrjgAm3YsMHv+pMnT1ZeXp7fnzfeeKPK+u3bt9f999+vK6+8Uh6Pp9ZxAMcNA8AKSebll1+udb3MzEzzpz/9qUH7Ki8vb9D2dbFu3ToTGxtrvv7662rXufXWW03fvn198uTm5hqXy2W+/fZb72232212797tXSc/P9/ExcWZJ554otYcL7/8sunatavPPgYNGmROO+00s2LFCr/z/tNPP5lmzZqZl156yef+gQMHmiuuuKLKPn7xi1+Ym2++2RQXF/v9Wbp0qXG73VW2Ky8vN126dKnT8w4cLzjiAQRg+/bt+t3vfqesrCzFxcWpd+/eevPNN33WMcZo1qxZ3kP4AwYM0Mcff+z38Z544gmdcMIJcrvd6tGjh9//cpak3NxcDRgwQLGxscrMzNScOXN8lg8ePFg5OTl64IEHlJSUpLFjxwZnwDWYO3euxo4dq5/97GfVrvPKK69o7Nixior635+a8847T4mJiXrnnXe865xzzjlq166dd52WLVtq2LBhWrZsWa055s2bp2uuucZnH4sWLdKqVat05pln+t1m6dKliomJ0ahRo3zuHz16dLX7vP/++xUfH+/357zzzvO7TVRUlK699lo9+uijtY4DOF5QPIAAvP7664qNjdUzzzyjNWvW6IwzztCll16q3bt3e9e5+eabdd9992nq1Klas2aNrrvuOo0bN67KY/3lL3/R1VdfrQkTJmjNmjWaMWOGbrzxRv34448+67355psaNWqUzj//fK1evVrTp0/XHXfcoWeeecZnvZUrV2r16tV6//33NW3atBrHce+99yo2Nrbanw8//LDWuVi6dKnOOussXXfddUpNTVWbNm00fvx4/fTTT5Kk0tJSbdmyRb169fLZzuVyqXv37vr2228lSRs3bqyyjiT16NHDu051SktLtWLFCg0fPtzn/tTU1Bq327hxo3r06KHo6Ogq+9yzZ4/279/vc/8LL7yg4uLiGn/y8/P97mv48OH66KOPVFpaWmMm4HgRE+4AgJNMnDhRTZs29d5+6KGHNH/+fK1YsUKXXnqpduzYoT/96U969tlndemll0qSevXqpaSkJP3qV7/ybnfw4EFNmzZN9957r2666SZJUu/evdWpUyf17dvXZ5833HCDJk6cqLvvvtu73o4dOzRr1ixdfvnl3vW+++47rVixQm63u9ZxZGdn65JLLql2eUZGRo3bFxcXa+fOnZo7d64GDx6sV155Rf/5z39044036rLLLtPSpUv1008/yePxqFWrVlW2b9mypQoLCyVJeXl5ta5TnQ0bNqhZs2bq3r17jetVVtM+JamoqEjNmzevchJsTYwx3sISGxurmJijf167d++uZs2aacOGDRowYEBAOYHGiOIBBKBp06Y6fPiwPv74Y3355Zf69ttvFRUVpT179kiSli1bptjYWI0ePdpnu8qH4j/++GMVFhZq/PjxPvf36dNHbdq08d7esmWLtm7dqgkTJvisd9ZZZ+muu+7SkSNH1KRJE0nS0KFD61Q6JCklJUUpKSl1WtefoqIiSVLfvn29b/uceuqp6tChg0477TStWbPGe9Th2LdAKrhcLrlcLklSWVlZretUZ8+ePT5v0dRVTfus+N/t27crKysr4MeWjr79k52d7b3dtm1b/fDDD/V6LKCxoXgAAVi0aJGys7PVoUMH9erVS506dVJsbKz3qoU9e/aoQ4cOVV4wmzVr5nN7z549crvdPiXD37p5eXmSpNNPP91nHWOMPB6P9uzZo/T0dElHX9xsqSg7559/vs/9p556quLj47Vx40Z169ZNkvwetSgoKFDv3r0lSQkJCdWu4++oxLEKCwuVnJwccP6EhARt2bLF7z5dLpeSk5PldrtVXFzsd/snnnhCTzzxRLVXzFT+MLHk5ORaj94AxwvO8QDqaN++fbrqqqv0yCOPaNOmTXruued03333eQ+pS1Lr1q2rnKMhqcp/7bZu3VolJSVVXtiMMd6yIUlJSUmSjp7nsX79eu/P559/ri+//NLnv/b9/Rd8dRp6jkfr1q3VokULFRQUVFlWUboSEhLUtm1bffXVV1XG+PXXX6tnz56SpJ/97GdV1pGkL7/80rtOdeLj471HXwJR0z67dOmi2NhYuVwutWjRQi1atNDcuXP1xRdfeG+73W5FRUV5b1f+OfbfhHS0IMXHxwecE2iMKB5AHX377bc6dOiQzjnnHO99n3/+uU9R6Nu3r/Lz87V8+XKfbZ9//nmf2z179lRMTIz++c9/+tz/xhtv6ODBg97b3bt3V0pKirZt26bu3btX+ak48hCo7OxsnyJT+ae2cxFcLpeGDRumRYsW+dy/YsUKFRcX64wzzpB09MTK5557zmed5cuXa//+/d4TQocPH64lS5b4lJiCggItW7ZMv/zlL2vM0aZNm3q9hXHeeefpxx9/rPI8/fOf//S7z2effVabNm0KeD8V9u7dq9atW9d7e6Ax4a0WoI66dOmi5s2b64477tDkyZO1bds23X333d4TEiXp5JNP1vDhw/XrX/9aDz/8sE444QS9++67evHFF30eKzU1VVdddZVycnLk8Xi850XMnTvX59yL6Oho3XbbbfrjH/+oAwcOaOjQoTp48KA+/PBDlZeXa8qUKfUaS0PP8ZCk2267TaeffromTZqkSZMmaceOHbr22ms1fvx47yW2t9xyi/r376+cnBxNnDhR//73v5Wdna2bb77Z+zbK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72rxeDzatWuX4uPj5XI544t5jlVUVKT09HTt2LGj0X3XTGMem9S4x8fYnKsxj4+xOZe/8RljVFxcrPbt2ysqquFnaFg74hEVFaUOHTrY2l3IJCQkNMp/bFLjHpvUuMfH2JyrMY+PsTlX5fEF40hHBU4uBQAA1lA8AACANRSPOnK73brzzjvldrvDHSXoGvPYpMY9PsbmXI15fIzNuWyMz9rJpQAAABzxAAAA1lA8AACANRQPAABgDcUDAABYQ/GQtHPnTl1wwQVKS0tTp06ddM8993iXrVu3TqeddpoyMzPVo0cPLVu2zGfbhx56SF26dFFaWpouvPBC5efn245fhTFGTz31lAYOHOhzf0PGkp+fr9GjRysjI0OZmZl68MEHrYzFH3/jO3LkiO6++2716tVL6enpOuuss7R+/Xqf7RYtWqQTTjhBHTp00JAhQ/Tdd995lx06dEgTJ05UZmamOnTooJtvvjlo30sQiOqeuwoHDhxQ69atNWvWLJ/7nfDcVTc2Y4zmzJmjbt26KSMjQ126dNGRI0e8y50wNqn68b3yyis68cQTlZGRoVNOOUUfffSRz/JIH9/y5ct1xhlnqEuXLurcubMeeeQR77Lvv/9e5557rjIzM9WlSxc988wzPts64XeuuvEZY/Too4+qT58+yszMVL9+/bR8+XKfbd955x316dNHGRkZGjBggD777DPvMo/HoylTpqhjx45KS0vThAkTdPjw4YgY27GMMerZs6eys7N97g/pc2dghg4dam6++Wbj8XhMfn6+6dOnj5k/f74pKioyaWlpZtmyZcYYY95//32TmJhodu/ebYwxZvHixeakk04y+fn5pqyszGRnZ5uLLroonEMxb7/9tunZs6fp3Lmz6datm/f+ho7l5z//ubnrrruMx+MxO3fuNJmZmea1116zOzhT/fg2btxobr/9drN//35jjDF//etfTYcOHUxpaakxxpiVK1eajh07mu3btxtjjJkxY4bp37+/d/urr77aXHXVVebIkSOmoKDADBgwwMydO9fiyKof27Fmz55toqOjzcyZM733OeG5q2ls99xzjxk0aJD54YcfjDHG7Ny505SXlxtjnDE2Y6of37Zt20x8fLxZs2aNMcaYpUuXmuTkZFNQUGCMccb4rr/+evPVV18ZY4zZunWrSUtLM2+//bYpKyszPXv2NPPnzzfG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",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"import matplotlib as mpl\n",
|
|
"mpl.rcParams['font.family'] = 'Malgun Gothic'\n",
|
|
"\n",
|
|
"m = 105\n",
|
|
"present_time = fmins[m]\n",
|
|
"histid = preprocess(m)\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"k = 0\n",
|
|
"for node_id, group in histid.groupby('node_id'):\n",
|
|
" k += 1\n",
|
|
" plt.plot(group.start_unix.unique(), [k] * len(group.start_unix.unique()), marker='o')\n",
|
|
" plt.axvline(present_time - 300, c='r', linewidth=.5)\n",
|
|
" plt.axvline(present_time, c='r', linewidth=.5)\n",
|
|
" plt.title('adder = 600 (10분)')\n",
|
|
" plt.savefig('../Analysis/0201_adder/adder=600.png')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"preprocess(105)\n",
|
|
"preprocess(106)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 23,
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"30\n",
|
|
"2024-01-05 02:30:00\n",
|
|
"31\n",
|
|
"2024-01-05 02:35:00\n",
|
|
"32\n",
|
|
"2024-01-05 02:40:00\n",
|
|
"33\n",
|
|
"2024-01-05 02:45:00\n",
|
|
"34\n",
|
|
"2024-01-05 02:50:00\n",
|
|
"35\n",
|
|
"2024-01-05 02:55:00\n",
|
|
"36\n",
|
|
"2024-01-05 03:00:00\n",
|
|
"37\n",
|
|
"2024-01-05 03:05:00\n",
|
|
"38\n",
|
|
"2024-01-05 03:10:00\n",
|
|
"39\n",
|
|
"2024-01-05 03:15:00\n",
|
|
"40\n",
|
|
"2024-01-05 03:20:00\n",
|
|
"41\n",
|
|
"2024-01-05 03:25:00\n",
|
|
"42\n",
|
|
"2024-01-05 03:30:00\n",
|
|
"43\n",
|
|
"2024-01-05 03:35:00\n",
|
|
"44\n",
|
|
"2024-01-05 03:40:00\n",
|
|
"45\n",
|
|
"2024-01-05 03:45:00\n",
|
|
"46\n",
|
|
"2024-01-05 03:50:00\n",
|
|
"47\n",
|
|
"2024-01-05 03:55:00\n",
|
|
"48\n",
|
|
"2024-01-05 04:00:00\n",
|
|
"49\n",
|
|
"2024-01-05 04:05:00\n",
|
|
"50\n",
|
|
"2024-01-05 04:10:00\n",
|
|
"51\n",
|
|
"2024-01-05 04:15:00\n",
|
|
"52\n",
|
|
"2024-01-05 04:20:00\n",
|
|
"53\n",
|
|
"2024-01-05 04:25:00\n",
|
|
"54\n",
|
|
"2024-01-05 04:30:00\n",
|
|
"55\n",
|
|
"2024-01-05 04:35:00\n",
|
|
"56\n",
|
|
"2024-01-05 04:40:00\n",
|
|
"57\n",
|
|
"2024-01-05 04:45:00\n",
|
|
"58\n",
|
|
"2024-01-05 04:50:00\n",
|
|
"59\n",
|
|
"2024-01-05 04:55:00\n",
|
|
"60\n",
|
|
"2024-01-05 05:00:00\n",
|
|
"61\n",
|
|
"2024-01-05 05:05:00\n",
|
|
"62\n",
|
|
"2024-01-05 05:10:00\n",
|
|
"63\n",
|
|
"2024-01-05 05:15:00\n",
|
|
"64\n",
|
|
"2024-01-05 05:20:00\n",
|
|
"65\n",
|
|
"2024-01-05 05:25:00\n",
|
|
"66\n",
|
|
"2024-01-05 05:30:00\n",
|
|
"67\n",
|
|
"2024-01-05 05:35:00\n",
|
|
"68\n",
|
|
"2024-01-05 05:40:00\n",
|
|
"69\n",
|
|
"2024-01-05 05:45:00\n",
|
|
"70\n",
|
|
"2024-01-05 05:50:00\n",
|
|
"71\n",
|
|
"2024-01-05 05:55:00\n",
|
|
"72\n",
|
|
"2024-01-05 06:00:00\n",
|
|
"73\n",
|
|
"2024-01-05 06:05:00\n",
|
|
"74\n",
|
|
"2024-01-05 06:10:00\n",
|
|
"75\n",
|
|
"2024-01-05 06:15:00\n",
|
|
"76\n",
|
|
"2024-01-05 06:20:00\n",
|
|
"77\n",
|
|
"2024-01-05 06:25:00\n",
|
|
"78\n",
|
|
"2024-01-05 06:30:00\n",
|
|
"79\n",
|
|
"2024-01-05 06:35:00\n",
|
|
"80\n",
|
|
"2024-01-05 06:40:00\n",
|
|
"81\n",
|
|
"2024-01-05 06:45:00\n",
|
|
"82\n",
|
|
"2024-01-05 06:50:00\n",
|
|
"83\n",
|
|
"2024-01-05 06:55:00\n",
|
|
"84\n",
|
|
"2024-01-05 07:00:00\n",
|
|
"85\n",
|
|
"2024-01-05 07:05:00\n",
|
|
"86\n",
|
|
"2024-01-05 07:10:00\n",
|
|
"87\n",
|
|
"2024-01-05 07:15:00\n",
|
|
"88\n",
|
|
"2024-01-05 07:20:00\n",
|
|
"89\n",
|
|
"2024-01-05 07:25:00\n",
|
|
"90\n",
|
|
"2024-01-05 07:30:00\n",
|
|
"91\n",
|
|
"2024-01-05 07:35:00\n",
|
|
"92\n",
|
|
"2024-01-05 07:40:00\n",
|
|
"93\n",
|
|
"2024-01-05 07:45:00\n",
|
|
"94\n",
|
|
"2024-01-05 07:50:00\n",
|
|
"95\n",
|
|
"2024-01-05 07:55:00\n",
|
|
"96\n",
|
|
"2024-01-05 08:00:00\n",
|
|
"97\n",
|
|
"2024-01-05 08:05:00\n",
|
|
"98\n",
|
|
"2024-01-05 08:10:00\n",
|
|
"99\n",
|
|
"2024-01-05 08:15:00\n",
|
|
"100\n",
|
|
"2024-01-05 08:20:00\n",
|
|
"101\n",
|
|
"2024-01-05 08:25:00\n",
|
|
"102\n",
|
|
"2024-01-05 08:30:00\n",
|
|
"103\n",
|
|
"2024-01-05 08:35:00\n",
|
|
"104\n",
|
|
"2024-01-05 08:40:00\n",
|
|
"105\n",
|
|
"2024-01-05 08:45:00\n",
|
|
"106\n",
|
|
"2024-01-05 08:50:00\n",
|
|
"107\n",
|
|
"2024-01-05 08:55:00\n",
|
|
"108\n",
|
|
"2024-01-05 09:00:00\n",
|
|
"109\n",
|
|
"2024-01-05 09:05:00\n",
|
|
"110\n",
|
|
"2024-01-05 09:10:00\n",
|
|
"111\n",
|
|
"2024-01-05 09:15:00\n",
|
|
"112\n",
|
|
"2024-01-05 09:20:00\n",
|
|
"113\n",
|
|
"2024-01-05 09:25:00\n",
|
|
"114\n",
|
|
"2024-01-05 09:30:00\n",
|
|
"115\n",
|
|
"2024-01-05 09:35:00\n",
|
|
"116\n",
|
|
"2024-01-05 09:40:00\n",
|
|
"117\n",
|
|
"2024-01-05 09:45:00\n",
|
|
"118\n",
|
|
"2024-01-05 09:50:00\n",
|
|
"119\n",
|
|
"2024-01-05 09:55:00\n",
|
|
"120\n",
|
|
"2024-01-05 10:00:00\n",
|
|
"121\n",
|
|
"2024-01-05 10:05:00\n",
|
|
"122\n",
|
|
"2024-01-05 10:10:00\n",
|
|
"123\n",
|
|
"2024-01-05 10:15:00\n",
|
|
"124\n",
|
|
"2024-01-05 10:20:00\n",
|
|
"125\n",
|
|
"2024-01-05 10:25:00\n",
|
|
"126\n",
|
|
"2024-01-05 10:30:00\n",
|
|
"127\n",
|
|
"2024-01-05 10:35:00\n",
|
|
"128\n",
|
|
"2024-01-05 10:40:00\n",
|
|
"129\n",
|
|
"2024-01-05 10:45:00\n",
|
|
"130\n",
|
|
"2024-01-05 10:50:00\n",
|
|
"131\n",
|
|
"2024-01-05 10:55:00\n",
|
|
"132\n",
|
|
"2024-01-05 11:00:00\n",
|
|
"133\n",
|
|
"2024-01-05 11:05:00\n",
|
|
"134\n",
|
|
"2024-01-05 11:10:00\n",
|
|
"135\n",
|
|
"2024-01-05 11:15:00\n",
|
|
"136\n",
|
|
"2024-01-05 11:20:00\n",
|
|
"137\n",
|
|
"2024-01-05 11:25:00\n",
|
|
"138\n",
|
|
"2024-01-05 11:30:00\n",
|
|
"139\n",
|
|
"2024-01-05 11:35:00\n",
|
|
"140\n",
|
|
"2024-01-05 11:40:00\n",
|
|
"141\n",
|
|
"2024-01-05 11:45:00\n",
|
|
"142\n",
|
|
"2024-01-05 11:50:00\n",
|
|
"143\n",
|
|
"2024-01-05 11:55:00\n",
|
|
"144\n",
|
|
"2024-01-05 12:00:00\n",
|
|
"145\n",
|
|
"2024-01-05 12:05:00\n",
|
|
"146\n",
|
|
"2024-01-05 12:10:00\n",
|
|
"147\n",
|
|
"2024-01-05 12:15:00\n",
|
|
"148\n",
|
|
"2024-01-05 12:20:00\n",
|
|
"149\n",
|
|
"2024-01-05 12:25:00\n",
|
|
"150\n",
|
|
"2024-01-05 12:30:00\n",
|
|
"151\n",
|
|
"2024-01-05 12:35:00\n",
|
|
"152\n",
|
|
"2024-01-05 12:40:00\n",
|
|
"153\n",
|
|
"2024-01-05 12:45:00\n",
|
|
"154\n",
|
|
"2024-01-05 12:50:00\n",
|
|
"155\n",
|
|
"2024-01-05 12:55:00\n",
|
|
"156\n",
|
|
"2024-01-05 13:00:00\n",
|
|
"157\n",
|
|
"2024-01-05 13:05:00\n",
|
|
"158\n",
|
|
"2024-01-05 13:10:00\n",
|
|
"159\n",
|
|
"2024-01-05 13:15:00\n",
|
|
"160\n",
|
|
"2024-01-05 13:20:00\n",
|
|
"161\n",
|
|
"2024-01-05 13:25:00\n",
|
|
"162\n",
|
|
"2024-01-05 13:30:00\n",
|
|
"163\n",
|
|
"2024-01-05 13:35:00\n",
|
|
"164\n",
|
|
"2024-01-05 13:40:00\n",
|
|
"165\n",
|
|
"2024-01-05 13:45:00\n",
|
|
"166\n",
|
|
"2024-01-05 13:50:00\n",
|
|
"167\n",
|
|
"2024-01-05 13:55:00\n",
|
|
"168\n",
|
|
"2024-01-05 14:00:00\n",
|
|
"169\n",
|
|
"2024-01-05 14:05:00\n",
|
|
"170\n",
|
|
"2024-01-05 14:10:00\n",
|
|
"171\n",
|
|
"2024-01-05 14:15:00\n",
|
|
"172\n",
|
|
"2024-01-05 14:20:00\n",
|
|
"173\n",
|
|
"2024-01-05 14:25:00\n",
|
|
"174\n",
|
|
"2024-01-05 14:30:00\n",
|
|
"175\n",
|
|
"2024-01-05 14:35:00\n",
|
|
"176\n",
|
|
"2024-01-05 14:40:00\n",
|
|
"177\n",
|
|
"2024-01-05 14:45:00\n",
|
|
"178\n",
|
|
"2024-01-05 14:50:00\n",
|
|
"179\n",
|
|
"2024-01-05 14:55:00\n",
|
|
"180\n",
|
|
"2024-01-05 15:00:00\n",
|
|
"181\n",
|
|
"2024-01-05 15:05:00\n",
|
|
"182\n",
|
|
"2024-01-05 15:10:00\n",
|
|
"183\n",
|
|
"2024-01-05 15:15:00\n",
|
|
"184\n",
|
|
"2024-01-05 15:20:00\n",
|
|
"185\n",
|
|
"2024-01-05 15:25:00\n",
|
|
"186\n",
|
|
"2024-01-05 15:30:00\n",
|
|
"187\n",
|
|
"2024-01-05 15:35:00\n",
|
|
"188\n",
|
|
"2024-01-05 15:40:00\n",
|
|
"189\n",
|
|
"2024-01-05 15:45:00\n",
|
|
"190\n",
|
|
"2024-01-05 15:50:00\n",
|
|
"191\n",
|
|
"2024-01-05 15:55:00\n",
|
|
"192\n",
|
|
"2024-01-05 16:00:00\n",
|
|
"193\n",
|
|
"2024-01-05 16:05:00\n",
|
|
"194\n",
|
|
"2024-01-05 16:10:00\n",
|
|
"195\n",
|
|
"2024-01-05 16:15:00\n",
|
|
"196\n",
|
|
"2024-01-05 16:20:00\n",
|
|
"197\n",
|
|
"2024-01-05 16:25:00\n",
|
|
"198\n",
|
|
"2024-01-05 16:30:00\n",
|
|
"199\n",
|
|
"2024-01-05 16:35:00\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"for m in range(30, 288):\n",
|
|
" print(m)\n",
|
|
" histid = preprocess(m)"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "rts",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.8.10"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 2
|
|
}
|