콘텐츠로 이동

hossam.my_pipeline

hossam.my_pipeline

품질검사·EDA 반자동화 파이프라인 모듈

두 개의 파이프라인을 제공한다.

1) qtcheck_pipeline : 원본 데이터를 받아 자료형 점검 → (체크박스로) 명목형 변수 선택·변환 → (버튼으로) 중복 처리 결정 → 결측치 점검 → 기술통계 → 인사이트(결론)까지 대화형으로 수행하는 품질검사 파이프라인. 2) eda_pipeline : 품질검사가 끝난 데이터와 종속변수 이름을 받아 시각화· 추론통계·변수 선별표를 탭으로 종합하는 EDA 파이프라인.

원본 데이터프레임과 종속변수 이름만 전달하면, 필요한 기술통계량을 my_qtcheck 로 스스로 산출하고, my_stats 와 중복되지 않는 시각화를 일괄 수행한 뒤, 추론통계 검정을 단계적으로 실행하여 최종 '변수 선별표'까지 만들어내는 파이프라인을 제공한다.

산출물은 파이캐럿(PyCaret)처럼 처리 단계별 탭으로 구분되어 표시된다 (ipywidgets 미설치 시 순차 출력으로 자동 대체).

기술통계 → 종속변수 시각화 → 독립변수 시각화
         → 연속×연속 / 연속×명목(2) / 연속×명목(3↑) / 명목×명목
         → 변수 선별표

각 탭은 하나의 공개 함수로 분리되어 있어, 노트북에서 개별적으로 호출하여 독립적으로 결과를 확인할 수 있다. eda_pipeline 은 이 개별 함수들을 호출해 결과가 있는 경우에만 탭으로 종합한다.

show_descriptive   ── 기술통계
viz_dependent      ── 종속변수 시각화
viz_independent    ── 독립변수 시각화
infer_cont_cont    ── 연속 × 연속       (상관분석)
infer_cont_nom2    ── 연속 × 명목(2집단) (T검정)
infer_cont_nom3    ── 연속 × 명목(3집단↑)(분산분석)
infer_nom_nom      ── 명목 × 명목       (교차분석)
selection_table    ── 변수 선별표
eda_pipeline       ── 위 함수들을 탭으로 종합

검정 선택 규칙 (독립변수 유형 × 종속변수 유형)

┌───────────────┬───────────────────────┬────────────────────────┐
│               │ 연속형 종속변수(예측) │ 범주형 종속변수(분류)  │
├───────────────┼───────────────────────┼────────────────────────┤
│ 연속형 독립변수 │ 상관분석              │ 집단비교(T검정/ANOVA)  │
│ 명목형 독립변수 │ 집단비교(T검정/ANOVA) │ 교차분석(카이제곱)     │
└───────────────┴───────────────────────┴────────────────────────┘

show_descriptive

show_descriptive(
    data, target, task="regression", _as_widget=False
)

기술통계 탭: 페이지(기본정보 · 연속형 기술통계량 · 명목형 기술통계량)로 구분해 출력한다.

노트북에서 단독 호출 시 드롭다운으로 페이지를 넘길 수 있다. (다중공선성 VIF 는 '독립변수 상관분석' 탭으로 옮겨졌다.) _as_widget=True 면 표시 대신 위젯을 반환한다(파이프라인용).

Source code in hossam/my_pipeline.py
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
def show_descriptive(data, target, task="regression", _as_widget=False):
    """기술통계 탭: 페이지(기본정보 · 연속형 기술통계량 · 명목형 기술통계량)로 구분해 출력한다.

    노트북에서 단독 호출 시 드롭다운으로 페이지를 넘길 수 있다.
    (다중공선성 VIF 는 '독립변수 상관분석' 탭으로 옮겨졌다.)
    _as_widget=True 면 표시 대신 위젯을 반환한다(파이프라인용).
    """
    is_clf = _resolve_task(task)
    number_cols, category_cols, feat_cont, feat_nom = _classify(data, target)

    # ── 기본정보: 종속변수·모델링 유형·변수 분류 ──
    def basic():
        display(Markdown(f"**종속변수** : `{target}`  |  **모델링 유형** : "
                         f"{'분류(범주형)' if is_clf else '예측(연속형)'}"))
        display(Markdown(f"- 연속형 독립변수 : {feat_cont}"))
        display(Markdown(f"- 명목형 독립변수 : {feat_nom}"))

    # ── 연속형 기술통계량 ──
    def numeric():
        display(my_qtcheck.numerical_summary(data, columns=number_cols))

    # ── 명목형 기술통계량 ──
    def category():
        display(my_qtcheck.categorical_summary(data, columns=category_cols, value_counts=False))

    sections = [("기본정보", basic)]
    if number_cols:
        sections.append(("연속형 기술통계량", numeric))
    if category_cols:
        sections.append(("명목형 기술통계량", category))

    if _as_widget:
        return _pages_widget(sections)
    _pages_display(sections)

