티스토리 뷰
내일배움캠프 데이터 분석
74일차) 내일배움캠프 데이터 분석 TIL - Streamlit(4), 최종 프로젝트(3), QCC(3)
heeso0908 2026. 4. 10. 21:07아침 6시 6분부터 공부함! 4일차 뿌듯!

🚀 Streamlit 앱 배포 실습
배포에 필요한 파일 구조
- app.py — 진입점 파일
- pages/ — 멀티페이지 폴더
- data/ — 데이터 폴더
- models/ — 머신러닝 모델 폴더
- requirements.txt — 패키지 목록
- secrets.toml — API 키 (GitHub에 올리면 ❌, .gitignore에 추가)
requirements.txt 작성 방법
| 방법 | 명령어 | 특징 |
| pip freeze (비권장) | pip freeze > requirements.txt | 현재 환경의 모든 패키지 포함 → OS 종속 패키지(pywin32 등) 포함되어 오류 가능 |
| pipreqs (권장) | pip install pipreqs → pipreqs . --force | 실제 코드에서 사용한 패키지만 추출. 누락된 패키지는 수동으로 추가 |
GitHub 업로드 순서
- 다운로드 받은 폴더에서 .git 폴더 삭제 (기존 버전 관리 정보 제거)
- .gitignore 생성: F1 → Add gitignore → Python 선택
- secrets.toml을 .gitignore에 추가
- Git 명령어 순서:
git init
git remote add origin [레포지토리 주소]
git remote -v # 연결 확인
git add .
git commit -m "커밋 메시지"
git push origin master
로컬 기본 브랜치는 master, GitHub 기본 브랜치는 main으로 이름이 다를 수 있음
Streamlit Cloud 배포 순서
- share.streamlit.io 접속 → GitHub 계정으로 로그인
- Create app → Deploy public app from GitHub
- Repository, Branch(main), Main file(app.py) 선택
- Advanced Settings:
- Python 버전: 3.12
- Secrets: secrets.toml 내용 붙여넣기 → Save
- Deploy 버튼 클릭
코드 수정 후에는 git commit & push만 하면 자동으로 배포에 반영됨 ✅
🐛 배포 실패 주요 원인 & 해결
| 에러 | 원인 | 해결 |
| ModuleNotFoundError | requirements.txt에 패키지 누락 | 패키지 추가 후 commit & push |
| FileNotFoundError | 절대 경로 하드코딩 (C:\\Users\\...) | 상대 경로 또는 현재 파일 기반 경로로 변경 |
| KeyError | API 키 미설정 | Streamlit Cloud → App Settings → Secrets 탭에서 추가 |
| 메모리 초과 | 대용량 데이터를 한꺼번에 로드 | 아래 메모리 최적화 기법 적용 |
| 계속 로딩 중 | 코드 오류, 무한 루프 | 중간중간 디버깅 메시지 추가 |
💾 대용량 파일 처리 전략
GitHub 파일 크기 제한
- 일반 파일: 100MB
- Git LFS 사용 시: 최대 2GB
- 2GB 초과: Google Drive + gdown 라이브러리로 다운로드
# Git LFS 사용법 (최초 1회)
git lfs install
git lfs track "*.csv"
git add .gitattributes
git commit & push
메모리 최적화 기법
- 데이터 타입 최적화 — int64 → int8 (8바이트 → 1바이트), float64 → float32
- 주의: int8은 0~255 범위만 표현 가능
- Parquet 파일 사용 — CSV 대비 용량 50~90% 감소, 읽기 속도 향상
df.to_parquet('file.parquet', compression='gzip')
pd.read_parquet('file.parquet')
대용량 처리 라이브러리
| 도구 | 특징 |
| Polars | Pandas보다 빠르고 메모리 효율적. 필요한 부분만 로드하여 처리 |
| DuckDB | SQL로 대용량 CSV 직접 쿼리. Pandas 대비 수천 배 빠름 (3GB 기준 수십 초 → 0.02초) |
| Polars + DuckDB 조합 | DuckDB로 필요한 부분만 추출 → Polars로 분석 → Pandas로 추가 가공 |
import duckdb
con = duckdb.connect()
df = con.sql("SELECT * FROM 'data.csv' WHERE year = 2024").df()
Streamlit Cloud 리소스 제한
- 메모리: 최소 690MB ~ 최대 2.7GB
- 디스크: 최대 50GB
머신러닝 모델 저장
- pickle 대신 joblib 사용 → 압축 저장으로 용량 절감
최종 프로젝트(3)
📊 프로젝트 개요
- 분석 대상: 2024년 텍사스 레인저스 시즌
- 핵심 문제: 기대 승률 vs 실제 승률의 괴리 → 전반부 선전 후 후반부 급격한 하락
- 분석 목표: 기대 성적 대비 실제 성적 차이 원인 규명 + 2026년 시즌 개선 방안 도출
🗂️ 데이터 수집 전략
주요 데이터 소스
- FanGraphs – 세이버메트릭스 지표
- Baseball Reference
- Baseball Savant
수집 방법
- CSV 다운로드 + API 활용 병행
🛠️ 오늘의 기술적 이슈 & 해결
💡FanGraphs 팀 페이지에서 네트워크 API로 데이터 수집이 안 됐던 이유
팀 페이지는 SSR(Server-Side Rendering) 방식 → 완성된 HTML을 서버에서 전송하기 때문에 API 엔드포인트가 노출되지 않음
해결 방법
- BeautifulSoup 등을 활용한 정적 웹 크롤링 방식으로 전환
- tbody, tr, td 태그 파싱으로 게임 로그 데이터 추출 성공 ✅
- 선수별 페이지는 기존 API 방식으로 수집 가능 (팀 페이지만 SSR)
핵심 개념 정리
| 방식 | 설명 |
| SSR | 서버에서 완성된 HTML을 보내줌 → 정적 크롤링 필요 |
| CSR | 클라이언트에서 JS가 데이터를 요청 → API 엔드포인트 확인 가능 |
📐 고려 중인 분석 지표
- OPS (출루율 + 장타율) – 득점과 상관관계 높음
- xStats (기대 지표) vs 실제 지표 비교
- 단, 기대값 산정 방식이 공개되지 않아 검증 어려움
- WAR – fWAR(FanGraphs)와 bWAR(Baseball Reference) 산정 방식 차이 있음
- 볼 트래킹 데이터
📅 분석 각도
- 월별 / 분기별 성적 변화
- 홈 / 원정 경기 비교
- 이닝별 성적 (전반부 vs 후반부)
- 접전(1점 차 경기) 분석
- 선발 / 불펜 투수 분리 분석
- 선수 부상 이력 & 나이 요인
- 레딧 팬 커뮤니티 감정 분석 (Reddit API 승인 후 진행 예정)
QCC 3회차
Q1.


