ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 감(感)이 아닌 '통계'로 증명하기: 단 3개의 시료로 품질 동등성 검증하기 (Python T-test)
    제조업 30년, 데이터로 다시 쓰다 2026. 1. 6. 09:02
    728x90
    반응형
    SMALL

    현장에서 품질 관리를 하다 보면 늘 마주치는 딜레마가 있습니다. 바로 '시료의 개수' 문제입니다.
    양산 중인 제품(B)은 데이터가 넘쳐납니다. 10개, 100개, 원한다면 수천 개의 데이터도 추출할 수 있습니다. 하지만 새로 개발되거나 변경 승인을 요청하는 시료(A)는 고작해야 3개, 많아야 5개 정도가 입고되는 경우가 다반사입니다.
    "XXX님, 시료 3개 측정해 보니 평균이 양산품이랑 비슷합니다. 승인할까요?"
    예전 같으면 오랜 경험(감)과 평균값의 차이 정도만 보고 "그래요, 진행하세요"라고 했을지도 모릅니다. 하지만 30년 넘게 제조업에 몸담으면서 느낀 점은, 숫자는 거짓말을 하지 않지만 '평균'은 종종 우리를 속인다는 것입니다.
    이제는 달라져야 한다고 생각합니다. 나의 경험에 데이터 분석(Data Analysis)이라는 무기를 더해, 더 객관적이고 과학적인 의사결정을 내리고자 합니다. 오늘은 파이썬(Python)을 활용해 단 3개의 시료만으로도 양산품과 통계적으로 동등함을 증명하는 과정을 기록해 봅니다.

    1. 문제 상황: N=3 vs N=10

    상황은 이렇습니다.

    • A 시료 (신규): 단 3개 입고 (N=3)
    • B 시료 (양산): 데이터 확보 용이 (N=10 추출)

    단순히 평균값을 비교해 보니 A는 6.461mm, B는 6.449mm가 나왔습니다. 차이는 불과 0.012mm. 공차 범위 내에 있으니 괜찮은 걸까요? 만약 A 시료 3개가 우연히 좋게 나온 것이라면요?
    이 불확실성을 없애기 위해 통계적 가설 검정(T-test)을 도입했습니다.

    2. 해결 방법: Welch's T-test (이분산 가정 T-검정)

    두 집단의 데이터 개수가 다르고(3개 vs 10개), 표본의 분산(퍼짐 정도)이 같다고 장담할 수 없기 때문에 일반적인 T-test 대신 Welch's T-test를 사용했습니다.
    제가 공부하고 있는 파이썬(Python)의 scipy.stats 라이브러리를 활용하면, 복잡한 통계 공식 없이도 단 몇 줄의 코드로 이 검증이 가능합니다.

    3. 분석 결과 및 시각화

    파이썬으로 분석한 결과는 명쾌했습니다.

     

    • P-value (유의확률): 0.099

    통계학적으로 P-value가 0.05(5%)보다 크다는 것은 "두 집단 간에 통계적으로 유의미한 차이가 없다"는 것을 의미합니다. 즉, 0.099라는 수치는 "A 시료가 B 양산품과 다르다고 말할 근거가 없다(동등하다)"는 강력한 증거가 됩니다.
    그래프를 보면 더욱 확실합니다. 파란색 점(개별 데이터)들이 양산품의 산포 범위(회색 박스) 안에 안정적으로 들어와 있음을 한눈에 확인할 수 있습니다.

    4. 결론: 경험 위에 데이터를 쌓다

    과거에는 "이 정도면 문제없어"라고 경험으로 설득했다면, 이제는 한 장의 그래프와 P-value라는 숫자로 고객과 실무자를 설득합니다.
    "통계적으로 차이가 없음이 95% 신뢰수준에서 증명되었습니다."
    이 한마디가 주는 무게감은 다릅니다. 은퇴를 앞둔 시점이지만, 품질경영기사 자격증에 이어 빅데이터 분석 기사에 도전하는 이유도 바로 여기에 있습니다. 현장의 '감'을 '데이터'로 증명해 낼 때, 제조업의 품질은 한 단계 더 진화하기 때문입니다.
    오늘도 코랩(Colab)을 켜고 데이터를 돌려봅니다. 배움에는 정년이 없습니다.


    [부록] 사용한 파이썬 코드

    혹시 현업에서 비슷한 고민을 하시는 분들을 위해 제가 사용한 코드를 공유합니다. 데이터 입력 부분만 바꾸면 누구나 활용 가능합니다.

     

    참고로..

    "왜 일반 T-test가 아닌 Welch's T-test인가?"

    통계 교과서에 나오는 일반적인 T-test(Student's T-test)는 한 가지 중요한 전제 조건이 필요합니다. 바로 "비교하려는 두 집단의 산포(분산)가 같아야 한다"는 것입니다. 이를 '등분산 가정'이라고 합니다.

    하지만 현장의 데이터는 그렇지 않습니다.

    1. 데이터 개수의 불균형: 시료는 3개뿐이고, 양산 데이터는 10개입니다.
    2. 성격의 차이: 막 만든 시료(A)와 안정된 양산품(B)의 산포가 같다고 장담할 수 없습니다.

    만약 억지로 등분산을 가정하고 분석하면 엉뚱한 결론이 나올 수 있습니다. 그래서 저는 두 집단의 분산이 달라도 정확하게 검정할 수 있는 'Welch's T-test'를 선택했습니다.

    파이썬 코드에서 equal_var=False (등분산이 아니다) 옵션 한 줄만 넣어주면, 파이썬이 알아서 이 깐깐한 검증을 수행해 줍니다. 이것이 데이터 분석이 주는 '안전장치'입니다. 

    import pandas as pd
    import matplotlib.pyplot as plt
    import numpy as np
    from scipy import stats

    # ==========================================
    # 1. 데이터 입력
    # ==========================================
    data_a = [6.469, 6.454, 6.459]
    data_b = [6.459, 6.454, 6.431, 6.457, 6.459,
              6.454, 6.431, 6.457, 6.431, 6.457]

    # ==========================================
    # 2. 통계 분석 (T-test)
    # ==========================================
    mean_a = np.mean(data_a)
    mean_b = np.mean(data_b)
    diff = abs(mean_a - mean_b)

    # T-test (이분산 가정)
    t_stat, p_val = stats.ttest_ind(data_a, data_b, equal_var=False)

    # ==========================================
    # 3. 결과 리포트 텍스트 자동 생성
    # ==========================================
    print("=" * 60)
    print("             [품질 동등성 검증 보고서]")
    print("=" * 60)

    print(f"1. 분석 개요")
    print(f"   - 목적: 시료 A(N={len(data_a)})와 양산품 B(N={len(data_b)}) 간의 치수 동등성 검증")
    print(f"   - 방법: Welch's T-test (데이터 산포가 다를 수 있음을 고려한 통계 검정)")
    print(f"   - 판정 기준: 유의수준 5% (P-value > 0.05 일 경우 '동등'으로 판정)")
    print("-" * 60)

    print(f"2. 데이터 분석 결과")
    print(f"   - A 시료 평균 : {mean_a:.3f} mm")
    print(f"   - B 시료 평균 : {mean_b:.3f} mm")
    print(f"   - 평균 차이   : {diff:.3f} mm")
    print(f"   - ★ P-value   : {p_val:.3f}")
    print("-" * 60)

    print(f"3. 최종 결론 및 해석")

    if p_val > 0.05:
        print("   ✅ 결과: 통계적으로 유의미한 차이가 없습니다. (동등함)")
        print("")
        print("   [상세 해석]")
        print(f"   ① 산출된 P-value({p_val:.3f})가 판정 기준인 0.05보다 큽니다.")
        print("   ② 이는 두 집단 간의 평균 차이가 단순한 우연(Sampling Error)일")
        print("      가능성이 높다는 것을 의미합니다.")
        print("   ③ 따라서, A 시료는 양산 중인 B 시료의 관리 범위 내에 있으며,")
        print("      품질적으로 동등한 수준임을 통계적으로 증명합니다.")
    else:
        print("   ❌ 결과: 통계적으로 유의미한 차이가 발견되었습니다. (다름)")
        print("")
        print("   [상세 해석]")
        print(f"   ① 산출된 P-value({p_val:.3f})가 판정 기준인 0.05보다 작습니다.")
        print("   ② 이는 두 집단 간의 차이가 우연이 아니라 실제 품질 차이일")
        print("      가능성이 매우 높다는 것을 의미합니다.")
        print("   ③ 따라서, 공정 점검 및 재확인이 필요합니다.")

    print("=" * 60)


    # ==========================================
    # 4. 그래프 시각화 (기존과 동일)
    # ==========================================
    plt.figure(figsize=(10, 6))
    plt.boxplot([data_a, data_b], labels=[f'Sample A (N={len(data_a)})', f'Sample B (N={len(data_b)})'],
                widths=0.5, patch_artist=True,
                boxprops=dict(facecolor='#E0E0E0', color='black'),
                medianprops=dict(color='red'))

    x_a = np.random.normal(1, 0.04, size=len(data_a))
    x_b = np.random.normal(2, 0.04, size=len(data_b))
    plt.scatter(x_a, data_a, color='blue', alpha=0.7, s=100)
    plt.scatter(x_b, data_b, color='blue', alpha=0.7, s=100)

    plt.plot([0.8, 1.2], [mean_a]*2, color='green', linestyle='--', linewidth=2, label='Mean')
    plt.plot([1.8, 2.2], [mean_b]*2, color='green', linestyle='--', linewidth=2)

    title_text = "No Significant Difference (OK)" if p_val > 0.05 else "Significant Difference (NG)"
    title_color = 'blue' if p_val > 0.05 else 'red'

    plt.title(f'Sample Comparison (P-value: {p_val:.3f})', fontsize=14, fontweight='bold')
    plt.ylabel('Dimension Value (mm)', fontsize=12)
    plt.grid(True, linestyle=':', alpha=0.6)
    plt.legend(loc='upper right')

    plt.text(1.5, max(max(data_a), max(data_b)) + 0.005, title_text,
             ha='center', va='bottom', fontsize=14, color=title_color, fontweight='bold')
    plt.ylim(min(min(data_a), min(data_b)) - 0.01, max(max(data_a), max(data_b)) + 0.02)
    plt.show()
    ============================================================
                 [품질 동등성 검증 보고서]
    ============================================================
    1. 분석 개요
       - 목적: 시료 A(N=3)와 양산품 B(N=10) 간의 치수 동등성 검증
       - 방법: Welch's T-test (데이터 산포가 다를 수 있음을 고려한 통계 검정)
       - 판정 기준: 유의수준 5% (P-value > 0.05 일 경우 '동등'으로 판정)
    ------------------------------------------------------------
    2. 데이터 분석 결과
       - A 시료 평균 : 6.461 mm
       - B 시료 평균 : 6.449 mm
       - 평균 차이   : 0.012 mm
       - ★ P-value   : 0.099
    ------------------------------------------------------------
    3. 최종 결론 및 해석
       ✅ 결과: 통계적으로 유의미한 차이가 없습니다. (동등함)
    
       [상세 해석]
       ① 산출된 P-value(0.099)가 판정 기준인 0.05보다 큽니다.
       ② 이는 두 집단 간의 평균 차이가 단순한 우연(Sampling Error)일
          가능성이 높다는 것을 의미합니다.
       ③ 따라서, A 시료는 양산 중인 B 시료의 관리 범위 내에 있으며,
          품질적으로 동등한 수준임을 통계적으로 증명합니다.
    ============================================================
    
    /tmp/ipython-input-164401017.py:70: MatplotlibDeprecationWarning: The 'labels' parameter of boxplot() has been renamed 'tick_labels' since Matplotlib 3.9; support for the old name will be dropped in 3.11.
      plt.boxplot([data_a, data_b], labels=[f'Sample A (N={len(data_a)})', f'Sample B (N={len(data_b)})'],
    

     

     

     

    반응형
Designed by Tistory.