"반려동물의 혈당 데이터, 종, 나이, 질병 이력을 학습시켜 맞춤형 사료를 추천하고, 향후 질병까지 예측하는 ML 모델 개발"
소프트웨어 마에스트로 프로젝트 초기, 다음과 같은 계획을 수립했다.
혈당 패턴 분석 → 당뇨 위험도 예측
반려동물 프로필(종, 나이, 체중) → 최적 사료 추천
협업 필터링 → "비슷한 강아지들이 선택한 사료"
하지만 결론부터 말하면, 완성하지 못했다.
이 글은 실패 사례를 공유하는 것이 아니라, 왜 실패했는지, 무엇을 배웠는지, 다음에는 어떻게 할 것인지를 정리한 회고다.
🚧 계획했던 ML 파이프라인
Phase 1: 데이터 수집 (4주)
반려동물 프로필 데이터
├─ 종(개/고양이), 품종
├─ 나이, 체중
├─ 질병 이력(당뇨, 신부전, 비만 등)
└─ 현재 사료 정보
혈당 데이터
├─ 평균 혈당
├─ 혈당 변동성 (표준편차)
├─ 스파이크 빈도
└─ 저혈당/고혈당 발생 횟수
사료 선택 데이터
├─ 사용자가 구매한 사료
├─ 사료 만족도 평가
└─ 재구매 여부
Phase 2: 모델 학습 (6주)
python
❌ 실패 원인 분석
1. 결정적 문제: 데이터 부족
📊 필요 데이터 vs 실제 확보 데이터
데이터가 부족했던 이유
센서 구매 비용 문제
FreeStyle Libre 센서: 1개당 7만원
14일 교체 주기 → 월 14만원 소요
대부분의 보호자가 비용 부담으로 참여를 포기했다
타겟층의 한계
당뇨를 앓고 있는 반려동물: 전체의 0.5-2% (추정)
그 중 혈당 센서 사용자: 극소수
우리 서비스를 알고 참여한 사용자: 23명
높은 이탈율
초기 가입: 47명
1주 후 잔존: 31명
4주 후 잔존: 23명 (51% 이탈)
주요 이탈 사유: "센서 부착이 번거롭다", "비용 부담"
2. 시간 부족과 우선순위 조정
⏰ 타임라인 재구성
ML 모델 개발 시간이 사라진 배경
데이터 파이프라인 구축 지연
Kafka, Spark, Airflow 학습 시간 필요
실시간 데이터 처리 안정화에 4주 소요
기획 변경에 따른 일정 손실
초기: 산책 경로 + 건강 관리 통합 서비스
변경: 건강 관리에 집중
재설계에 2주 추가 소요
팀 내부 우선순위 조정
멘토 피드백: ML보다 실시간 대시보드 완성도에 집중 권고
최종 발표에서 시연 가능한 기능 우선 개발 결정
3. 팀 내부 역량 및 리소스 문제
👥 팀 구성과 역할
문제점
ML 전문가 부재 → 모델 설계/학습 담당자 없음
Backend + 데이터 엔지니어링 + ML 모두 혼자 담당 → 역량 분산
팀원 간 ML 이해도 차이 → 협업 어려움
시도했던 접근
python
→ 과적합(Overfitting) 문제 심각, 일반화 불가능
python
→ 데이터 부족으로 학습 자체가 불가능했다
4. 도메인 지식 부족
ML 모델을 개발하려면 "무엇을 예측할 것인가"를 명확히 정의해야 한다.
막혔던 지점
"당뇨 위험도"의 정의
평균 혈당 180 이상? → 너무 단순
혈당 변동성 + 스파이크 빈도? → 가중치는?
수의사 진단 기준? → 데이터 없음
"사료 추천"의 평가 기준
사용자 만족도? → 설문 데이터 없음
혈당 개선 여부? → 인과관계 증명 불가 (다른 변수 많음)
재구매율? → 구매 데이터 없음
협업 필터링의 한계
User-Item Matrix가 거의 비어있음 (Cold Start 문제)
23명의 사용자로는 유사 프로필 찾기 불가능
수의사 인터뷰 피드백
"혈당만으로 사료를 추천하는 건 위험하다. 신장 기능, 간 수치, 알레르기 등 고려할 요소가 너무 많다."
→ ML보다 규칙 기반(Rule-Based) 추천이 더 현실적이라는 결론
🔄 대안: 규칙 기반 추천 시스템
ML을 포기하는 대신, 수의사 가이드라인 기반 추천 로직을 구현했다.
✅ 구현한 로직
java
규칙 기반 시스템의 장점
해석 가능성
ML 블랙박스와 달리 추천 이유를 명확히 설명 가능
수의사가 검증 가능한 로직
적은 데이터로도 작동
학습 데이터 불필요
수의학 가이드라인만 있으면 구현 가능
유지보수 용이
새로운 규칙 추가/수정 간단
ML 재학습 불필요
규칙 기반 시스템의 단점
개인화 부족
모든 비슷한 프로필에 동일한 추천
개체별 특성 반영 어려움
확장성 한계
규칙이 복잡해질수록 관리 어려움
예외 케이스 처리 한계
데이터 기반 개선 불가
사용자 피드백 반영 어려움
A/B 테스트 불가능
📊 결과 비교
실제 사용자 피드백:
"왜 이 사료를 추천하는지 알 수 있어서 좋다" (긍정 67%)
"우리 강아지만의 특별한 추천이 아니라 아쉽다" (개선 요구 33%)
🎓 배운 점
1. 데이터가 없으면 ML은 불가능하다
많은 ML 강의와 튜토리얼은 이미 정제된 데이터셋을 제공한다. 하지만 실제 프로젝트에서는 데이터 수집 자체가 가장 큰 난관이었다.
# 당초 설계한 모델 구조
# 1. 질병 예측 모델 (Classification)
from sklearn.ensemble import RandomForestClassifier
features = ['avg_glucose', 'glucose_std', 'spike_count', 'age', 'weight', 'breed']
target = 'diabetes_risk' # 0: 정상, 1: 주의, 2: 위험
model = RandomForestClassifier(n_estimators=100)
model.fit(X_train, y_train)
# 2. 사료 추천 모델 (Collaborative Filtering)
from surprise import SVD
# User-Item Matrix (사용자 x 사료 만족도)
trainset = Dataset.load_from_df(ratings_df[['user_id', 'food_id', 'rating']])
algo = SVD()
algo.fit(trainset)
# 3. 개인화 추천 모델 (Content-Based)
from sklearn.metrics.pairwise import cosine_similarity
# 반려동물 프로필과 사료 성분 벡터화
pet_vector = vectorize_pet_profile(pet_data)
food_vectors = vectorize_food_ingredients(food_data)
# 유사도 계산
similarity_scores = cosine_similarity(pet_vector, food_vectors)
초기 계획 (20주)
├─ 1-4주: 기획 및 시장 조사 ✅
├─ 5-8주: 데이터 수집 인프라 구축 ✅
├─ 9-14주: 데이터 수집 및 ML 모델 개발 ❌
└─ 15-20주: 서비스 고도화 및 배포 ⚠️
실제 진행 (20주)
├─ 1-4주: 기획 (+ 기획 변경으로 2주 지연) ✅
├─ 5-10주: 데이터 파이프라인 구축 (예상보다 어려움) ✅
├─ 11-15주: 대시보드 UI 개발 ✅
├─ 16-18주: 실시간 알림 기능 구현 ✅
└─ 19-20주: 최종 발표 준비 ✅
# 1. Scikit-learn 기반 간단한 분류 모델
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
X = df[['avg_glucose', 'glucose_std', 'age', 'weight']]
y = df['diabetes_risk']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
model = RandomForestClassifier()
model.fit(X_train, y_train)
# 결과: 정확도 62% (데이터 23개로는 의미 없음)
# 2. TensorFlow 기반 신경망
import tensorflow as tf
model = tf.keras.Sequential([
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(32, activation='relu'),
tf.keras.layers.Dense(3, activation='softmax')
])
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy')
model.fit(X_train, y_train, epochs=50)
# 결과: Validation loss 급증, 학습 불안정
@Service
public class FoodRecommendationService {
public List<Food> recommendByHealth(String petId) {
Pet pet = petRepository.findById(petId);
GlucoseStats stats = getWeeklyGlucoseStats(petId);
// 1. 혈당 상태 분석
HealthStatus status = analyzeHealthStatus(stats);
// 2. 조건별 필터링
FoodFilter filter = new FoodFilter();
if (status == HealthStatus.DIABETIC) {
// 당뇨: 저탄수화물, 고단백, GI 낮은 사료
filter.setMaxCarbohydrate(20); // 20% 이하
filter.setMinProtein(30); // 30% 이상
filter.setGlycemicIndex("LOW");
}
else if (status == HealthStatus.PREDIABETIC) {
// 당뇨 전단계: 중간 수준
filter.setMaxCarbohydrate(30);
filter.setMinProtein(25);
}
else {
// 정상: 연령/품종별 추천
filter = getAgeBasedFilter(pet.getAge());
}
// 3. 품종별 특이사항 반영
if (pet.getBreed().equals("퍼그") || pet.getBreed().equals("불독")) {
// 단두종: 소화 잘 되는 사료
filter.addTag("EASY_DIGEST");
}
// 4. MongoDB에서 필터링
List<Food> candidates = foodRepository.findByFilter(filter);
// 5. 평점순 정렬
return candidates.stream()
.sorted(Comparator.comparing(Food::getRating).reversed())
.limit(10)
.collect(Collectors.toList());
}
private HealthStatus analyzeHealthStatus(GlucoseStats stats) {
if (stats.getAverage() > 180 || stats.getSpikeCount() > 15) {
return HealthStatus.DIABETIC;
}
else if (stats.getAverage() > 140 || stats.getSpikeCount() > 8) {
return HealthStatus.PREDIABETIC;
}
return HealthStatus.NORMAL;
}
}
Phase 1: 파트너십 (6개월)
├─ 동물병원 5곳과 협약
├─ 병원 방문 환자 데이터 수집 (익명화)
└─ 목표: 반려동물 500마리, 혈당 데이터 50만 건
Phase 2: 인센티브 프로그램 (6개월)
├─ 센서 비용 50% 할인 제공
├─ 데이터 제공 시 사료 할인 쿠폰
└─ 목표: 월 활성 사용자 200명
Phase 3: ML 모델 개발 (3개월)
└─ 충분한 데이터 확보 후 진행
Step 1: 협업 필터링
└─ 사용자 200명 이상 확보 시 구현
└─ "비슷한 강아지들이 선택한 사료" 추천
Step 2: 혈당 패턴 분류
└─ 혈당 데이터 10만 건 이상 확보 시
└─ K-Means 클러스터링으로 패턴 그룹화
Step 3: 질병 예측 모델
└─ 진단 데이터 500건 이상 확보 시
└─ RandomForest 또는 XGBoost 활용
// 규칙 기반 + ML 결합
public List<Food> hybridRecommendation(String petId) {
// 1. 규칙 기반으로 1차 필터링 (안전성 확보)
List<Food> candidates = ruleBasedFilter(petId);
// 2. ML 모델로 재정렬 (개인화)
if (hasEnoughData(petId)) {
candidates = mlModel.rerank(petId, candidates);
}
// 3. 최종 추천
return candidates.subList(0, 10);
}