Python으로 데이터 분석을 하다 보면 결과를 노트북 안에서만 확인하는 데 한계가 생긴다.
분석 결과를 다른 사람에게 보여주거나, 사용자가 직접 옵션을 바꿔가며 결과를 확인하게 하려면 웹 UI가 필요하다.
이때 Streamlit을 사용하면 HTML, CSS, JavaScript를 직접 작성하지 않아도 Python 코드만으로 데이터 분석용 웹 애플리케이션을 빠르게 만들 수 있다.
이번 글에서는 Streamlit의 기본 구조부터 텍스트, 데이터프레임, 입력 위젯, 차트, 버튼 이벤트까지 한 흐름으로 정리한다.
Python 데이터/모델
↓
Streamlit UI
↓
사용자 입력
↓
분석 또는 예측
↓
브라우저에서 결과 확인
Streamlit은 Python 기반의 데이터 앱을 빠르게 만들기 위한 오픈소스 프레임워크다.
일반적인 웹 애플리케이션을 만들려면 프론트엔드와 백엔드를 따로 구성해야 하는 경우가 많지만, Streamlit은 Python 코드 안에서 화면 구성과 데이터 처리를 함께 작성할 수 있다.
예를 들어 다음과 같은 작업에 잘 어울린다.
특히 분석 결과를 빠르게 웹 화면으로 보여주는 용도에서 진입장벽이 낮다.
가상환경을 사용하고 있다면 해당 환경을 활성화한 뒤 설치하는 것이 좋다.
pip install streamlit
conda activate data_env
pip install streamlit
설치 여부는 다음 명령어로 확인할 수 있다.
streamlit --version
정상적으로 버전이 출력되면 준비가 끝난다.
Streamlit 파일을 일반 Python 프로그램처럼 실행하면 웹 앱이 정상적으로 열리지 않을 수 있다.
예를 들어 다음처럼 실행하는 것은 Streamlit 앱 실행 방식이 아니다.
python app.py
Streamlit 앱은 반드시 다음처럼 실행한다.
streamlit run app.py
실행하면 기본적으로 로컬 웹 서버가 열리고 브라우저에서 확인할 수 있다.
보통 개발 환경에서는 다음 주소가 사용된다.
http://localhost:8501
만약 IDE에서 python app.py로 실행했는데 다음과 비슷한 안내가 보인다면,
To view this Streamlit app on a browser,
run it with the following command:
streamlit run app.py
코드 오류라기보다 실행 방식이 잘못된 경우다.
app.py 파일을 하나 만들고 다음 코드부터 시작해보자.
import streamlit as st
st.title("서비스 데이터 대시보드")
st.write("Streamlit으로 만든 간단한 데이터 앱입니다.")
터미널에서 실행한다.
streamlit run app.py
브라우저에 제목과 문장이 표시된다면 기본 환경은 정상적으로 구성된 것이다.
Streamlit 코드의 중요한 특징은 작성한 순서대로 화면이 구성된다는 점이다.
import streamlit as st
st.title("대시보드")
st.header("오늘의 서비스 지표")
st.write("사용자 행동 데이터를 확인합니다.")
화면도 그대로 다음 순서로 표시된다.
대시보드
↓
오늘의 서비스 지표
↓
사용자 행동 데이터를 확인합니다.
처음 사용할 때는 이 단순한 구조를 이해하는 것이 중요하다.
Streamlit은 제목, 설명, Markdown, 코드 등을 바로 출력할 수 있다.
import streamlit as st
st.title("서비스 분석")
st.header("트래픽 현황")
st.subheader("최근 7일")
st.write("API 요청량과 오류율을 확인합니다.")
st.markdown("""
**체크 포인트**
- 요청량
- 평균 응답시간
- 오류율
""")
자주 사용하는 함수는 다음과 같다.
| 함수 | 용도 |
|---|---|
st.title() | 페이지 대표 제목 |
st.header() | 큰 섹션 제목 |
st.subheader() | 하위 섹션 제목 |
st.write() | 문자열, 객체 등을 범용적으로 출력 |
st.markdown() | Markdown 문법 사용 |
st.code() | 코드 블록 출력 |
st.caption() | 보조 설명 |
데이터 분석 앱에서는 표를 보여주는 기능이 중요하다.
간단한 예제 데이터를 만들어보자.
import pandas as pd
import streamlit as st
df = pd.DataFrame({
"endpoint": ["/login", "/products", "/cart", "/orders"],
"requests": [1820, 3540, 1210, 890],
"avg_latency_ms": [118, 96, 132, 165],
"error_rate": [0.8, 0.4, 1.2, 0.9]
})
Streamlit에서는 다음처럼 출력할 수 있다.
st.dataframe(df)
st.dataframe()은 스크롤과 정렬 등 인터랙티브한 표 기능을 제공한다.
단순 정적 표가 필요하다면 다음도 사용할 수 있다.
st.table(df)
둘의 차이는 간단하다.
| 함수 | 특징 |
|---|---|
st.dataframe() | 인터랙티브한 데이터 탐색에 적합 |
st.table() | 고정된 정적 표에 적합 |
분석용 화면이라면 대부분 st.dataframe()이 더 편하다.
사용자에게 필요한 정보만 선택해서 보여주고 싶다면 체크박스를 사용할 수 있다.
show_raw = st.checkbox("원본 데이터 보기")
if show_raw:
st.dataframe(df)
핵심은 위젯이 값을 반환한다는 점이다.
checkbox 선택
↓
True
↓
if 문 실행
↓
데이터 출력
Streamlit의 많은 UI 요소는 이처럼 Python 변수와 바로 연결된다.
여러 옵션 중 하나를 선택하게 하고 싶다면 selectbox가 편하다.
metric = st.selectbox(
"확인할 지표를 선택하세요",
[
"요청량",
"평균 응답시간",
"오류율"
]
)
선택된 값은 일반 Python 문자열로 사용할 수 있다.
if metric == "요청량":
st.bar_chart(
df.set_index("endpoint")["requests"]
)
elif metric == "평균 응답시간":
st.bar_chart(
df.set_index("endpoint")["avg_latency_ms"]
)
else:
st.bar_chart(
df.set_index("endpoint")["error_rate"]
)
이렇게 하면 하나의 페이지에서도 사용자가 보고 싶은 분석을 직접 바꿀 수 있다.
수치 범위를 직관적으로 조절할 때는 slider가 유용하다.
threshold = st.slider(
"응답시간 경고 기준(ms)",
min_value=50,
max_value=500,
value=150,
step=10
)
선택된 값은 그대로 숫자로 사용할 수 있다.
slow_api = df[
df["avg_latency_ms"] >= threshold
]
st.dataframe(slow_api)
이렇게 하면 사용자가 기준값을 바꿀 때마다 결과가 다시 계산된다.
선택지가 적고 모두 화면에 보여야 한다면 radio가 적합하다.
mode = st.radio(
"조회 방식",
[
"전체 보기",
"오류율 높은 API만 보기"
]
)
if mode == "전체 보기":
result = df
else:
result = df[df["error_rate"] >= 1.0]
st.dataframe(result)
selectbox와 비교하면 다음과 같다.
| 위젯 | 적합한 경우 |
|---|---|
selectbox | 선택지가 많거나 화면을 작게 쓰고 싶을 때 |
radio | 선택지가 적고 모두 바로 보여주고 싶을 때 |
모델이나 계산식에 숫자를 직접 넣어야 한다면 number_input을 사용할 수 있다.
requests = st.number_input(
"예상 요청량",
min_value=0,
value=1000,
step=100
)
latency = st.number_input(
"평균 응답시간(ms)",
min_value=0.0,
value=120.0,
step=5.0
)
반환값은 일반 숫자이므로 바로 계산에 사용할 수 있다.
load_score = requests * latency
st.write("간단한 부하 점수:", load_score)
입력값을 모두 받은 뒤 특정 시점에만 계산하고 싶다면 버튼을 사용한다.
if st.button("분석 실행"):
score = requests * latency
st.success(
f"계산된 부하 점수는 {score:,.0f}입니다."
)
이 구조는 머신러닝 예측 화면에서도 거의 동일하게 사용된다.
사용자 입력
↓
버튼 클릭
↓
전처리
↓
model.predict()
↓
결과 출력
Streamlit은 상태에 맞는 메시지를 쉽게 출력할 수 있다.
st.success("데이터 로딩이 완료되었습니다.")
st.info("분석 조건을 선택하세요.")
st.warning("응답시간이 기준값을 초과했습니다.")
st.error("데이터를 불러오지 못했습니다.")
데이터 앱에서는 처리 상태를 사용자에게 알려주는 것이 중요하다.
대시보드처럼 정보를 좌우로 배치하고 싶다면 st.columns()를 사용할 수 있다.
col1, col2, col3 = st.columns(3)
with col1:
st.metric("요청량", "7,460")
with col2:
st.metric("평균 응답시간", "128 ms")
with col3:
st.metric("오류율", "0.8%")
이 방식은 KPI 카드 형태의 화면을 만들 때 자주 사용한다.
필터나 설정값은 본문보다 사이드바에 두는 것이 깔끔한 경우가 많다.
service = st.sidebar.selectbox(
"서비스",
[
"전체",
"인증",
"상품",
"주문"
]
)
min_requests = st.sidebar.slider(
"최소 요청량",
0,
5000,
500
)
본문에는 결과만 남길 수 있어 대시보드 구성이 더 명확해진다.
로고나 분석 결과 이미지를 넣고 싶다면 st.image()를 사용할 수 있다.
st.image(
"./assets/service-logo.png",
width=160
)
프로젝트에서는 사용자 환경에 종속된 절대 경로보다 상대 경로를 사용하는 편이 관리하기 쉽다.
project/
├─ app.py
└─ assets/
└─ service-logo.png
Streamlit이 자체 차트를 제공하지만 기존 Matplotlib/Seaborn 코드도 그대로 활용할 수 있다.
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots()
sns.scatterplot(
data=df,
x="requests",
y="avg_latency_ms",
ax=ax
)
st.pyplot(fig)
즉 기존 분석 노트북의 시각화 코드를 완전히 새로 작성할 필요 없이 웹 UI에 연결하는 방식으로 확장할 수 있다.
Streamlit은 이미 학습된 모델의 입력 화면을 만들 때도 많이 사용한다.
예를 들어 서비스 트래픽을 이용해 부하 점수를 예측하는 모델이 있다고 가정해보자.
import joblib
import numpy as np
import streamlit as st
model = joblib.load("./model.pkl")
scaler = joblib.load("./scaler.pkl")
사용자 입력을 받는다.
requests = st.number_input(
"분당 요청량",
min_value=0.0,
value=1000.0
)
latency = st.number_input(
"평균 응답시간(ms)",
min_value=0.0,
value=120.0
)
error_rate = st.number_input(
"오류율(%)",
min_value=0.0,
max_value=100.0,
value=1.0
)
버튼을 눌렀을 때 모델에 전달한다.
if st.button("예측하기"):
new_data = np.array([
requests,
latency,
error_rate
]).reshape(1, -1)
scaled_data = scaler.transform(new_data)
prediction = model.predict(
scaled_data
)
st.success(
f"예측 결과: {prediction[0]:.3f}"
)
여기서 중요한 것은 학습 때 사용한 전처리를 예측 때도 동일하게 적용해야 한다는 점이다.
학습 데이터
→ scaler.fit()
→ scaler.transform()
→ model.fit()
새 입력
→ 같은 scaler.transform()
→ model.predict()
새로운 입력에서 다시 fit()하면 학습 당시 기준이 달라지므로 올바른 예측이 되지 않는다.
Streamlit을 처음 사용할 때 가장 헷갈리는 부분 중 하나는 위젯 값이 바뀔 때 스크립트가 다시 실행된다는 점이다.
예를 들어 다음 코드가 있다고 하자.
value = st.slider(
"값",
0,
100,
50
)
st.write(value)
슬라이더를 움직이면 앱이 해당 시점의 값으로 다시 계산된다.
이를 단순하게 표현하면 다음과 같다.
사용자 입력 변경
↓
스크립트 재실행
↓
현재 위젯 상태 반영
↓
화면 다시 렌더링
따라서 일반적인 GUI 프레임워크처럼 모든 이벤트마다 별도 콜백을 작성하지 않아도 된다.
이 단순한 실행 모델이 Streamlit의 큰 장점이다.
지금까지 사용한 기능을 하나로 묶어보자.
import pandas as pd
import streamlit as st
st.set_page_config(
page_title="API Metrics Dashboard",
layout="wide"
)
st.title("API Metrics Dashboard")
df = pd.DataFrame({
"endpoint": [
"/login",
"/products",
"/cart",
"/orders"
],
"requests": [
1820,
3540,
1210,
890
],
"avg_latency_ms": [
118,
96,
132,
165
],
"error_rate": [
0.8,
0.4,
1.2,
0.9
]
})
metric = st.sidebar.selectbox(
"확인할 지표",
[
"요청량",
"평균 응답시간",
"오류율"
]
)
show_table = st.sidebar.checkbox(
"원본 데이터 보기"
)
col1, col2, col3 = st.columns(3)
with col1:
st.metric(
"전체 요청량",
f"{df['requests'].sum():,}"
)
with col2:
st.metric(
"평균 응답시간",
f"{df['avg_latency_ms'].mean():.1f} ms"
)
with col3:
st.metric(
"평균 오류율",
f"{df['error_rate'].mean():.2f}%"
)
if show_table:
st.subheader("원본 데이터")
st.dataframe(df)
st.subheader("지표 시각화")
chart_df = df.set_index("endpoint")
if metric == "요청량":
st.bar_chart(
chart_df["requests"]
)
elif metric == "평균 응답시간":
st.bar_chart(
chart_df["avg_latency_ms"]
)
else:
st.bar_chart(
chart_df["error_rate"]
)
실행한다.
streamlit run app.py
이 정도 코드만으로도 다음 기능을 가진 간단한 데이터 앱이 된다.
사이드바 필터
+
KPI 카드
+
데이터프레임
+
선택 가능한 차트
Streamlit은 전통적인 웹 프레임워크와 접근 방식이 다르다.
| 구분 | 일반적인 웹 앱 | Streamlit |
|---|---|---|
| 화면 구성 | HTML/JS/프레임워크 | Python 함수 |
| 상태 처리 | 이벤트·상태 관리 필요 | 위젯 상태 기반 재실행 |
| 목적 | 범용 웹 서비스 | 데이터/AI 앱 |
| 개발 속도 | 구조 설계 필요 | 빠른 프로토타이핑 |
| UI 자유도 | 높음 | 상대적으로 제한적 |
따라서 Streamlit은 React나 Next.js를 대체하는 도구라기보다 데이터 분석 결과를 빠르게 제품 형태로 보여주는 도구에 가깝다.
예를 들어 다음 상황에서 특히 효율적이다.
모델 개발
↓
Jupyter Notebook 검증
↓
Streamlit 데모 앱
↓
사용자 피드백
↓
필요하면 정식 서비스로 확장
AI/데이터 프로젝트에서는 이 중간 단계가 상당히 유용하다.
python app.py와 streamlit run app.pyStreamlit 앱은 다음 명령어로 실행해야 한다.
streamlit run app.py
st.table()과 st.dataframe()탐색 가능한 표가 필요하면 st.dataframe()을 사용하는 것이 좋다.
st.dataframe(df)
selected = st.selectbox(
"선택",
["A", "B", "C"]
)
selected에는 선택된 문자열이 저장된다.
if st.button("실행"):
st.success("작업 완료")
new_data = scaler.transform(new_data)
prediction = model.predict(new_data)
새 데이터로 scaler를 다시 학습시키면 안 된다.
python app.py가 아니라 streamlit run app.py를 사용한다.st.title(), st.header(), st.markdown() 등으로 텍스트 UI를 구성할 수 있다.st.dataframe()을 사용하면 데이터프레임을 인터랙티브하게 표시할 수 있다.checkbox, radio, selectbox, slider, number_input, button 등 다양한 입력 위젯을 사용할 수 있다.st.columns()와 st.sidebar를 활용하면 간단한 대시보드 레이아웃을 만들 수 있다.st.pyplot()으로 연결할 수 있다.Streamlit의 핵심은 웹 개발 문법을 많이 배우는 것이 아니라 Python 코드와 UI를 직접 연결하는 방식을 이해하는 데 있다.
기본 흐름은 생각보다 단순하다.
데이터 또는 모델 준비
→ UI 구성
→ 사용자 입력 받기
→ Python 코드 실행
→ 결과 화면 출력
분석 코드를 Jupyter Notebook 안에만 두는 것과, 사용자가 직접 조작할 수 있는 웹 화면으로 만드는 것은 활용도에서 큰 차이가 있다.
특히 데이터 분석이나 머신러닝 프로젝트에서는 Streamlit을 이용해 결과를 빠르게 웹 앱 형태로 만들어보는 것만으로도 분석 결과 공유 → 사용자 테스트 → 프로토타입 검증까지 자연스럽게 연결할 수 있다.