viz_dependent

viz_dependent(
    data,
    target,
    task="regression",
    palette=None,
    _as_widget=False,
)

종속변수 시각화 탭: 종속변수의 단변량 분포 + 기술통계량 표를 표시한다.

  • 연속형: 히스토그램 + 상자그림
  • 범주형: 빈도 막대그래프

_as_widget=True 면 표시 대신 위젯을 반환한다(파이프라인용).

Source code in hossam/my_pipeline.py
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
def viz_dependent(data, target, task="regression", palette=None, _as_widget=False):
    """종속변수 시각화 탭: 종속변수의 단변량 분포 + 기술통계량 표를 표시한다.

    - 연속형: 히스토그램 + 상자그림
    - 범주형: 빈도 막대그래프

    _as_widget=True 면 표시 대신 위젯을 반환한다(파이프라인용).
    """
    is_clf = _resolve_task(task)

    def render():
        display(Markdown(f"#### 종속변수 `{target}` 분포"))
        if is_clf:
            my_plot.countplot(data=data, x=target, palette=palette,
                              title=f"종속변수 {target} 분포", width=800, height=500)
        else:
            fig, ax = my_plot.init(rows=1, cols=2, title=f"종속변수 {target} 분포",
                                   width=800, height=500)
            my_plot.histplot(data=data, x=target, kde=True, ax=ax[0])
            my_plot.boxplot(data=data, x=target, ax=ax[1])
            my_plot.show()
        # 그래프 아래에 기술통계량 표 함께 표시
        _var_stats(data, target, continuous=not is_clf)

    if _as_widget:
        return _pages_widget([("종속변수 분포", render)])
    render()

viz_independent

viz_independent(
    data,
    target,
    task="regression",
    palette=None,
    _as_widget=False,
)

독립변수 시각화 탭: 독립변수별 페이지로 단변량 분포를 그린다.

  • 연속형: 히스토그램 + 상자그림
  • 명목형: 빈도 막대그래프

_as_widget=True 면 위젯(없으면 None)을 반환하고, 아니면 그 자리에서 표시하고 표시할 내용이 있었는지 여부(bool)를 반환한다.

Source code in hossam/my_pipeline.py
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
def viz_independent(data, target, task="regression", palette=None, _as_widget=False):
    """독립변수 시각화 탭: 독립변수별 페이지로 단변량 분포를 그린다.

    - 연속형: 히스토그램 + 상자그림
    - 명목형: 빈도 막대그래프

    _as_widget=True 면 위젯(없으면 None)을 반환하고, 아니면 그 자리에서 표시하고
    표시할 내용이 있었는지 여부(bool)를 반환한다.
    """
    _, _, feat_cont, feat_nom = _classify(data, target)

    # 독립변수별로 페이지 구성 (연속형: 히스토그램+상자그림 / 명목형: 빈도)
    # 각 그래프 아래에 해당 변수의 기술통계량 표를 함께 표시한다.
    def _cont(f):
        def render():
            fig, ax = my_plot.init(rows=1, cols=2, title=f"독립변수 {f} 분포",
                                   width=800, height=500)
            my_plot.histplot(data=data, x=f, kde=True, ax=ax[0])
            my_plot.boxplot(data=data, x=f, ax=ax[1])
            my_plot.show()
            _var_stats(data, f, continuous=True)
        return render

    def _nom(n):
        def render():
            my_plot.countplot(data=data, x=n, palette=palette,
                              title=f"독립변수 {n} 분포", width=800, height=500)
            _var_stats(data, n, continuous=False)
        return render

    sections = [(f, _cont(f)) for f in feat_cont] + [(n, _nom(n)) for n in feat_nom]

    if _as_widget:
        return _pages_widget(sections)
    _pages_display(sections)
    return bool(sections)

infer_cont_cont

infer_cont_cont(
    data,
    target,
    task="regression",
    alpha=0.05,
    corr_threshold=0.3,
    verbose=True,
    palette=None,
    _as_widget=False,
)

