Python으로 인터랙티브 아이리스 꽃 분류기 GUI 만들기

발행: (2026년 1월 19일 오전 10:30 GMT+9)
7 min read
원문: Dev.to

I’m happy to translate the article for you, but I’ll need the full text of the post (excluding the source link you’ve already provided). Could you please paste the article’s content here? Once I have it, I’ll translate everything—preserving the markdown formatting, code blocks, URLs, and technical terms—while keeping the source line unchanged at the top.

우리가 사용할 것

  • scikit‑learn – 머신러닝
  • pandas – CSV 처리
  • tkinter + ttkbootstrap – GUI
  • Optional: tkinterdnd2 – 드래그 & 드롭 지원

전체 저장소를 여기에서 복제할 수 있습니다:

🔗 Iris-Flower-Classifier-GUI on GitHub

의존성 설치

pip install pandas scikit-learn ttkbootstrap
# Optional: for drag & drop
pip install tkinterdnd2

Note: tkinter는 대부분의 시스템에서 Python과 함께 사전 설치됩니다.

라이브러리 가져오기

import os, sys, threading
import pandas as pd
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

import ttkbootstrap as tb
from ttkbootstrap.constants import *

# Optional drag & drop
try:
    from tkinterdnd2 import TkinterDnD, DND_FILES
    DND_ENABLED = True
except ImportError:
    DND_ENABLED = False
    print("Drag & Drop requires tkinterdnd2: pip install tkinterdnd2")

여기서 가져옵니다:

  • pandas는 CSV 파일을 처리하기 위해 사용합니다
  • tkinterttkbootstrap은 현대적인 GUI 요소를 위해 사용합니다
  • tkinterdnd2는 CSV 드래그‑앤‑드롭 지원을 원할 경우 사용합니다

Iris 머신러닝 모델 만들기

from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler


class IrisModel:
    def __init__(self):
        data = load_iris()
        self.X = data.data
        self.y = data.target
        self.target_names = data.target_names
        self.scaler = StandardScaler()

        # Scale features
        X_scaled = self.scaler.fit_transform(self.X)

        # Train/test split
        X_train, X_test, y_train, y_test = train_test_split(
            X_scaled, self.y, test_size=0.2, random_state=42
        )

        # Random Forest classifier
        self.clf = RandomForestClassifier(n_estimators=100, random_state=42)
        self.clf.fit(X_train, y_train)

    def predict(self, X):
        X_scaled = self.scaler.transform(X)
        preds = self.clf.predict(X_scaled)
        return [self.target_names[p] for p in preds]

설명

  • 특징을 표준화하여 모델 성능을 향상시킵니다.
  • 랜덤 포레스트 분류기는 초보자에게 친숙하며 이 분류 작업에 잘 맞습니다.

CSV 처리용 워커

이 워커는 GUI가 인터페이스가 멈추지 않도록 여러 CSV 파일을 처리할 수 있게 합니다.

class ClassifierWorker:
    def __init__(self, files, callbacks):
        self.files = files
        self.callbacks = callbacks
        self._running = True
        self.model = IrisModel()

    def stop(self):
        self._running = False

    def run(self):
        total = len(self.files)
        for i, file in enumerate(self.files):
            if not self._running:
                break
            try:
                df = pd.read_csv(file)
                required = {"sepal_length", "sepal_width", "petal_length", "petal_width"}
                if set(df.columns) >= required:
                    X = df[["sepal_length", "sepal_width",
                            "petal_length", "petal_width"]].values
                    preds = self.model.predict(X)
                    if "found" in self.callbacks:
                        self.callbacks["found"](file, preds)
                else:
                    if "found" in self.callbacks:
                        self.callbacks["found"](file, ["Error: Missing required columns"])
            except Exception as e:
                if "found" in self.callbacks:
                    self.callbacks["found"](file, [f"Error: {str(e)}"])
            # Progress update
            if "progress" in self.callbacks:
                self.callbacks["progress"](int((i + 1) / total * 100))
        # Finished
        if "finished" in self.callbacks:
            self.callbacks["finished"]()

설명

  • CSV 파일을 하나씩 읽습니다.
  • Iris 모델을 사용해 종을 예측합니다.
  • 진행 상황 업데이트를 비동기적으로 GUI에 전송합니다.

Source:

GUI 구축

메인 애플리케이션 클래스

class IrisClassifierApp:
    def __init__(self):
        if DND_ENABLED:
            self.root = TkinterDnD.Tk()
        else:
            self.root = tb.Window(themename="darkly")
        self.root.title("IrisClassifier v1.1")
        self.root.minsize(1000, 700)

        self.worker_obj = None
        self.file_set = set()
        self.model = IrisModel()

        self._build_ui()
        self._apply_styles()
  • 드래그‑앤‑드롭이 가능한지 확인합니다.
  • 현대적인 다크 테마를 위해 ttkbootstrap을 초기화합니다.

GUI 레이아웃

