-
asc 파일을 pandas 데이터프레임으로 변환하기tip 2025. 1. 4. 14:02
02_asc_to_df asc to dataframe¶
- 메시지 전송 주기를 분석하기 위해 수치 데이터 처리에 편리한 pandas를 사용할 것이다.
- m_id별로 분리된 asc 파일을 읽어서 pandas 데이터프레임을 만든다.
- 데이터 길이 (dlc: data length code)가 일정하지 않다. 어떻게 처리할까?
In [16]:import pandas as pd from pathlib import Path
In [17]:# data 디렉토리에 있는 모든 .asc 파일의 이름을 출력한다. dir_data = Path('.').absolute()/'asc_per_id' ascs = list(dir_data.glob('*.asc')) print(f'{len(ascs) = :,}') for asc in ascs: print(asc.name)
len(ascs) = 59 042.asc 043.asc 044.asc 080.asc 081.asc 111.asc 112.asc 113.asc 124.asc 153.asc 164.asc 18F.asc 200.asc 220.asc 251.asc 260.asc 280.asc 2B0.asc 316.asc 329.asc 340.asc 346.asc 34C.asc 374.asc 381.asc 383.asc 386.asc 387.asc 38D.asc 394.asc 417.asc 436.asc 483.asc 492.asc 4A7.asc 4E5.asc 4E6.asc 4E7.asc 4F1.asc 500.asc 502.asc 507.asc 50C.asc 50E.asc 52A.asc 53E.asc 541.asc 545.asc 547.asc 549.asc 553.asc 556.asc 557.asc 593.asc 5A0.asc 5B0.asc 5CE.asc 5CF.asc 5FA.asc
한 asc 파일로 df를 만드는 법을 개발한다.¶
In [18]:asc = ascs[0] print(asc) df = pd.read_csv(asc, sep=' ', skiprows=4, header=None, dtype=str) df = df.dropna(axis=1) print(df.head(3))
c:\Users\haese\OneDrive\01_Projects\1_picode\05_tosun\30_기술\00_교육_자료\CySec\IDS\asc_per_id\042.asc 3 4 6 13 16 17 18 19 20 21 22 23 24 25 0 72.698660 1 042 Rx d 8 15 FF 00 00 01 00 00 00 1 73.697781 1 042 Rx d 8 15 FF 00 00 01 00 00 00 2 74.697229 1 042 Rx d 8 15 FF 00 00 01 00 00 00
In [19]:n_cols = df.shape[1] print(f'{n_cols = }') n_data_byte = n_cols - 6 print(f'{n_data_byte = }') col_ds = [f'd{i + 1:02}' for i in range(n_data_byte)] print(f'{col_ds = }')
n_cols = 14 n_data_byte = 8 col_ds = ['d01', 'd02', 'd03', 'd04', 'd05', 'd06', 'd07', 'd08']
In [20]:# 컬럼 이름은 다음과 같다. # ts ch m_id trx d dlc d01 d02 d03 d04 d05 d06 d07 d08 d09 d10 d11 d12 d13 d14 d15 d16 ... # 맨 앞에 6개는 고정이고, 나머지는 d01, d02, ... 이런 식으로 이름을 붙인다. cols = ['ts', 'ch', 'm_id', 'trx', 'd', 'dlc'] + col_ds df.columns = cols print(df.dtypes) print(df.head(3))
ts object ch object m_id object trx object d object dlc object d01 object d02 object d03 object d04 object d05 object d06 object d07 object d08 object dtype: object ts ch m_id trx d dlc d01 d02 d03 d04 d05 d06 d07 d08 0 72.698660 1 042 Rx d 8 15 FF 00 00 01 00 00 00 1 73.697781 1 042 Rx d 8 15 FF 00 00 01 00 00 00 2 74.697229 1 042 Rx d 8 15 FF 00 00 01 00 00 00
In [21]:# 컬럼별 dtype을 아래와 같이 변경한다. # ts: float # ch: int # m_id: hex # trx: str # d: str # dlc: int # d01 ~ : hex df['ts'] = df['ts'].astype(float) df['ch'] = df['ch'].astype(int) df['dlc'] = df['dlc'].astype(int) for col in col_ds: df[col] = df[col].apply(lambda x: int(x, 16)) print(df.dtypes) print(df.head(3))
ts float64 ch int32 m_id object trx object d object dlc int32 d01 int64 d02 int64 d03 int64 d04 int64 d05 int64 d06 int64 d07 int64 d08 int64 dtype: object ts ch m_id trx d dlc d01 d02 d03 d04 d05 d06 d07 d08 0 72.698660 1 042 Rx d 8 21 255 0 0 1 0 0 0 1 73.697781 1 042 Rx d 8 21 255 0 0 1 0 0 0 2 74.697229 1 042 Rx d 8 21 255 0 0 1 0 0 0
In [22]:# 위 과정을 함수로 만들어서 다른 파일에도 적용한다. def read_asc_to_df(asc): ''' .asc 파일을 읽어서 DataFrame으로 반환한다. asc 파일은 m_id 별로 분리된 파일이어야 한다. ''' # 파일을 읽어서 DataFrame으로 변환한다. df = pd.read_csv(asc, sep=' ', skiprows=4, header=None, dtype=str) # 빈 컬럼은 제거한다. df = df.dropna(axis=1) # 컬럼의 개수를 확인한다. n_cols = df.shape[1] # 처음 6개 컬럼은 고정이고, 나머지는 d01, d02, ... 이런 식으로 이름을 붙인다. n_data_byte = n_cols - 6 col_ds = [f'd{i + 1:02}' for i in range(n_data_byte)] cols = ['ts', 'ch', 'm_id', 'trx', 'd', 'dlc'] + col_ds df.columns = cols # 컬럼별 dtype을 변경한다. df['ts'] = df['ts'].astype(float) df['ch'] = df['ch'].astype(int) df['dlc'] = df['dlc'].astype(int) for col in col_ds: df[col] = df[col].apply(lambda x: int(x, 16)) return df
In [23]:# 임의로 고른 asc 파일을 읽어서 DataFrame으로 변환이 잘 되나 확인한다. asc = ascs[-20] print(asc.name) df = read_asc_to_df(asc) print(df.head())
500.asc ts ch m_id trx d dlc d01 0 72.415913 1 500 Rx d 1 1 1 72.515901 1 500 Rx d 1 1 2 72.615890 1 500 Rx d 1 1 3 72.715880 1 500 Rx d 1 1 4 72.815868 1 500 Rx d 1 1
In [24]:# 임의로 고른 asc 파일을 읽어서 DataFrame으로 변환이 잘 되나 확인한다. asc = ascs[10] print(asc.name) df = read_asc_to_df(asc) # print(df.dtypes) print(df.head())
164.asc ts ch m_id trx d dlc d01 d02 d03 d04 0 72.378126 1 164 Rx d 4 0 8 16 102 1 72.388119 1 164 Rx d 4 0 8 18 92 2 72.398848 1 164 Rx d 4 0 8 20 18 3 72.408127 1 164 Rx d 4 0 8 22 40 4 72.418854 1 164 Rx d 4 0 8 24 142
In [25]:# 임의로 고른 asc 파일을 읽어서 DataFrame으로 변환이 잘 되나 확인한다. asc = ascs[30] print(asc.name) df = read_asc_to_df(asc) # print(df.dtypes) print(df.head())
417.asc ts ch m_id trx d dlc d01 d02 d03 d04 d05 d06 d07 d08 0 72.551204 1 417 Rx d 8 0 0 0 0 1 0 0 90 1 72.751431 1 417 Rx d 8 0 0 0 0 1 0 0 75 2 72.951224 1 417 Rx d 8 0 0 0 0 1 0 0 60 3 73.151453 1 417 Rx d 8 0 0 0 0 1 0 0 45 4 73.351219 1 417 Rx d 8 0 0 0 0 1 0 0 30
결과: read_asc_to_df()가 잘 작동한다.¶
id별 dlc를 저장한다.¶
- 나중에 사용한다.
In [26]:# id별 dlc를 확인한다. id_dlc = {} n_ascs = len(ascs) for i_asc, asc in enumerate(ascs): print(f'{i_asc:02}/{n_ascs:2}: {asc.name}') df = read_asc_to_df(asc) # 가능성은 거의 0%라고 생각하지만, # 한 asc 파일에 # m_id가 2개 이상인 경우를 확인한다. # dlc가 2개 이상인 경우를 확인한다. if df['m_id'].nunique() != 1: print(f'{asc.name = } has more than one m_id.') print(df['m_id'].unique()) print() elif df['dlc'].nunique() != 1: print(f'{asc.name = } has more than one dlc.') print(df['dlc'].unique()) print() else: m_id = int(df['m_id'].unique()[0], base=16) dlc = df['dlc'].unique()[0] id_dlc[m_id] = dlc print(id_dlc)
00/59: 042.asc 01/59: 043.asc 02/59: 044.asc 03/59: 080.asc 04/59: 081.asc 05/59: 111.asc 06/59: 112.asc 07/59: 113.asc 08/59: 124.asc 09/59: 153.asc 10/59: 164.asc 11/59: 18F.asc 12/59: 200.asc 13/59: 220.asc 14/59: 251.asc 15/59: 260.asc 16/59: 280.asc 17/59: 2B0.asc 18/59: 316.asc 19/59: 329.asc 20/59: 340.asc 21/59: 346.asc 22/59: 34C.asc 23/59: 374.asc 24/59: 381.asc 25/59: 383.asc 26/59: 386.asc 27/59: 387.asc 28/59: 38D.asc 29/59: 394.asc 30/59: 417.asc 31/59: 436.asc 32/59: 483.asc 33/59: 492.asc 34/59: 4A7.asc 35/59: 4E5.asc 36/59: 4E6.asc 37/59: 4E7.asc 38/59: 4F1.asc 39/59: 500.asc 40/59: 502.asc 41/59: 507.asc 42/59: 50C.asc 43/59: 50E.asc 44/59: 52A.asc 45/59: 53E.asc 46/59: 541.asc 47/59: 545.asc 48/59: 547.asc 49/59: 549.asc 50/59: 553.asc 51/59: 556.asc 52/59: 557.asc 53/59: 593.asc 54/59: 5A0.asc 55/59: 5B0.asc 56/59: 5CE.asc 57/59: 5CF.asc 58/59: 5FA.asc {66: 8, 67: 8, 68: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 292: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 640: 8, 688: 6, 790: 8, 809: 8, 832: 8, 838: 8, 844: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 8, 909: 8, 916: 8, 1047: 8, 1078: 4, 1155: 8, 1170: 8, 1191: 2, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1292: 8, 1294: 8, 1322: 8, 1342: 6, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1427: 6, 1440: 8, 1456: 4, 1486: 8, 1487: 8, 1530: 8}
In [27]:import pickle
In [28]:# id_dlc를 파일로 저장한다. pickle.dump(id_dlc, open('id_dlc.pkl', 'wb')) # id_dlc를 파일에서 읽어온다. 잘 되나 확인한다. id_dlc = pickle.load(open('id_dlc.pkl', 'rb')) print(id_dlc) # 잘 된다.
{66: 8, 67: 8, 68: 8, 128: 8, 129: 8, 273: 8, 274: 8, 275: 8, 292: 8, 339: 8, 356: 4, 399: 8, 512: 6, 544: 8, 593: 8, 608: 8, 640: 8, 688: 6, 790: 8, 809: 8, 832: 8, 838: 8, 844: 8, 884: 8, 897: 8, 899: 8, 902: 8, 903: 8, 909: 8, 916: 8, 1047: 8, 1078: 4, 1155: 8, 1170: 8, 1191: 2, 1253: 8, 1254: 8, 1255: 8, 1265: 4, 1280: 1, 1282: 4, 1287: 4, 1292: 8, 1294: 8, 1322: 8, 1342: 6, 1345: 8, 1349: 8, 1351: 8, 1353: 8, 1363: 8, 1366: 8, 1367: 8, 1427: 6, 1440: 8, 1456: 4, 1486: 8, 1487: 8, 1530: 8}
'tip' 카테고리의 다른 글
IDS 오감지/ 민감 감지에 관한 고찰 (0) 2025.01.04 침입 판정 기준값 데이터 준비 (0) 2025.01.04 asc 파일을 m_id별로 분리하기 (0) 2025.01.04 mdf 데이터 파일을 읽어서 그래프 그리기 (1) 2025.01.01 CAN dbc 편집 (0) 2024.12.30