연속 × 연속 상관분석 탭 (변수 쌍별 페이지).

연속형 종속변수(예측)일 때만 수행되며, 각 연속형 독립변수와 종속변수의 상관분석을 실행한다. 대상이 없으면 빈 리스트를 반환한다.

Parameters:

Name Type Description Default
verbose bool

True 면 결과표·산점도를 표시, False 면 결과만 수집.

True
_as_widget bool

True 면 (rows, 위젯) 을 반환한다(파이프라인용).

False

Returns:

Type Description

list[dict]: 변수 선별표에 사용할 결과행 리스트

Source code in hossam/my_pipeline.py
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
def infer_cont_cont(data, target, task="regression", alpha=0.05,
                    corr_threshold=0.3, verbose=True, palette=None, _as_widget=False):
    """연속 × 연속 상관분석 탭 (변수 쌍별 페이지).

    연속형 종속변수(예측)일 때만 수행되며, 각 연속형 독립변수와 종속변수의
    상관분석을 실행한다. 대상이 없으면 빈 리스트를 반환한다.

    Args:
        verbose (bool): True 면 결과표·산점도를 표시, False 면 결과만 수집.
        _as_widget (bool): True 면 (rows, 위젯) 을 반환한다(파이프라인용).

    Returns:
        list[dict]: 변수 선별표에 사용할 결과행 리스트
    """
    if _resolve_task(task):
        return ([], None) if _as_widget else []   # 연속형 종속변수 아님 → 대상 없음
    _, _, feat_cont, _ = _classify(data, target)

    def work(f, plot):
        row, res = _run_correlation(data, f, target, alpha, corr_threshold,
                                    plot=plot, palette=palette)
        if plot and row is not None:
            display(res)
        return row

    items = [(f"{f}{target}", f) for f in feat_cont]
    return _emit_sections(items, work, verbose, as_widget=_as_widget)

infer_cont_nom2

infer_cont_nom2(
    data,
    target,
    task="regression",
    alpha=0.05,
    corr_threshold=0.3,
    verbose=True,
    palette=None,
    _as_widget=False,
)

연속 × 명목(2집단) 독립표본 T검정 탭 (변수 쌍별 페이지).

  • 예측: 2수준 명목형 독립변수 ↔ 연속형 종속변수
  • 분류: 연속형 독립변수 ↔ 2범주 종속변수

_as_widget=True 면 (rows, 위젯) 을 반환한다(파이프라인용).

Returns:

Type Description

list[dict]: 변수 선별표에 사용할 결과행 리스트 (대상 없으면 빈 리스트)

Source code in hossam/my_pipeline.py
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
def infer_cont_nom2(data, target, task="regression", alpha=0.05,
                    corr_threshold=0.3, verbose=True, palette=None, _as_widget=False):
    """연속 × 명목(2집단) 독립표본 T검정 탭 (변수 쌍별 페이지).

    - 예측: 2수준 명목형 독립변수 ↔ 연속형 종속변수
    - 분류: 연속형 독립변수 ↔ 2범주 종속변수

    _as_widget=True 면 (rows, 위젯) 을 반환한다(파이프라인용).

    Returns:
        list[dict]: 변수 선별표에 사용할 결과행 리스트 (대상 없으면 빈 리스트)
    """
    is_clf = _resolve_task(task)
    _, _, feat_cont, feat_nom = _classify(data, target)

    # (cat, cont, 표시명) 쌍 구성
    if is_clf:
        if _nlevels(data, target) != 2:
            return ([], None) if _as_widget else []
        pairs = [(target, f, f) for f in feat_cont]
    else:
        pairs = [(n, target, n) for n in feat_nom if _nlevels(data, n) == 2]

    def work(pair, plot):
        cat, cont, name = pair
        row, res = _run_ttest(data, cat, cont, name, alpha, corr_threshold,
                              plot=plot, palette=palette, title=f"{name}{target}")
        if plot and row is not None:
            display(res)
        return row

    items = [(f"{name}{target}", (cat, cont, name)) for cat, cont, name in pairs]
    return _emit_sections(items, work, verbose, as_widget=_as_widget)

infer_cont_nom3

infer_cont_nom3(
    data,
    target,
    task="regression",
    alpha=0.05,
    corr_threshold=0.3,
    verbose=True,
    palette=None,
    _as_widget=False,
)

연속 × 명목(3집단↑) 일원분산분석 + 사후검정 탭 (변수 쌍별 페이지).

  • 예측: 3수준 이상 명목형 독립변수 ↔ 연속형 종속변수
  • 분류: 연속형 독립변수 ↔ 3범주 이상 종속변수

