본문 바로가기
프로그램

[파이썬] 150배 빨라진다! 조건에 맞는 데이터 계산(병렬처리와 Numba사용)

by 오디세이99 2025. 6. 3.
728x90
반응형

 

https://question99.tistory.com/1095

 

[파이썬] 조건에 맞는 데이터 계산(다중 for문)

어떤 데이터가 있을때 어떤 컬럼의 데이터들끼리 어떤 조건들로 찾거나 계산할때import timeimport pandas as pdimport numpy as npnp.random.seed(0) # 난수 생성 시 일관성을 위해 시드 설정### 1) 데이터 생성data_s

question99.tistory.com

 

https://question99.tistory.com/1096

 

[파이썬] 조건에 맞는 데이터 계산(Parallel, 병렬처리, 다중프로세스)

https://question99.tistory.com/1095 [파이썬] 조건에 맞는 데이터 계산(다중 for문)어떤 데이터가 있을때 어떤 컬럼의 데이터들끼리 어떤 조건들로 찾거나 계산할때import timeimport pandas as pdimport numpy as npnp.r

question99.tistory.com

 

병렬처리를 해도 데이터 항목이 많아지면 역시 실행시간이 많이 소요됨.

Numba를 사용해서 실행시간 단축.

import itertools
import psutil
from functools import partial
import time
from joblib import Parallel, delayed
import pandas as pd
import numpy as np
from numba import jit

np.random.seed(0)  # 난수 생성 시 일관성을 위해 시드 설정

# Numba JIT 처리
# 이 함수에서는 문자열, Datafreame, datatime, time 등 사용 할 수 없음
# 함수내에서 문자열 formater 도 사용 할 수 없음
# return도 조건에 따라 다른 return 값을 가질 수 없다. 하나의 return 형태가 되어야 함
@jit(nopython=True)                          # JIT 지정
def run_simulation(idx, case1, case2, n_df):
    count1 = []
    count2 = []
    for i in range(len(n_df)):
        data1 = n_df[i][case1[0]]
        data2 = n_df[i][case1[1]]
        data3 = n_df[i][case2[0]]
        data4 = n_df[i][case2[1]]
        
        if data1 > data2:
            count1.append(idx)
        elif data3 > data4:
            count2.append(idx)

    count_sum = len(count1) + len(count2)

    # print(f"[{idx}] {case1} : {case2} : {count_sum}")
   
    return [idx, count_sum]
    

### 1) 데이터 생성
data_size = 2000
data = {
    'c1': np.random.randint(50, 201, size=data_size),  # 50에서 200 사이의 정수, 100개
    'c2': np.random.randint(50, 201, size=data_size),
    'c3': np.random.randint(50, 201, size=data_size),
    'c4': np.random.randint(50, 201, size=data_size),
    'c5': np.random.randint(50, 201, size=data_size),
    'c6': np.random.randint(50, 201, size=data_size),
    'c7': np.random.randint(50, 201, size=data_size),
    'c8': np.random.randint(50, 201, size=data_size),
    'c9': np.random.randint(50, 201, size=data_size),
    'c10': np.random.randint(50, 201, size=data_size)
}

# DataFrame 생성
df = pd.DataFrame(data)

### 2) 조건의 조합(순열) 만들기
col = ['c1','c2','c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'c10']

lst = list(itertools.permutations(col, 2))
# lst는 문자열('c1'등)로 되고, Numba에서는 문자열이 안되기 때문에 정수(인덱스 사용)로 만듬
lst_no = []
for i in range(len(lst)):
    n1 = col.index(lst[i][0])     # 해당 컬럼명(문자열)의 인덱스를 찾아 정수로 사용
    n2 = col.index(lst[i][1])
    lst_no.append((n1, n2))

### 3) 데이터에서 조건으로 찾기
combinations_no = [
    (idx, case1, case2)
    for idx, (case1, case2) in enumerate(
            [(b, s) for b in lst_no for s in lst_no]
        )
    ]

# 조건을 출력해 보기 위해 컬럼명으로 변경
# combinations3 = []
# for i in range(len(combinations_no)):
#     dd = combinations_no[i]
#     combinations3.append([dd[0], (col[dd[1][0]],col[dd[1][1]]) , (col[dd[2][0]],col[dd[2][1]])])

start_time = time.time()

# Numba에서는 Dataframe을 사용할 수 없기때문에 df.values를 사용해서 변경
# 이때 컬럼의 datetime, 문자열 데이터가 있으면 안됨
n_df = df[col].values
idx = 0
max_idx = 0
max_count = 0

# 병렬(다중) 작업. combinations에서 조건(데이터)를 하나씩 지정해서 하나의 단위 작업(함수)가 실행되도록 함
results = Parallel(n_jobs=-1)(
    delayed(run_simulation)(idx, case1, case2, n_df)
    for idx, case1, case2 in combinations_no
)

best_idx, max_count = max(results, key=lambda x: x[1])
max_info = [item for item in combinations_no if item[0] == best_idx]
case1 = max_info[0][1]
case2 = max_info[0][2]
case1_col = [col[case1[0]], col[case1[1]]]
case2_col = [col[case2[0]], col[case2[1]]]

### 4) 출력
print(f"Best case : {max_count:,} (idx={best_idx}), {case1_col}:{case2_col}")

# 실행기간 계산 및 출력
end_time = time.time()
elapsed = end_time - start_time
minutes = int(elapsed // 60)
seconds = int(elapsed % 60)
print(f"\nRunning time: {minutes}m {seconds}sec")

 

병렬처리때 24 sec 보다 2 sec 로 12배 실행시간 개선 됨.

다중 for문때 5분(300sec) 보다 2 sec로 150배 실행시간 개선 됨.

 

Numba 적용을 위해서는 Dataframe, datetime, time, formater 등을 사용할 수 없어서

이를 사용하도록 변환하는게 쉽지 않음.

 

그러나 단축된 실행시간을 보면 충분히 시간을 들여서 개선할 필요가 있음.

실행시간이 많이 걸려서 시도해 볼 수도 없던 것을 해 볼 수 있음.

 

https://question99.tistory.com/1098

 

[파이썬] 조건에 맞는 데이터 계산(병렬처리 하지 않고 Numba만 사용)

https://question99.tistory.com/1095 [파이썬] 조건에 맞는 데이터 계산(다중 for문)어떤 데이터가 있을때 어떤 컬럼의 데이터들끼리 어떤 조건들로 찾거나 계산할때import timeimport pandas as pdimport numpy as npnp.r

question99.tistory.com

 

728x90
반응형

댓글