기능 데이터 분석으로 곡선 차이와 예측 모델링하기
기능 데이터 분석 관점에서 Functional ANOVA와 Functional Regression을 적용해 연속 곡선의 집단 차이, 예측, 해석을 다루는 방법
2026-08-14 · 최초 발행 2024-04-29
곡선 전체를 분석 단위로 삼는 이유
시간이나 공간을 따라 연속적으로 기록한 곡선, 스펙트럼, 형상 데이터는 개별 시점의 숫자 모음이 아니라 함수로 다룰 수 있다. 기능 데이터 분석(Functional Data Analysis, FDA)은 이를 시간 또는 위치 (t \in T)에서 정의된 연속 함수 (x(t))로 모델링하는 접근이다.
실제 관측은 이산 격자에서 얻어지므로 평활화(smoothing), 기저 전개(basis expansion), FPCA 같은 표현 단계가 필요하다. 고빈도 시계열, 제조 공정 곡선, 의료 생체신호, 에너지 수요 곡선처럼 연속적 형태 자체가 의사결정에 중요한 데이터가 대상이다.
Functional ANOVA는 여러 집단의 평균 함수가 구간 전체에서 같은지 검정한다. 귀무가설은 모든 집단의 평균 함수 (\mu_g(t))가 (T) 전 구간에서 동일하다는 것이다. L2-노름을 집계한 전역 통계량과 순열 검정(permutation test)을 사용하면, 점별(pointwise) 다중검정보다 오류율을 통제하기 수월하다.
Functional Regression은 함수형 변수를 모형 안으로 가져온다. Scalar-on-Function 모형은 다음과 같이 쓸 수 있다.
[ y = \alpha + \int \beta(t)x(t)dt + \epsilon ]
반응 자체가 함수라면 Function-on-Scalar 또는 Function-on-Function으로 확장할 수 있다. 이때 매끄러움 패널티와 정규화는 일식성과 과적합을 완화하는 역할을 한다.
표현과 추론은 분리되지 않는다
기능형 분석의 결과는 원시 곡선을 어떻게 표현했는지에 크게 좌우된다. B-spline, Fourier, 웨이블릿 같은 기저 표현을 선택하고 GCV/AICc로 기저 수와 패널티를 조정한다. 곡선 정렬(registration)과 위상 변화 보정(SRSF 등)은 위상과 진폭을 분리해 군집·회귀의 왜곡을 줄인다.
(\beta(t))는 벌점 최소제곱(roughness penalty), ridge, LASSO를 통해 안정적으로 추정할 수 있다. FPCA 점수 회귀(Truncation)는 차원을 줄이면서 해석 가능한 표현을 제공한다.
추론 단계에서는 순열 기반 전역 검정 통계와 동시 신뢰대역(SCB)을 함께 활용해 (\beta(t))의 구간별 효과를 확인한다. 부트스트랩이나 야콥스 변환 기반 분산 추정, 점별 검정의 FWER/FDR 교정도 병행 대상이다.
검증은 관측 시점이 아니라 곡선 단위로 나눠야 누출을 막을 수 있다. 시점 구간 홀드아웃은 외삽 리스크를 점검하는 데 쓰이며, 기능형 성능지표(R2_func, Integrated RMSE)와 배포 후 데이터 드리프트 모니터링까지 운영 체계에 포함된다.
입력 곡선에서 결과 보고까지의 흐름
곡선의 차이와 예측이 필요한 현장
제조 공정에서는 반응로 온도·압력 곡선 (x(t))를 수율 (y)와 연결하는 Scalar-on-Function 회귀를 적용할 수 있다. 라인이나 배치별 평균 곡선의 차이는 FANOVA로 탐지한다.
에너지 분야에서는 일일 부하 곡선과 기상 변수를 기능 회귀에 넣어 단기 예측을 고도화한다. 요일과 시즌별 그룹은 FANOVA로 수요 패턴 차이를 확인하는 대상이 된다.
생체역학과 의료 신호 분석에서는 보행 주기 곡선으로 치료군과 대조군을 FANOVA로 비교할 수 있다. ICU의 연속 심박·호흡 곡선은 악화 예측 모델의 입력으로 활용된다.
분석 목적에 따른 선택
| 방법 | 성능(예측/검정력) | 확장성(표본·격자) | 일관성(전역/국소) | 안정성(노이즈·위상) | 운영 편의 |
|---|---|---|---|---|---|
| Functional ANOVA(전역) | 전역 차이 검정력 우수 | 순열 병렬화로 확장 용이 | 전역 일관성 확보 | 정렬·평활화 민감 | 해석 직관적 |
| 점별 ANOVA+보정 | 국소 차이 탐지 우수 | 점별 병렬화 매우 용이 | 다중검정 부담 | 노이즈 민감 | 구현 간단 |
| 스칼라화 후 ANOVA(특징 추출) | 요약 정보에 제한 | 고차원에서도 효율 | 요약 손실로 편향 가능 | 비교적 견고 | 파이프라인 단순 |
| Functional Regression(SoF) | 예측·해석 균형 | 기저 축소로 확장 | β(t)로 국소·전역 해석 | 정규화 의존 | 운영화 용이 |
| Function-on-Function | 고표현력 | 계산량 큼 | 커널/기저 설계 중요 | 과적합 위험 | 복잡도 높음 |
R에서 평균 함수 차이 검정하기
환경과 전제는 R >= 4.2, 패키지 fdANOVA >= 0.1.7, fda >= 6.1이다. 최신 API 확인이 필요하다. 아래 예제는 세 집단 평균 함수의 전역 차이를 검정한다.
# install.packages(c("fdANOVA", "fda")) # 최초 1회
library(fdANOVA)
library(fda)
set.seed(42)
n_per_group <- 30
t <- seq(0, 1, length.out = 101)
# 기저 진실 평균 함수
mu1 <- sin(2*pi*t)
mu2 <- sin(2*pi*t) + 0.3*exp(-((t-0.5)^2)/0.01)
mu3 <- sin(2*pi*t) - 0.2
# 데이터 시뮬레이션
sim_curves <- function(mu, n) {
replicate(n, mu + 0.2 * arima.sim(list(ar = 0.7), n = length(t)) / 3)
}
X1 <- t(sim_curves(mu1, n_per_group))
X2 <- t(sim_curves(mu2, n_per_group))
X3 <- t(sim_curves(mu3, n_per_group))
# B-spline 평활화
nbasis <- 25
basis <- create.bspline.basis(rangeval = c(0,1), nbasis = nbasis)
lambda <- 1e-4
fdParObj <- fdPar(basis, Lfdobj = int2Lfd(2), lambda = lambda)
smooth_group <- function(X) smooth.basis(t, t(X), fdParObj)$fd
fd1 <- smooth_group(X1); fd2 <- smooth_group(X2); fd3 <- smooth_group(X3)
# fdANOVA: 일원 분산분석(전역 순열 검정)
res <- fanova.onefactor(functionalData = list(fd1, fd2, fd3),
nperm = 999, seed = 123)
print(res$pvalue) # 전역 p-값
plot(res) # 통계량 곡선 및 임계값 시각화
p-값이 유의수준 이하이면 집단 평균 함수 사이에 전역 차이가 있다고 판단한다. 통계량 곡선의 피크 구간은 차이가 큰 구간이며, 사후검정과 SCB를 통해 더 구체적으로 확인할 수 있다.
Python에서 함수형 입력으로 회귀하기
환경과 전제는 Python 3.10+, numpy, scikit-learn >= 1.2, scikit-fda >= 0.8.1, matplotlib이며 최신 API 확인이 필요하다. 예제는 (y = \int \beta(t)x(t)dt + \epsilon)을 추정하고 (\beta(t)) 해석과 예측 성능 검증을 수행한다.
# pip install numpy matplotlib scikit-learn scikit-fda
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV, KFold
from sklearn.linear_model import Ridge
from skfda.representation.basis import BSplineBasis
from skfda.representation import FDataGrid
rng = np.random.default_rng(42)
n, m = 150, 101
t = np.linspace(0, 1, m)
# 진실 베타 함수와 곡선 생성
beta_true = 1.5*np.sin(2*np.pi*t) + 2*np.exp(-((t-0.6)**2)/0.01)
X = []
for _ in range(n):
x = np.sin(2*np.pi*t) + 0.3*np.cos(4*np.pi*t) + rng.normal(0, 0.15, m)
X.append(x)
X = np.array(X)
# 수치적분 근사로 y 생성
y = np.trapz(X * beta_true, t, axis=1) + rng.normal(0, 0.3, n)
# B-spline 기저 전개로 특징 추출
nbasis = 25
basis = BSplineBasis(domain_range=(0,1), n_basis=nbasis, order=4)
fd = FDataGrid(data_matrix=X, grid_points=t).to_basis(basis)
Phi = fd.coefficients # (n, nbasis)
# Ridge 회귀 + CV
alphas = {"alpha": np.logspace(-4, 2, 20)}
cv = KFold(n_splits=5, shuffle=True, random_state=42)
ridge = GridSearchCV(Ridge(fit_intercept=True), alphas, cv=cv, scoring="r2")
ridge.fit(Phi, y)
print("Best alpha:", ridge.best_params_, "CV R2:", ridge.best_score_)
# 베타(t) 복원: 기저 함수의 선형결합으로 근사
coefs = ridge.best_estimator_.coef_ # (nbasis,)
# 기저 평가 행렬
B = np.vstack([basis(i)(t) for i in range(nbasis)]) # (nbasis, m)
beta_hat = coefs @ B
# 시각화
plt.figure(figsize=(7,4))
plt.plot(t, beta_true, label="beta true", lw=2)
plt.plot(t, beta_hat, label="beta estimated", lw=2, ls="--")
plt.legend(); plt.xlabel("t"); plt.ylabel("beta(t)"); plt.tight_layout()
plt.show()
Ridge 계수와 기저 평가행렬의 선형결합으로 (\beta(t))를 근사한다. 기저 수가 과도하면 과적합 위험이 커진다. 교차검증은 곡선 단위로 구성해 누출을 최소화하고, 도메인 외삽 구간에서는 신뢰도가 낮아질 수 있음을 고려한다.
전처리와 운영에서 남는 선택지
위상 변동이 큰 데이터에는 SRSF/elastic registration을 적용할 수 있지만, 이 과정에는 정보 손실의 트레이드오프가 있다. 결측이나 불규칙 격자는 공통 격자로 재표본화한 뒤 평활화하며, 희소 관측은 PACE 기반 보간을 고려한다.
B-spline은 국소성과 경계 안정성에 장점이 있고, Fourier는 주기적 신호에 적합하다. 웨이블릿은 급격한 변화를 포착하는 데 강점이 있다. FPCA 점수 회귀는 계산 효율성이 우수하지만 해석은 기저 함수에 종속된다.
FANOVA는 전역 차이 검정에 맞고, 국소 현상 탐지는 SCB 또는 점별 검정을 병행해야 한다. 순열 검정은 분포 자유라는 장점이 있으나 대용량에서는 계산 비용이 증가하므로 병렬 분산 처리로 완화할 수 있다.
운영 단계에서는 도메인 범위와 해상도 변화 같은 데이터 드리프트 감지 규칙을 정의하고, 기저 재학습을 자동화하는 파이프라인을 둔다. 설명가능성이 요구되면 (\beta(t))의 중요 구간을 보고하고, 규제 환경에서는 SCB와 함께 결과를 제공한다.
스칼라 특징 기반 접근과 비교하면 예측 성능은 5~20% RMSE 개선 가능하며, 이는 도메인과 정렬 품질에 의존한다. 또한 점별 검정과 비교해 FWER 통제 하에서 전역 차이 검출력을 높일 수 있다. 전처리→표현→추정→추론 절차를 표준화하면 재현 가능한 분석 파이프라인을 구성할 수 있다.