def _build_ui(self):
    main = tb.Frame(self.root, padding=10)
    main.pack(fill="both", expand=True)

    tb.Label(
        main,
        text="🌸 Iris Flower Classifier",
        font=("Segoe UI", 20, "bold")
    ).pack(pady=(0, 10))

    # File selection row
    row1 = tb.Frame(main)
    row1.pack(fill="x", pady=(0, 6))

    self.path_input = tb.Entry(row1, width=80)
    self.path_input.pack(side="left", fill="x", expand=True, padx=(0, 6))
    self.path_input.insert(0, "Drag & drop CSV files here…")

설명

  • 파일 경로 입력을 위한 텍스트 박스를 생성합니다.
  • 명확하고 친절한 라벨을 추가합니다.

버튼 및 진행 바

    browse_btn = tb.Button(
        row1, text="📂 Browse", bootstyle="info", command=self.browse
    )
    browse_btn.pack(side="left", padx=3)

    self.start_btn = tb.Button(
        row1, text="🚀 Classify CSV", bootstyle="success", command=self.start
    )
    self.start_btn.pack(side="left", padx=3)

    self.cancel_btn = tb.Button(
        row1, text="⏹ Cancel", bootstyle="danger", command=self.cancel
    )
    self.cancel_btn.pack(side="left", padx=3)
    self.cancel_btn.config(state="disabled")

    self.progress = tb.Progressbar(
        main, bootstyle="success-striped", maximum=100
    )
    self.progress.pack(fill="x", pady=10)
  • Browse – 파일 대화상자를 엽니다.
  • Classify CSV – 워커 스레드를 시작합니다.
  • Cancel – 처리를 중단합니다.
  • 진행 바는 분류 진행 상황을 시각화합니다.

(나머지 메서드(browse, start, cancel, _apply_styles 등)는 원본 저장소에 구현되어 있습니다. 파일 선택, 스레드 관리, UI 업데이트를 담당합니다.)

Run the application

if __name__ == "__main__":
    app = IrisClassifierApp()
    app.root.mainloop()

그게 전부입니다! 네 가지 아이리스 측정값이 들어 있는 CSV 파일을 드래그하거나 찾아서 선택하고, Classify 버튼을 누르면 인터페이스가 멈추지 않은 채 예측 결과가 나타납니다. 머신러닝과 GUI 개발을 마음껏 실험해 보세요!

GUI Controls

Browse: Select CSVs → 찾아보기: CSV 선택

Classify CSV: Start predictions → CSV 분류: 예측 시작

Cancel: Stop predictions → 취소: 예측 중지

Progress bar: Visual feedback → 진행 표시줄: 시각적 피드백

수동 입력 추가

manual_frame = tb.Labelframe(main, text="Manual Input", padding=10)
manual_frame.pack(fill="x", pady=(10, 6))

labels = ["Sepal Length", "Sepal Width", "Petal Length", "Petal Width"]
self.manual_entries = {}
for i, label in enumerate(labels):
    tb.Label(manual_frame, text=label).grid(row=0, column=i * 2, sticky="w")
    entry = tb.Entry(manual_frame, width=8)
    entry.grid(row=0, column=i * 2 + 1)
    entry.insert(0, "0")
    self.manual_entries[label] = entry

predict_btn = tb.Button(
    manual_frame,
    text="🔮 Predict",
    bootstyle="info",
    command=self.manual_predict,
)
predict_btn.grid(row=0, column=8, padx=10)

self.manual_result = tb.Label(
    manual_frame,
    text="Prediction: ---",
    font=("Segoe UI", 12, "bold"),
)
self.manual_result.grid(row=1, column=0, columnspan=9, pady=(6, 0), sticky="w")

설명

  • 사용자는 꽃의 측정값을 수동으로 입력할 수 있습니다.
  • Predict 버튼을 클릭하면 바로 종을 확인할 수 있습니다.

Run the App (alternative entry)

if __name__ == "__main__":
    app = IrisClassifierApp()
    app.run()

And that’s it! Your interactive Iris Flower Classifier is ready to run.

Optional Features

  • Drag & Drop CSVs (requires tkinterdnd2)
  • Export results to a text file
  • Beautiful dark/light theme with ttkbootstrap

🎯 요약

당신은 다음을 배웠습니다:

  • Iris 데이터셋으로 Random Forest 분류기를 훈련시키기
  • 이를 활용하는 Python GUI 만들기
  • CSV 파일을 로드하고 수동으로 예측하기
  • 진행 상황과 결과를 시각화하기

전체 프로젝트를 확인해 보세요:

🔗 Iris-Flower-Classifier-GUI on GitHub

Iris Flower Classifier GUI

Back to Blog

관련 글

더 보기 »

기술은 구원자가 아니라 촉진자다

왜 사고의 명확성이 사용하는 도구보다 더 중요한가? Technology는 종종 마법 스위치처럼 취급된다—켜기만 하면 모든 것이 개선된다. 새로운 software, ...

에이전틱 코딩에 입문하기

Copilot Agent와의 경험 나는 주로 GitHub Copilot을 사용해 인라인 편집과 PR 리뷰를 수행했으며, 대부분의 사고는 내 머리로 했습니다. 최근 나는 t...