_as_widget=True 면 (rows, 위젯) 을 반환한다(파이프라인용).

Returns:

Type Description

list[dict]: 변수 선별표에 사용할 결과행 리스트 (대상 없으면 빈 리스트)

Source code in hossam/my_pipeline.py
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
def infer_cont_nom3(data, target, task="regression", alpha=0.05,
                    corr_threshold=0.3, verbose=True, palette=None, _as_widget=False):
    """연속 × 명목(3집단↑) 일원분산분석 + 사후검정 탭 (변수 쌍별 페이지).

    - 예측: 3수준 이상 명목형 독립변수 ↔ 연속형 종속변수
    - 분류: 연속형 독립변수 ↔ 3범주 이상 종속변수

    _as_widget=True 면 (rows, 위젯) 을 반환한다(파이프라인용).

    Returns:
        list[dict]: 변수 선별표에 사용할 결과행 리스트 (대상 없으면 빈 리스트)
    """
    is_clf = _resolve_task(task)
    _, _, feat_cont, feat_nom = _classify(data, target)

    if is_clf:
        if _nlevels(data, target) < 3:
            return ([], None) if _as_widget else []
        pairs = [(target, f, f) for f in feat_cont]
    else:
        pairs = [(n, target, n) for n in feat_nom if _nlevels(data, n) >= 3]

    def work(pair, plot):
        cat, cont, name = pair
        row, aov = _run_anova(data, cat, cont, name, alpha, corr_threshold)
        if plot and row is not None:
            display(aov)
            # 사후검정(그룹 쌍별 비교)을 시각화와 함께 표시
            ph = my_stats.posthoc_oneway(data, y=cont, between=cat, alpha=alpha,
                                         plot=True, palette=palette,
                                         title=f"{name} 사후검정")
            display(ph)
        return row

    items = [(f"{name}{target}", (cat, cont, name)) for cat, cont, name in pairs]
    return _emit_sections(items, work, verbose, as_widget=_as_widget)

infer_nom_nom

infer_nom_nom(
    data,
    target,
    task="regression",
    alpha=0.05,
    corr_threshold=0.3,
    verbose=True,
    palette=None,
    _as_widget=False,
)

명목 × 명목 교차분석(카이제곱/피셔) 탭 (변수 쌍별 페이지).

범주형 종속변수(분류)일 때만 수행되며, 각 명목형 독립변수와 종속변수의 독립성 검정을 실행한다. 대상이 없으면 빈 리스트를 반환한다.

_as_widget=True 면 (rows, 위젯) 을 반환한다(파이프라인용).

Returns:

Type Description

list[dict]: 변수 선별표에 사용할 결과행 리스트

Source code in hossam/my_pipeline.py
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
def infer_nom_nom(data, target, task="regression", alpha=0.05,
                  corr_threshold=0.3, verbose=True, palette=None, _as_widget=False):
    """명목 × 명목 교차분석(카이제곱/피셔) 탭 (변수 쌍별 페이지).

    범주형 종속변수(분류)일 때만 수행되며, 각 명목형 독립변수와 종속변수의
    독립성 검정을 실행한다. 대상이 없으면 빈 리스트를 반환한다.

    _as_widget=True 면 (rows, 위젯) 을 반환한다(파이프라인용).

    Returns:
        list[dict]: 변수 선별표에 사용할 결과행 리스트
    """
    if not _resolve_task(task):
        return ([], None) if _as_widget else []   # 범주형 종속변수 아님 → 대상 없음
    _, _, _, feat_nom = _classify(data, target)

    def work(n, plot):
        row, res = _run_chi2(data, n, target, alpha, corr_threshold,
                             plot=plot, palette=palette)
        if plot and row is not None:
            display(res)
        return row

    items = [(f"{n}{target}", n) for n in feat_nom]
    return _emit_sections(items, work, verbose, as_widget=_as_widget)

corr_independent

corr_independent(
    data,
    target,
    alpha=0.05,
    collinearity_threshold=0.7,
    palette=None,
    _as_widget=False,
)

독립변수 간 상관분석 탭.

연속형 독립변수들 사이의 상관행렬과 강한 상관 쌍(공선성 후보)을 산출한다. 이는 변수 선별표의 공선성 신호(🅾️/❎)의 근거가 된다. 연속형 독립변수가 2개 미만이면 대상이 없으므로 위젯 모드에서는 None 을 반환한다.

