2023년 8월 동안 검색하고 공부한 것들을 정리한 내용입니다.
logging
- 참고자료
내장 모듈 logging
을 이용해 log를 기록할 수 있습니다. python에서는 DEBUG
, INFO
, WARNING
, ERROR
, CRITICAL
- 기본 5개의 로깅 수준이 있습니다. DEBUG
가 가장 낮은 심각도(severity)를 나타내며 CRITICAL
이 가장 높은 위험도 수준을 의미합니다. 기본적으로 WARNING
이상의 로그 내용이 기록되게 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import logging
logging.basicConfig(
filename=HOME_PATH + "log/example.log",
format='%(asctime)s %(levelname)s:%(message)s',
level=logging.WARNING,
datefmt='%Y-%m-%d %H:%M:%S',
# filemode="w",
)
logging.info('Info')
logging.warning('Warning')
logging.error('Error')
logging.critical('Critical')
## example.log
# 2023-08-27 21:02:54 WARNING:Warning
# 2023-08-27 21:02:54 ERROR:Error
# 2023-08-27 21:02:54 CRITICAL:Critical
위 예제에서는 log level을 WARNING으로 설정했기 때문에 INFO 레벨의 log는 기록되지 않았습니다. 또한, filemode="w"
로 옵션을 설정한다면 작업을 실행할 때마다 log 파일을 overwrite 합니다.
위의 예시는 log 작성의 간단한 예시이며, 이외에 상황에 맞게 Handler, Formatter를 적용해 사용할 수 있습니다.
code 병목 확인하기 w/ line_profiler
- 참고자료
line_profiler
는 코드 별 실행 시간을 확인하는 툴 중 하나입니다. py 파일이나 ipynb 파일 모두에서 사용 가능하며, 이름에서 알 수 있듯이 코드의 각 line 별로 수행되는 시간을 제공해주는 역할을 합니다.
py 파일
실행 시간을 확인하려는 코드를 함수로 정의하고 이를 실행하는 py 파일을 생성합니다. 해당 함수가 정의되는 부분에서 @profile
데코레이터를 선언합니다. 2개 이상의 함수를 정의해 사용하는 경우에는 각 함수 앞에 데코레이터를 선언해줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# main.py
import numpy as np
import pandas as pd
import string
import random
@profile
def create_rand_df(n):
rint = [random.randint(0, 100) for i in np.arange(n)]
rtext1 = [
"".join(random.choices(string.ascii_lowercase + string.digits, k=10))
for i in np.arange(n)
]
df = pd.DataFrame(
np.stack([np.array(rint), np.array(rtext1)], axis=1),
columns=["val_int", "val_str"],
)
df["val_int"] = df["val_int"].astype("int")
return df
if __name__ == "__main__":
create_rand_df(100000)
터미널에서 kernprof -lv {py 파일명}
를 실행합니다. 아래 결과를 보면 시간 단위는 $10^{-6}$(=1e-06)초이며, ‘rtext1’을 정의하는 부분이 전체 실행 시간의 약 55%를 차지하며 시간이 오래 걸림을 확인할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
> kernprof -lv main.py
Wrote profile results to main.py.lprof
Timer unit: 1e-06 s
Total time: 0.357017 s
File: main.py
Function: create_rand_df at line 7
Line # Hits Time Per Hit % Time Line Contents
==============================================================
7 @profile
8 def create_rand_df(n):
9 1 129024.0 129024.0 36.1 rint = [random.randint(0, 100) for i in np.arange(n)]
10 2 195786.0 97893.0 54.8 rtext1 = [
11 "".join(random.choices(string.ascii_lowercase + string.digits, k=10))
12 1 65.0 65.0 0.0 for i in np.arange(n)
13 ]
14 2 9279.0 4639.5 2.6 df = pd.DataFrame(
15 1 19084.0 19084.0 5.3 np.stack([np.array(rint), np.array(rtext1)], axis=1),
16 1 0.0 0.0 0.0 columns=["val_int", "val_str"],
17 )
18
19 1 3779.0 3779.0 1.1 df["val_int"] = df["val_int"].astype("int")
20 1 0.0 0.0 0.0 return df
ipynb 파일
실행 시간을 확인하려는 코드를 함수로 정의합니다.
1
2
3
4
5
6
7
def create_rand_df(n):
rint = [random.randint(0,100) for i in np.arange(n)]
rtext1 = [''.join(random.choices(string.ascii_lowercase + string.digits, k=10)) for i in np.arange(n)]
df = pd.DataFrame(np.stack([np.array(rint), np.array(rtext1)], axis=1), columns=['val_int', 'val_str'])
df['val_int'] = df['val_int'].astype('int')
return df
liner_profiler
를 import하는 magic command를 실행합니다.
1
%load_ext line_profiler
%lprun -f {정의한 함수명} {실행하려는 함수}
를 실행합니다.
1
%lprun -f create_rand_df create_rand_df(100000)
이러한 툴에 대해서 더 알고 싶으시면 cProfile
도 있으니 참고해보셔도 좋습니다.
pathlib.Path.write_text
지정된 파일 경로에 텍스트를 작성하는 method 입니다. 파일 경로가 존재하지 않는 경우에는 새롭게 파일을 생성해 텍스트를 작성하며, 파일 경로가 존재하는 경우에는 overwrite하게 됩니다.
1
2
3
4
5
6
from pathlib import Path
file_path = Path("example.txt")
file_path.write_text("Hello World!")
file_path.read_text()
# Hello World!