SELECT
login_cnt AS unique_logins,
COUNT(*) AS employee_count
FROM (
SELECT
employee_id,
COUNT(*) AS login_cnt
FROM logins
WHERE login_result = 'SUCCESS'
AND login_time >= '2023-07-01'
AND login_time < '2023-10-01'
GROUP BY employee_id
) t
GROUP BY login_cnt
ORDER BY unique_logins ASC;
# 내가 작성한 쿼리
WITH success_logins AS (
SELECT employee_id, login_id
FROM qcc.logins
WHERE login_result = 'SUCCESS'
AND login_time >= '2023-07-01'
AND login_time < '2023-10-01'
),
login_counts AS (
SELECT employee_id, COUNT(distinct login_id) AS unique_logins
FROM success_logins
GROUP BY employee_id
)
SELECT unique_logins, COUNT(1) AS employee_count
FROM login_counts
GROUP BY unique_logins
ORDER BY unique_logins
# 정답 쿼리
Q2.

SELECT
employee_id,
name,
salary
FROM employee_salary
WHERE salary = (
SELECT MIN(salary)
FROM (
SELECT DISTINCT salary
FROM employee_salary
ORDER BY salary DESC
LIMIT 3
# LIMIT 1 OFFSET 2
) t
)
ORDER BY employee_id ASC;
# 내가 작성한 쿼리
WITH salary_ranked AS (
SELECT employee_id, name, salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rnk
FROM qcc.employee_salary
)
SELECT employee_id, name, salary
FROM salary_ranked
WHERE rnk = 3
ORDER BY employee_id
# 정답 쿼리
Q3.


SELECT
ROUND(SUM(CASE WHEN s.department <> r.department THEN 1 ELSE 0 END) * 100.0/ COUNT(*), 1) AS inter_department_msg_pct
FROM messages m
JOIN employees s
ON m.sender_id = s.employee_id
JOIN employees r
ON m.receiver_id = r.employee_id;
# 내가 작성한 쿼리
SELECT
ROUND(100.0 * SUM(CASE WHEN e1.department != e2.department THEN 1 ELSE 0 END) / COUNT(*), 1) AS inter_department_msg_pct
FROM qcc.messages m
JOIN qcc.employees e1 ON m.sender_id = e1.employee_id
JOIN qcc.employees e2 ON m.receiver_id = e2.employee_id
# 정답 쿼리
Q4.


WITH converted_users AS (
SELECT DISTINCT us.user_id
FROM qcc.ad_attribution a
JOIN qcc.user_sessions us ON a.session_id = us.session_id
WHERE a.converted = TRUE
), first_sessions AS (
SELECT us.user_id, a.session_id, us.created_at, a.channel,
ROW_NUMBER() OVER (PARTITION BY us.user_id ORDER BY us.created_at) AS rn
FROM qcc.user_sessions us
JOIN converted_users cu ON us.user_id = cu.user_id
JOIN qcc.ad_attribution a ON us.session_id = a.session_id
)
SELECT user_id, channel
FROM first_sessions
WHERE rn = 1
ORDER BY user_id
# 정답 쿼리

'내일배움캠프 데이터 분석' 카테고리의 다른 글
| 76일차) 내일배움캠프 데이터 분석 TIL - 최종 프로젝트(5) (0) | 2026.04.14 |
|---|---|
| 75일차) 내일배움캠프 데이터 분석 TIL - 최종 프로젝트(4) (0) | 2026.04.13 |
| 73일차) 내일배움캠프 데이터 분석 TIL - Streamlit(3), 최종 프로젝트(2) (1) | 2026.04.09 |
| 72일차) 내일배움캠프 데이터 분석 TIL - 이커머스(4), 최종 프로젝트(1) (0) | 2026.04.08 |
| 71일차) 내일배움캠프 데이터 분석 TIL - 밍글데이(2) (0) | 2026.04.07 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- SQL
- 비전공자코딩
- 텍스트분석
- 태블로
- 판다스
- 코딩처음
- git
- 내일배움캠프
- github
- 데이터분석
- 파이썬입문
- Python
- 파이썬
- GoogleColab
- 머신러닝
- 코딩기초
- 데이터분석입문
- 구글코랩
- Tableau
- 프로그래밍입문
- 코드카타
- 중학생코딩
- 통계
- Til
- 데이터시각화
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 26 | 27 | 28 | 29 | 30 |
| 31 |
글 보관함