_as_widget=True 면 위젯(없으면 None)을 반환하고, 아니면 그 자리에서 표시한다.

Source code in hossam/my_pipeline.py
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
def corr_independent(data, target, alpha=0.05, collinearity_threshold=0.7,
                     palette=None, _as_widget=False):
    """독립변수 간 상관분석 탭.

    연속형 독립변수들 사이의 상관행렬과 강한 상관 쌍(공선성 후보)을 산출한다.
    이는 변수 선별표의 공선성 신호(🅾️/❎)의 근거가 된다. 연속형 독립변수가
    2개 미만이면 대상이 없으므로 위젯 모드에서는 None 을 반환한다.

    _as_widget=True 면 위젯(없으면 None)을 반환하고, 아니면 그 자리에서 표시한다.
    """
    _, _, feat_cont, _ = _classify(data, target)
    if len(feat_cont) < 2:
        return None if _as_widget else None

    # ── 상관행렬 · 강한 상관 쌍 ──
    def corr_page():
        display(Markdown("#### 연속형 독립변수 간 상관행렬"))
        _blank()
        display(Markdown("색이 진할수록 강한 상관 → 서로 중복(공선성) 후보"))
        _blank()
        # multi_correlation: 스타일된 상관행렬을 표시하고 쌍별 결과표를 반환
        corr_df = my_stats.multi_correlation(data, columns=feat_cont,
                                             plot=False, palette=palette)
        _blank()
        # 강한 상관 쌍(공선성 신호로 이어지는 쌍)을 강조해 표시
        display(Markdown(f"**강한 상관 쌍 (|coef|≥{collinearity_threshold} → 공선성 🅾️)**"))
        _blank()
        strong = corr_df[corr_df["coef"].abs() >= collinearity_threshold]
        if len(strong):
            display(strong.sort_values("coef", key=abs, ascending=False))
        else:
            display(Markdown("> 강한 상관 쌍 없음 (모든 독립변수 공선성 ❎)"))

    # ── 다중공선성(VIF): 기술통계 탭에서 이동해 옴 (독립변수 간 관계로 묶음) ──
    def vif_page():
        display(Markdown("#### 다중공선성(VIF)"))
        _blank()
        vif = _compute_vif(data, feat_cont)
        if vif is not None:
            display(vif)
        else:
            display(Markdown("> VIF 를 계산할 수 없습니다."))

    sections = [("독립변수 상관", corr_page), ("다중공선성(VIF)", vif_page)]
    if _as_widget:
        return _pages_widget(sections)
    _pages_display(sections)

selection_table

selection_table(
    data,
    target,
    task="regression",
    alpha=0.05,
    corr_threshold=0.3,
    collinearity_threshold=0.7,
    palette=None,
)

변수 선별표 탭: 4종 추론통계를 조용히 수행하여 최종 선별표를 출력한다.

노트북에서 단독 호출하면 개별 검정 과정 출력 없이 선별표만 확인할 수 있다. 공선성 신호는 연속형 독립변수 간 상관분석 결과로만 산출한다(VIF 미적용).

Source code in hossam/my_pipeline.py
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
def selection_table(data, target, task="regression", alpha=0.05,
                    corr_threshold=0.3, collinearity_threshold=0.7, palette=None):
    """변수 선별표 탭: 4종 추론통계를 조용히 수행하여 최종 선별표를 출력한다.

    노트북에서 단독 호출하면 개별 검정 과정 출력 없이 선별표만 확인할 수 있다.
    공선성 신호는 연속형 독립변수 간 상관분석 결과로만 산출한다(VIF 미적용).
    """
    number_cols, _, feat_cont, _ = _classify(data, target)
    desc = my_qtcheck.numerical_summary(data, columns=number_cols) if number_cols else None
    collin = _collinearity_map(data, feat_cont, alpha, collinearity_threshold)

    rows = []
    for fn in (infer_cont_cont, infer_cont_nom2, infer_cont_nom3, infer_nom_nom):
        rows.extend(fn(data, target, task=task, alpha=alpha,
                       corr_threshold=corr_threshold, verbose=False, palette=palette))

    table = _build_selection_frame(rows, desc, collin)
    _display_selection(table, alpha, corr_threshold, collinearity_threshold)

eda_pipeline

eda_pipeline(
    data,
    target,
    task="regression",
    alpha=0.05,
    corr_threshold=0.3,
    collinearity_threshold=0.7,
    palette=None,
)

