SciPy.optimize - 제약 조건과 경계 설정 방법
SciPy의 optimize
모듈은 최적화 문제를 해결하는 데 매우 유용한 도구입니다. 특히 현실적인 최적화 문제에서는 변수의 범위를 제한하거나 특정 제약 조건을 부여하는 경우가 많습니다. 이번 포스팅에서는 SciPy.optimize에서 제약 조건과 경계(경계 조건)를 설정하는 방법을 중심으로 설명드리겠습니다.
1. 최적화에서 제약 조건과 경계의 필요성
최적화 문제를 해결할 때, 현실적인 상황에서는 다음과 같은 제약이 존재할 수 있습니다.
- 경계(Bounds): 변수의 값이 특정 범위를 벗어나지 않도록 제한하는 조건.
- 등식 제약(Equality Constraint): 특정 식이 0과 같아야 하는 조건.
- 부등식 제약(Inequality Constraint): 특정 식이 0보다 크거나 같아야 하는 조건.
예를 들어, 생산 공정에서 자원을 최적화할 때 특정 자원은 최소 10개 이상 사용해야 하거나, 생산량은 일정 범위를 벗어나지 않아야 하는 상황이 있을 수 있습니다. 이러한 문제를 효과적으로 해결하려면 SciPy에서 제공하는 제약과 경계 설정 방법을 잘 이해하는 것이 중요합니다.
2. 경계(Bounds) 설정 방법
SciPy의 scipy.optimize.minimize
함수에서 경계를 설정하는 방법은 Bounds
클래스를 사용하는 것입니다. 변수의 하한과 상한을 지정해 최적화 과정에서 해당 범위를 벗어나지 않도록 제한할 수 있습니다.
2.1 기본 예제
아래는 간단한 함수 $ f(x) = (x-2)^2 $를 최소화하는 예제입니다. 이때, 변수 $ x $가 0과 4 사이에만 존재하도록 경계를 설정합니다.
import numpy as np
from scipy.optimize import minimize, Bounds
# 목적 함수 정의 (x가 2일 때 최소값)
def objective_function(x):
return (x - 2) ** 2
# 경계 설정: x는 0과 4 사이
bounds = Bounds(0, 4)
# 최적화 수행
result = minimize(objective_function, x0=0, bounds=bounds)
# 결과 출력
print("최적화 결과:", result)
print("최적화된 x 값:", result.x)
2.2 다변수 경계 설정
변수가 여러 개일 때는 각 변수에 대해 하한과 상한을 개별적으로 설정할 수 있습니다. 다음은 2개의 변수에 대해 경계를 설정하는 예입니다.
# 목적 함수 정의: 간단한 이변수 함수
def objective_function(x):
return (x[0] - 2) ** 2 + (x[1] - 3) ** 2
# 각 변수의 경계 설정 (x1: 0~4, x2: 1~5)
bounds = Bounds([0, 1], [4, 5])
# 최적화 수행
result = minimize(objective_function, x0=[0, 1], bounds=bounds)
# 결과 출력
print("최적화 결과:", result)
print("최적화된 x 값:", result.x)
위 예제에서는 Bounds
객체를 통해 다변수 문제에서도 개별 변수에 대해 범위를 제한하는 방법을 보여주었습니다.
3. 제약 조건(Constraints) 설정 방법
SciPy에서는 constraints
매개변수를 통해 등식과 부등식 제약 조건을 설정할 수 있습니다. scipy.optimize.minimize
함수에서는 다음과 같은 형식으로 제약을 설정합니다.
3.1 등식 제약 (Equality Constraint)
등식 제약은 다음과 같이 정의됩니다.
$$
g(x) = 0
$$
예를 들어, $ x_0 + x_1 - 3 = 0 $이라는 제약 조건을 설정하려면 다음과 같이 작성합니다.
# 목적 함수 정의
def objective_function(x):
return (x[0] - 1) ** 2 + (x[1] - 2) ** 2
# 등식 제약: x[0] + x[1] - 3 = 0
def equality_constraint(x):
return x[0] + x[1] - 3
# 제약 조건 설정
constraints = {'type': 'eq', 'fun': equality_constraint}
# 최적화 수행
result = minimize(objective_function, x0=[0, 0], constraints=constraints)
# 결과 출력
print("최적화 결과:", result)
print("최적화된 x 값:", result.x)
3.2 부등식 제약 (Inequality Constraint)
부등식 제약은 다음과 같이 정의됩니다.
$$
g(x) \ge 0
$$
예를 들어, $ x_0 - 1 \ge 0 $라는 제약을 설정하려면 다음과 같이 작성합니다.
# 부등식 제약: x[0] - 1 >= 0
def inequality_constraint(x):
return x[0] - 1
# 제약 조건 설정
constraints = {'type': 'ineq', 'fun': inequality_constraint}
# 최적화 수행
result = minimize(objective_function, x0=[0, 0], constraints=constraints)
# 결과 출력
print("최적화 결과:", result)
print("최적화된 x 값:", result.x)
3.3 다중 제약 조건 설정
복수의 등식과 부등식 제약을 함께 사용할 수도 있습니다. 다음은 등식과 부등식 제약을 동시에 적용하는 예입니다.
# 목적 함수 정의
def objective_function(x):
return (x[0] - 1) ** 2 + (x[1] - 2) ** 2
# 등식 제약: x[0] + x[1] - 3 = 0
def equality_constraint(x):
return x[0] + x[1] - 3
# 부등식 제약: x[0] - 1 >= 0
def inequality_constraint(x):
return x[0] - 1
# 여러 제약 조건 설정
constraints = [
{'type': 'eq', 'fun': equality_constraint},
{'type': 'ineq', 'fun': inequality_constraint}
]
# 최적화 수행
result = minimize(objective_function, x0=[0, 0], constraints=constraints)
# 결과 출력
print("최적화 결과:", result)
print("최적화된 x 값:", result.x)
4. 경계와 제약을 함께 사용하는 방법
경계와 제약 조건을 동시에 사용하는 것도 가능합니다. 다음은 경계와 부등식 제약을 함께 사용하는 예입니다.
# 목적 함수 정의
def objective_function(x):
return (x[0] - 1) ** 2 + (x[1] - 2) ** 2
# 부등식 제약: x[0] - 1 >= 0
def inequality_constraint(x):
return x[0] - 1
# 경계 설정 (x0: 0~4, x1: 1~5)
bounds = Bounds([0, 1], [4, 5])
# 제약 조건 설정
constraints = {'type': 'ineq', 'fun': inequality_constraint}
# 최적화 수행
result = minimize(objective_function, x0=[0, 0], bounds=bounds, constraints=constraints)
# 결과 출력
print("최적화 결과:", result)
print("최적화된 x 값:", result.x)
5. 실제 사례 적용: 자원 배분 문제
현실적인 예로, 예산을 최적화하는 간단한 자원 배분 문제를 풀어보겠습니다.
문제 설정
- 두 개의 제품을 생산하는 공장이 있으며, 각 제품을 생산하는 데 비용과 자원이 필요합니다.
- 제품 1과 제품 2의 생산량을 $ x_0 $와 $ x_1 $라 할 때, 총 비용을 최소화하는 것이 목표입니다.
수식화
- 목적 함수: $$ f(x) = 10 x_0^2 + 20 x_1^2 $$
- 제약 조건:
- 제품 1과 제품 2의 생산량 합이 100을 초과하지 않음: $$ x_0 + x_1 \le 100 $$
- 제품 1과 제품 2의 최소 생산량은 각각 10 이상이어야 함: $$ x_0 \ge 10, x_1 \ge 10 $$
코드 구현
# 목적 함수 정의
def objective_function(x):
return 10 * x[0]**2 + 20 * x[1]**2
# 부등식 제약: x[0] + x[1] <= 100
def production_constraint(x):
return 100 - (x[0] + x[1])
# 경계 설정 (각 변수는 최소 10 이상)
bounds = Bounds([10, 10], [100, 100])
# 제약 조건 설정
constraints = {'type': 'ineq', 'fun': production_constraint}
# 최적화 수행
result = minimize(objective_function, x0=[10, 10], bounds=bounds, constraints=constraints)
# 결과 출력
print("최적화 결과:", result)
print("최적화된 생산량 (x0, x1):", result.x)
이 예에서는 경계와 부등식 제약을 함께 적용해 현실적인 생산 계획을 수립하는 방법을 보여주었습니다.
6. 결론
SciPy의 optimize
모듈에서 경계와 제약 조건을 활용하면 현실적인 최적화 문제를 효과적으로 해결할 수 있습니다. 다음과 같은 요점을 기억하면 좋습니다.
- 경계(Bounds): 변수의 최소, 최대 값을 설정할 때 사용.
- 등식 제약(Equalities): 특정 관계식이 반드시 성립하도록 강제.
- 부등식 제약(Inequalities): 특정 조건을 만족하는 범위 내에서 최적화.
실제 문제에서는 여러 조건이 동시에 적용되는 경우가 많으므로, 제약과 경계를 적절히 조합하는 것이 중요합니다.
'Python SciPy' 카테고리의 다른 글
SciPy 푸리에 변환 (FFT) (0) | 2025.03.12 |
---|---|
SciPy를 활용한 필터 설계 및 적용 (butter, filtfilt) (0) | 2025.03.11 |
SciPy를 활용한 곡선 맞추기 (curve_fit) (0) | 2025.03.09 |
비선형 방정식 찾기 (SciPy.optimize.root) (0) | 2025.03.08 |
SciPy.optimize를 활용한 최소화 문제 해결 (minimize) (0) | 2025.03.07 |