추론통계 기반 EDA 를 단계별 탭으로 종합 실행하는 파이프라인.

원본 데이터프레임과 종속변수 이름만 전달하면, 기술통계량은 my_qtcheck 로 스스로 산출하고, 개별 탭 함수를 차례로 호출하여 결과가 있는 탭만 모아 파이캐럿처럼 탭으로 표시한다. 별도의 반환값은 없다.

구성 탭

기술통계 · 종속변수 시각화 · 독립변수 시각화 · (연속×연속 / 연속×명목(2) / 연속×명목(3↑) / 명목×명목 중 수행된 것만) · 변수 선별표

Parameters:

Name Type Description Default
data DataFrame

품질점검·타입변환이 완료된 원본 데이터프레임 (명목형은 category 타입으로 지정되어 있어야 자동 분류된다.)

required
target str

종속변수(목표변수) 컬럼명

required
task str

모델링 유형. 'regression'/'예측'/'연속형'(기본) 또는 'classification'/'분류'/'범주형'

'regression'
alpha float

유의수준 (기본값: 0.05)

0.05
corr_threshold float

상관계수 채택 기준 |coef| (기본값: 0.3)

0.3
collinearity_threshold float

공선성 신호 기준 |r| (연속형 독립변수 간 상관분석 기반, 기본값: 0.7). 이 단계에서 VIF는 사용하지 않는다.

0.7
palette str or list

시각화 색상 팔레트 (기본값: None)

None
Source code in hossam/my_pipeline.py
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
def eda_pipeline(data, target, task="regression", alpha=0.05,
                 corr_threshold=0.3, collinearity_threshold=0.7, palette=None):
    """추론통계 기반 EDA 를 단계별 탭으로 종합 실행하는 파이프라인.

    원본 데이터프레임과 종속변수 이름만 전달하면, 기술통계량은 my_qtcheck 로
    스스로 산출하고, 개별 탭 함수를 차례로 호출하여 결과가 있는 탭만 모아
    파이캐럿처럼 탭으로 표시한다. 별도의 반환값은 없다.

    구성 탭:
        기술통계 · 종속변수 시각화 · 독립변수 시각화 ·
        (연속×연속 / 연속×명목(2) / 연속×명목(3↑) / 명목×명목 중 수행된 것만) ·
        변수 선별표

    Args:
        data (DataFrame): 품질점검·타입변환이 완료된 원본 데이터프레임
            (명목형은 category 타입으로 지정되어 있어야 자동 분류된다.)
        target (str): 종속변수(목표변수) 컬럼명
        task (str): 모델링 유형. 'regression'/'예측'/'연속형'(기본) 또는
            'classification'/'분류'/'범주형'
        alpha (float): 유의수준 (기본값: 0.05)
        corr_threshold (float): 상관계수 채택 기준 |coef| (기본값: 0.3)
        collinearity_threshold (float): 공선성 신호 기준 |r| (연속형 독립변수 간
            상관분석 기반, 기본값: 0.7). 이 단계에서 VIF는 사용하지 않는다.
        palette (str or list): 시각화 색상 팔레트 (기본값: None)
    """
    # 변수 선별표에 필요한 기술통계량/공선성 신호는 한 번만 계산해 재사용
    # (공선성 신호는 VIF가 아니라 연속형 독립변수 간 상관분석 결과로만 산출)
    is_clf = _resolve_task(task)
    _, _, feat_cont, _ = _classify(data, target)
    number_cols = my_qtcheck.get_number_column_names(data)
    desc = my_qtcheck.numerical_summary(data, columns=number_cols) if number_cols else None
    collin = _collinearity_map(data, feat_cont, alpha, collinearity_threshold)

    # -----------------------------------------------------------------
    # 폴백: ipywidgets 가 없으면 탭 없이 순차 출력
    # -----------------------------------------------------------------
    if not _HAS_WIDGETS:
        display(Markdown("## 기술통계"))
        show_descriptive(data, target, task)
        display(Markdown("## 종속변수 시각화"))
        viz_dependent(data, target, task, palette=palette)
        display(Markdown("## 독립변수 시각화"))
        viz_independent(data, target, task, palette=palette)

        all_rows = []
        for fn, reg_title, clf_title in _INFER_DEFS:
            rows = fn(data, target, task=task, alpha=alpha,
                      corr_threshold=corr_threshold, verbose=True, palette=palette)
            if rows:
                display(Markdown(f"## {clf_title if is_clf else reg_title}"))
                all_rows.extend(rows)

        if len(feat_cont) >= 2:
            display(Markdown("## 독립변수 상관분석"))
            corr_independent(data, target, alpha=alpha,
                             collinearity_threshold=collinearity_threshold, palette=palette)

        display(Markdown("## 변수 선별표"))
        table = _build_selection_frame(all_rows, desc, collin)
        _display_selection(table, alpha, corr_threshold, collinearity_threshold)
        return

    # -----------------------------------------------------------------
    # 위젯 모드: 각 탭 위젯을 '직접' 구성해 상위 Tab 의 자식으로 넣는다.
    # (Output 안에서 컨테이너 위젯을 display 하는 중첩을 피해야 정상 렌더링됨)
    # -----------------------------------------------------------------
    tab_items = []   # (제목, 위젯)

    # 기술통계 · 종속변수 시각화 (항상 표시)
    tab_items.append(("기술통계", show_descriptive(data, target, task, _as_widget=True)))
    tab_items.append(("종속변수 시각화",
                      viz_dependent(data, target, task, palette=palette, _as_widget=True)))

    # 독립변수 시각화 (독립변수가 있을 때만)
    w = viz_independent(data, target, task, palette=palette, _as_widget=True)
    if w is not None:
        tab_items.append(("독립변수 시각화", w))

    # 추론통계 4종 (수행되어 결과가 있는 것만)
    all_rows = []
    for fn, reg_title, clf_title in _INFER_DEFS:
        rows, w = fn(data, target, task=task, alpha=alpha, corr_threshold=corr_threshold,
                     verbose=True, palette=palette, _as_widget=True)
        if rows:
            all_rows.extend(rows)
            tab_items.append((clf_title if is_clf else reg_title, w))

    # 독립변수 간 상관분석 (연속형 독립변수 2개 이상일 때만) — 공선성 신호의 근거
    w = corr_independent(data, target, alpha=alpha,
                         collinearity_threshold=collinearity_threshold,
                         palette=palette, _as_widget=True)
    if w is not None:
        tab_items.append(("독립변수 상관분석", w))

    # 변수 선별표 (항상 표시) — 정적 HTML 위젯으로 담는다(이중출력 방지)
    table = _build_selection_frame(all_rows, desc, collin)
    sel_widget = _capture_to_html(
        lambda: _display_selection(table, alpha, corr_threshold, collinearity_threshold))
    tab_items.append(("변수 선별표", sel_widget))

    # 상위 Tab 구성 후 한 번만 표시
    tab = _Tab(children=[w for _, w in tab_items])
    for i, (t, _) in enumerate(tab_items):
        tab.set_title(i, t)
    display(tab)

qtcheck_pipeline

qtcheck_pipeline(
    data,
    save_path=None,
    numeric_save_path=None,
    category_save_path=None,
)

데이터 품질검사를 대화형으로 수행하는 파이프라인.

자료형 점검 → (체크박스) 명목형 변수 선택·변환 → (버튼) 중복 처리 결정 → 결측치 점검 → 기술통계 → 인사이트(결론) 순으로 진행한다. 사용자의 의사결정이 필요한 단계(명목형 선택·중복 처리)는 위젯으로 물어보고, 나머지는 자동 진행하며, 결측치·기술통계·인사이트는 탭(마지막이 인사이트 결론)으로 종합한다. 별도의 반환값은 없다.

Parameters:

Name Type Description Default
data DataFrame

품질검사 대상 원본 데이터프레임

required
save_path str

품질검사 완료 데이터프레임을 저장할 파일 경로 (지원: .xlsx/.xls, .csv[utf-8], .parquet / 기본값: None → 저장 안 함)

None
numeric_save_path str

연속형 기술통계량 표를 저장할 파일 경로

None
category_save_path str

명목형 기술통계량 표를 저장할 파일 경로

None
Note

ipywidgets 가 없으면 기본값(비수치형→범주형 변환, 중복 제거)으로 비대화형 수행한다.

Source code in hossam/my_pipeline.py
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
def qtcheck_pipeline(data, save_path=None,
                     numeric_save_path=None, category_save_path=None):
    """데이터 품질검사를 대화형으로 수행하는 파이프라인.

    자료형 점검 → (체크박스) 명목형 변수 선택·변환 → (버튼) 중복 처리 결정 →
    결측치 점검 → 기술통계 → 인사이트(결론) 순으로 진행한다. 사용자의
    의사결정이 필요한 단계(명목형 선택·중복 처리)는 위젯으로 물어보고,
    나머지는 자동 진행하며, 결측치·기술통계·인사이트는 탭(마지막이 인사이트
    결론)으로 종합한다. 별도의 반환값은 없다.

    Args:
        data (DataFrame): 품질검사 대상 원본 데이터프레임
        save_path (str): 품질검사 완료 데이터프레임을 저장할 파일 경로
            (지원: .xlsx/.xls, .csv[utf-8], .parquet / 기본값: None → 저장 안 함)
        numeric_save_path (str): 연속형 기술통계량 표를 저장할 파일 경로
        category_save_path (str): 명목형 기술통계량 표를 저장할 파일 경로

    Note:
        ipywidgets 가 없으면 기본값(비수치형→범주형 변환, 중복 제거)으로
        비대화형 수행한다.
    """
    # 폴백: 비대화형 (기본값 사용)
    if not _HAS_WIDGETS:
        _qtcheck_noninteractive(data, save_path=save_path,
                                numeric_save_path=numeric_save_path,
                                category_save_path=category_save_path)
        return

    state = {"df": data.copy(), "dup_count": 0, "dup_removed": False}
    root = _VBox([])

    def append(*widgets):
        root.children = root.children + tuple(widgets)

    # ── ① 자료형 확인 ──
    o1 = _Output()
    with o1:
        display(Markdown("## ① 자료형 확인"))
        data.info()
    append(o1)

    # ── ② 명목형(범주형) 변수 선택 (체크박스) ──
    o2 = _Output()
    with o2:
        display(Markdown("## ② 명목형(범주형) 변수 선택"))
        display(Markdown("`category` 타입으로 변환할 컬럼을 체크하세요. "
                         "(비수치형 컬럼은 기본 선택됨)"))
    default_nom = set(_nonnumeric_columns(data))
    checks = [_Checkbox(value=(c in default_nom), description=c, indent=False)
              for c in data.columns]
    convert_btn = _Button(description="자료형 변환 ▶", button_style="primary")
    step2_out = _Output()
    append(_step_divider_widget(), o2, _VBox(checks), convert_btn, step2_out)

    # ── ③ 중복 점검 (버튼) ──
    def step3_duplicates():
        o3 = _Output()
        dup_count = int(state["df"].duplicated().sum())
        state["dup_count"] = dup_count
        with o3:
            display(Markdown("## ③ 데이터 중복 점검"))
            display(Markdown(f"중복 행: **{dup_count}건**"))
        append(_step_divider_widget(), o3)

        if dup_count > 0:
            with o3:
                display(Markdown("중복을 어떻게 처리할까요?"))
            drop_btn = _Button(description="🗑 중복 제거", button_style="warning")
            keep_btn = _Button(description="유지")
            dup_out = _Output()
            append(_HBox([drop_btn, keep_btn]), dup_out)

            def finish(removed):
                drop_btn.disabled = keep_btn.disabled = True
                state["dup_removed"] = removed
                with dup_out:
                    if removed:
                        state["df"] = my_qtcheck.check_duplicates(state["df"], drop=True)
                    else:
                        display(Markdown("중복을 **유지**합니다."))
                step_final()

            drop_btn.on_click(lambda _: finish(True))
            keep_btn.on_click(lambda _: finish(False))
        else:
            state["dup_removed"] = False
            step_final()

    # ── ④ 결측치·기술통계·인사이트(결론)를 탭으로 종합 ──
    def step_final():
        _save_df(state["df"], save_path, index=False)   # 품질검사 데이터 저장
        head = _Output()
        with head:
            display(Markdown("## ④ 품질검사 결과"))
            if save_path:
                display(Markdown(f"- 품질검사 데이터 저장: `{save_path}`"))
        # Tab 위젯을 Output 에 담지 않고 root 의 자식으로 '직접' 넣어야 렌더링됨
        tab = _qtcheck_result_tabs(state["df"], state["dup_count"], state["dup_removed"],
                                   numeric_save_path=numeric_save_path,
                                   category_save_path=category_save_path)
        append(_step_divider_widget(), head, tab)

    def on_convert(_):
        convert_btn.disabled = True
        for cb in checks:
            cb.disabled = True
        selected = [cb.description for cb in checks if cb.value]
        with step2_out:
            display(Markdown(f"**선택된 명목형 변수:** {selected}"))
            state["df"] = my_qtcheck.set_type(data, as_category=selected)
        step3_duplicates()

    convert_btn.on_click(on_convert)

    display(root)