특성 공학과 선택(Feature Engineering & Selection)

좋은 특성 하나는 데이터 포인트(data point) 천 개의 가치가 있습니다.

유형: Build 언어: Python 선수 지식: Phase 1 (머신러닝(Machine Learning)을 위한 통계, 선형대수), Phase 2 Lessons 1-7 예상 시간: 약 90분

학습 목표

  • 표준화(Standardization), 최소-최대 스케일링(min-max scaling), 로그 변환(Log transform), 구간화(binning) 같은 수치형 변환을 구현하고 각 변환이 언제 적절한지 설명합니다.
  • 범주형 특성(Categorical feature)을 위한 원-핫 인코딩(one-hot encoding), 라벨 인코딩(label encoding), 타깃 인코딩(target encoding)을 만들고 타깃 인코딩의 데이터 누수(Data leakage) 위험을 식별합니다.
  • TF-IDF 벡터화기(vectorizer)를 처음부터 만들고, 텍스트 분류에서 원시 단어 빈도(raw word count)보다 더 나은 이유를 설명합니다.
  • 분산 기준(Variance threshold), 상관관계(Correlation), 상호정보량(Mutual information) 같은 필터(filter) 기반 특성 선택(Feature selection)을 적용해 차원을 줄입니다.

문제

데이터셋이 있습니다. 알고리즘을 골라 학습했지만 결과가 평범합니다. 더 복잡한 알고리즘을 써도 여전히 평범합니다. 일주일 동안 하이퍼파라미터를 튜닝해도 개선은 작습니다.

그런데 누군가 원시 데이터(raw data)를 더 나은 특성으로 바꾸자, 단순한 로지스틱 회귀(Logistic regression)가 정성껏 튜닝한 그래디언트 부스팅 앙상블(gradient-boosted ensemble)보다 더 좋은 결과를 냅니다.

이 일은 자주 일어납니다. 전통적인 머신러닝(Classical ML)에서는 데이터의 표현 방식이 알고리즘 선택보다 더 중요할 때가 많습니다. 집값 모델에서 square footage(전용 면적)와 number of bedrooms(침실 수)를 쓰는 모델은 address(주소)를 원시 문자열(raw string)로 넣은 모델보다 거의 항상 더 낫습니다. 아무리 정교한 학습기(learner)라도, 모델은 주어진 표현 안에서만 학습할 수 있습니다.

특성 공학(Feature engineering)은 원시 데이터를 모델이 패턴(pattern)을 더 쉽게 찾을 수 있는 표현으로 바꾸는 과정입니다. 특성 선택(Feature selection)은 신호(signal)를 더하지 않고 잡음(noise)만 더하는 특성을 버리는 과정입니다. 둘은 전통적 머신러닝에서 가장 영향력(leverage)이 큰 활동입니다.

사전 테스트

2문제 · 이 강의를 시작하기 전에 얼마나 알고 있는지 확인해보세요

1.피처 엔지니어링(Feature engineering)이 더 복잡한 알고리즘을 고르는 것보다 더 큰 영향을 주는 경우가 많은 이유는 무엇인가요?

2.원-핫 인코딩(One-hot encoding)은 무엇인가요?

0/2 답변 완료

개념

특성 파이프라인(Feature Pipeline)

flowchart LR
    A[원시 데이터] --> B[결측값 처리]
    B --> C[수치형 변환]
    B --> D[범주형 인코딩]
    B --> E[텍스트 특성]
    C --> F[특성 상호작용]
    D --> F
    E --> F
    F --> G[특성 선택]
    G --> H[모델 입력 데이터]

수치형 특성

원시 수치(raw number)는 그대로 모델에 넣기 어려운 경우가 많습니다. 자주 쓰는 변환은 다음과 같습니다.

스케일링(Scaling): 특성을 같은 범위에 둡니다. K-Means, KNN, SVM 같은 거리 기반 알고리즘이 모든 특성을 공정하게 보도록 하기 위해 필요합니다. 최소-최대 스케일링은 값을 [0, 1]로 매핑합니다. 표준화, 즉 z-점수(z-score)는 평균 0, 표준편차 1로 매핑합니다.

로그 변환(Log transform): 오른쪽으로 긴 분포, 예를 들어 소득, 인구, 단어 빈도(word count)를 압축합니다. 곱셈 관계를 덧셈 관계처럼 다루기 쉽게 만들 수 있습니다.

구간화(Binning): 연속값을 범주(category)로 바꿉니다. 특성과 타깃(target)의 관계가 비선형이지만 계단식일 때 유용합니다. 예를 들어 나이대를 만들 수 있습니다.

다항 특성(Polynomial features): x^2, x^3, x1*x2 같은 항을 만듭니다. 특성 수가 늘어나는 대가로 선형 모델이 비선형 관계를 포착하게 합니다.

범주형 특성

모델은 숫자를 필요로 합니다. 범주는 인코딩(encoding)이 필요합니다.

원-핫 인코딩(One-hot encoding): 각 범주마다 이진 열(column)을 만듭니다. color = red/blue/greenis_red, is_blue, is_green 세 열이 됩니다. 카디널리티(cardinality)가 낮은 특성에는 잘 동작하지만 범주가 많으면 열이 폭발합니다.

라벨 인코딩(Label encoding): 각 범주를 정수로 매핑합니다. 예를 들어 red=0, blue=1, green=2입니다. 하지만 거짓 순서를 만들 수 있습니다. 모델이 green > blue > red라고 오해할 수 있습니다. 개별 값을 기준으로 분할(split)하는 트리(tree) 기반 모델에만 주로 적절합니다.

타깃 인코딩(Target encoding): 각 범주를 해당 범주의 타깃 평균으로 바꿉니다. 강력하지만 위험합니다. 데이터 누수 위험이 큽니다. 반드시 학습 데이터에서만 계산하고 테스트 데이터에는 학습 데이터에서 얻은 인코딩을 적용해야 합니다.

텍스트 특성

카운트 벡터라이저(Count vectorizer): 문서에 각 단어가 몇 번 등장했는지 셉니다. "the cat sat on the mat"{the: 2, cat: 1, sat: 1, on: 1, mat: 1}처럼 표현됩니다.

TF-IDF: 단어 빈도-역문서 빈도(Term Frequency-Inverse Document Frequency)입니다. 전체 문서에서 얼마나 구별력 있는 단어인지에 따라 단어에 가중치를 줍니다. "the"처럼 흔한 단어는 낮은 가중치를 받고, 드물고 특징적인 단어는 높은 가중치를 받습니다.

TF(word, doc) = count(word in doc) / total words in doc
IDF(word) = log(total docs / docs containing word)
TF-IDF = TF * IDF

결측값(Missing Values)

현실 데이터에는 빈칸이 있습니다. 전략은 다음과 같습니다.

  • 행 삭제(Drop rows): 결측 데이터가 드물고 무작위일 때만 사용합니다.
  • 평균/중앙값 대체(Mean/median imputation): 단순하며 분포 형태를 어느 정도 보존합니다. 중앙값은 이상치에 더 강합니다.
  • 최빈값 대체(Mode imputation): 범주형 특성에 사용합니다.
  • 지시 열(Indicator column): 대체 전에 was_this_missing 같은 이진 열을 추가합니다. 값이 결측이라는 사실 자체가 신호일 수 있습니다.
  • 앞/뒤 채우기(Forward/backward fill): 시계열 데이터에서 사용합니다.

특성 상호작용

때로는 관계가 조합 안에 있습니다. heightweight 각각보다 BMI = weight / height^2가 더 예측적일 수 있습니다. 특성 상호작용은 특성 공간을 빠르게 키우므로 도메인 지식(domain knowledge)으로 필요한 조합을 골라야 합니다.

특성 선택

특성이 많다고 항상 좋은 것은 아닙니다. 관련 없는 특성은 잡음을 더하고 학습 시간을 늘리며 과적합을 유발할 수 있습니다.

필터 방식(Filter methods, 모델 적용 이전):

  • 상관관계(Correlation): 서로 매우 상관된 중복 특성(redundant feature)을 제거합니다.
  • 상호정보량(Mutual information): 어떤 특성을 알면 타깃에 대한 불확실성이 얼마나 줄어드는지 측정합니다.
  • 분산 기준(Variance threshold): 거의 변하지 않는 특성을 제거합니다.

래퍼 방식(Wrapper methods, 모델 기반):

  • L1 정규화(L1 regularization; Lasso): 관련 없는 특성의 가중치(weight)를 정확히 0으로 밀어냅니다.
  • 재귀적 특성 제거(Recursive feature elimination): 학습하고, 가장 덜 중요한 특성을 제거하고, 반복합니다.

왜 중요한가: 좋은 특성 10개로 만든 모델은 좋은 특성 10개와 잡음 특성 90개로 만든 모델보다 보통 더 좋습니다. 잡음 특성은 학습 데이터에만 있는 패턴에 과적합할 기회를 줍니다.

만들어 보기

Step 1: 수치형 변환 처음부터 구현하기

import math


def min_max_scale(values):
    min_val = min(values)
    max_val = max(values)
    if max_val == min_val:
        return [0.0] * len(values)
    return [(v - min_val) / (max_val - min_val) for v in values]


def standardize(values):
    n = len(values)
    mean = sum(values) / n
    variance = sum((v - mean) ** 2 for v in values) / n
    std = math.sqrt(variance) if variance > 0 else 1.0
    return [(v - mean) / std for v in values]


def log_transform(values):
    return [math.log(v + 1) for v in values]


def bin_values(values, n_bins=5):
    min_val = min(values)
    max_val = max(values)
    bin_width = (max_val - min_val) / n_bins
    if bin_width == 0:
        return [0] * len(values)
    result = []
    for v in values:
        bin_idx = int((v - min_val) / bin_width)
        bin_idx = min(bin_idx, n_bins - 1)
        result.append(bin_idx)
    return result


def polynomial_features(row, degree=2):
    n = len(row)
    result = list(row)
    if degree >= 2:
        for i in range(n):
            result.append(row[i] ** 2)
        for i in range(n):
            for j in range(i + 1, n):
                result.append(row[i] * row[j])
    return result

Step 2: 범주형 인코딩 처음부터 구현하기

def one_hot_encode(values):
    categories = sorted(set(values))
    cat_to_idx = {cat: i for i, cat in enumerate(categories)}
    n_cats = len(categories)

    encoded = []
    for v in values:
        row = [0] * n_cats
        row[cat_to_idx[v]] = 1
        encoded.append(row)

    return encoded, categories


def label_encode(values):
    categories = sorted(set(values))
    cat_to_int = {cat: i for i, cat in enumerate(categories)}
    return [cat_to_int[v] for v in values], cat_to_int


def target_encode(feature_values, target_values, smoothing=10):
    global_mean = sum(target_values) / len(target_values)

    category_stats = {}
    for feat, target in zip(feature_values, target_values):
        if feat not in category_stats:
            category_stats[feat] = {"sum": 0.0, "count": 0}
        category_stats[feat]["sum"] += target
        category_stats[feat]["count"] += 1

    encoding = {}
    for cat, stats in category_stats.items():
        cat_mean = stats["sum"] / stats["count"]
        weight = stats["count"] / (stats["count"] + smoothing)
        encoding[cat] = weight * cat_mean + (1 - weight) * global_mean

    return [encoding[v] for v in feature_values], encoding

Step 3: 텍스트 특성 처음부터 구현하기

def count_vectorize(documents):
    vocab = {}
    idx = 0
    for doc in documents:
        for word in doc.lower().split():
            if word not in vocab:
                vocab[word] = idx
                idx += 1

    vectors = []
    for doc in documents:
        vec = [0] * len(vocab)
        for word in doc.lower().split():
            vec[vocab[word]] += 1
        vectors.append(vec)

    return vectors, vocab


def tfidf(documents):
    n_docs = len(documents)

    vocab = {}
    idx = 0
    for doc in documents:
        for word in doc.lower().split():
            if word not in vocab:
                vocab[word] = idx
                idx += 1

    doc_freq = {}
    for doc in documents:
        seen = set()
        for word in doc.lower().split():
            if word not in seen:
                doc_freq[word] = doc_freq.get(word, 0) + 1
                seen.add(word)

    vectors = []
    for doc in documents:
        words = doc.lower().split()
        word_count = len(words)
        tf_map = {}
        for word in words:
            tf_map[word] = tf_map.get(word, 0) + 1

        vec = [0.0] * len(vocab)
        for word, count in tf_map.items():
            tf = count / word_count
            idf = math.log(n_docs / doc_freq[word])
            vec[vocab[word]] = tf * idf
        vectors.append(vec)

    return vectors, vocab

Step 4: 결측값 대치 처음부터 구현하기

def impute_mean(values):
    present = [v for v in values if v is not None]
    if not present:
        return [0.0] * len(values), 0.0
    mean = sum(present) / len(present)
    return [v if v is not None else mean for v in values], mean


def impute_median(values):
    present = sorted(v for v in values if v is not None)
    if not present:
        return [0.0] * len(values), 0.0
    n = len(present)
    if n % 2 == 0:
        median = (present[n // 2 - 1] + present[n // 2]) / 2
    else:
        median = present[n // 2]
    return [v if v is not None else median for v in values], median


def impute_mode(values):
    present = [v for v in values if v is not None]
    if not present:
        return values, None
    counts = {}
    for v in present:
        counts[v] = counts.get(v, 0) + 1
    mode = max(counts, key=counts.get)
    return [v if v is not None else mode for v in values], mode


def add_missing_indicator(values):
    return [0 if v is not None else 1 for v in values]

Step 5: 특성 선택 처음부터 구현하기

def correlation(x, y):
    n = len(x)
    mean_x = sum(x) / n
    mean_y = sum(y) / n
    cov = sum((xi - mean_x) * (yi - mean_y) for xi, yi in zip(x, y)) / n
    std_x = math.sqrt(sum((xi - mean_x) ** 2 for xi in x) / n)
    std_y = math.sqrt(sum((yi - mean_y) ** 2 for yi in y) / n)
    if std_x == 0 or std_y == 0:
        return 0.0
    return cov / (std_x * std_y)


def mutual_information(feature, target, n_bins=10):
    feat_min = min(feature)
    feat_max = max(feature)
    bin_width = (feat_max - feat_min) / n_bins if feat_max != feat_min else 1.0
    feat_binned = [
        min(int((f - feat_min) / bin_width), n_bins - 1) for f in feature
    ]

    n = len(feature)
    target_classes = sorted(set(target))

    feat_bins = sorted(set(feat_binned))
    p_feat = {}
    for b in feat_bins:
        p_feat[b] = feat_binned.count(b) / n

    p_target = {}
    for t in target_classes:
        p_target[t] = target.count(t) / n

    mi = 0.0
    for b in feat_bins:
        for t in target_classes:
            joint_count = sum(
                1 for fb, tv in zip(feat_binned, target) if fb == b and tv == t
            )
            p_joint = joint_count / n
            if p_joint > 0:
                mi += p_joint * math.log(p_joint / (p_feat[b] * p_target[t]))

    return mi


def variance_threshold(features, threshold=0.01):
    n_features = len(features[0])
    n_samples = len(features)
    selected = []

    for j in range(n_features):
        col = [features[i][j] for i in range(n_samples)]
        mean = sum(col) / n_samples
        var = sum((v - mean) ** 2 for v in col) / n_samples
        if var >= threshold:
            selected.append(j)

    return selected


def remove_correlated(features, threshold=0.9):
    n_features = len(features[0])
    n_samples = len(features)

    to_remove = set()
    for i in range(n_features):
        if i in to_remove:
            continue
        col_i = [features[r][i] for r in range(n_samples)]
        for j in range(i + 1, n_features):
            if j in to_remove:
                continue
            col_j = [features[r][j] for r in range(n_samples)]
            corr = abs(correlation(col_i, col_j))
            if corr >= threshold:
                to_remove.add(j)

    return [i for i in range(n_features) if i not in to_remove]

Step 6: 전체 파이프라인과 데모

import random


def make_housing_data(n=200, seed=42):
    random.seed(seed)
    data = []
    for _ in range(n):
        sqft = random.uniform(500, 5000)
        bedrooms = random.choice([1, 2, 3, 4, 5])
        age = random.uniform(0, 50)
        neighborhood = random.choice(["downtown", "suburbs", "rural"])
        has_pool = random.choice([True, False])

        sqft_with_missing = sqft if random.random() > 0.05 else None
        age_with_missing = age if random.random() > 0.08 else None

        price = (
            50 * sqft
            + 20000 * bedrooms
            - 1000 * age
            + (50000 if neighborhood == "downtown" else 10000 if neighborhood == "suburbs" else 0)
            + (15000 if has_pool else 0)
            + random.gauss(0, 20000)
        )

        data.append({
            "sqft": sqft_with_missing,
            "bedrooms": bedrooms,
            "age": age_with_missing,
            "neighborhood": neighborhood,
            "has_pool": has_pool,
            "price": price,
        })
    return data


if __name__ == "__main__":
    data = make_housing_data(200)

    print("=== 원시 데이터 예시 ===")
    for row in data[:3]:
        print(f"  {row}")

    sqft_raw = [d["sqft"] for d in data]
    age_raw = [d["age"] for d in data]
    prices = [d["price"] for d in data]

    print("\n=== 결측값 처리 ===")
    sqft_missing = sum(1 for v in sqft_raw if v is None)
    age_missing = sum(1 for v in age_raw if v is None)
    print(f"  sqft 결측: {sqft_missing}/{len(sqft_raw)}")
    print(f"  age 결측: {age_missing}/{len(age_raw)}")

    sqft_indicator = add_missing_indicator(sqft_raw)
    age_indicator = add_missing_indicator(age_raw)
    sqft_imputed, sqft_fill = impute_median(sqft_raw)
    age_imputed, age_fill = impute_mean(age_raw)
    print(f"  sqft는 중앙값으로 채웠습니다: {sqft_fill:.0f}")
    print(f"  age는 평균으로 채웠습니다: {age_fill:.1f}")

    print("\n=== 수치형 변환 ===")
    sqft_scaled = standardize(sqft_imputed)
    age_scaled = min_max_scale(age_imputed)
    sqft_log = log_transform(sqft_imputed)
    age_binned = bin_values(age_imputed, n_bins=5)
    print(f"  sqft 표준화: mean={sum(sqft_scaled)/len(sqft_scaled):.4f}, std={math.sqrt(sum(v**2 for v in sqft_scaled)/len(sqft_scaled)):.4f}")
    print(f"  age min-max: [{min(age_scaled):.2f}, {max(age_scaled):.2f}]")
    print(f"  age 구간: {sorted(set(age_binned))}")

    print("\n=== 범주형 인코딩(Categorical Encoding) ===")
    neighborhoods = [d["neighborhood"] for d in data]

    ohe, ohe_cats = one_hot_encode(neighborhoods)
    print(f"  원-핫 범주(One-hot categories): {ohe_cats}")
    print(f"  인코딩 예시: {neighborhoods[0]} -> {ohe[0]}")

    le, le_map = label_encode(neighborhoods)
    print(f"  라벨 인코딩 맵(Label encoding map): {le_map}")

    te, te_map = target_encode(neighborhoods, prices, smoothing=10)
    print(f"  타깃 인코딩(Target encoding): {({k: round(v) for k, v in te_map.items()})}")

    print("\n=== 텍스트 특성 ===")
    descriptions = [
        "large modern house with pool",
        "small cozy cottage near downtown",
        "spacious family home with large yard",
        "modern apartment downtown with view",
        "rustic cabin in rural area",
    ]
    cv, cv_vocab = count_vectorize(descriptions)
    print(f"  어휘 크기(Vocabulary size): {len(cv_vocab)}")
    print(f"  문서 0의 0이 아닌 특성 수: {sum(1 for v in cv[0] if v > 0)}")

    tf, tf_vocab = tfidf(descriptions)
    print(f"  TF-IDF 어휘 크기: {len(tf_vocab)}")
    top_words = sorted(tf_vocab.keys(), key=lambda w: tf[0][tf_vocab[w]], reverse=True)[:3]
    print(f"  문서 0의 상위 TF-IDF 단어: {top_words}")

    print("\n=== 다항식 특성 ===")
    sample_row = [sqft_scaled[0], age_scaled[0]]
    poly = polynomial_features(sample_row, degree=2)
    print(f"  입력: {[round(v, 4) for v in sample_row]}")
    print(f"  다항식 특성: {[round(v, 4) for v in poly]}")
    print("  특성: [x1, x2, x1^2, x2^2, x1*x2]")

    print("\n=== 특성 선택 ===")
    feature_matrix = [
        [sqft_scaled[i], age_scaled[i], float(sqft_indicator[i]), float(age_indicator[i])]
        + ohe[i]
        for i in range(len(data))
    ]

    print(f"  전체 특성 수: {len(feature_matrix[0])}")

    surviving_var = variance_threshold(feature_matrix, threshold=0.01)
    print(f"  분산 임계값(0.01) 이후: 특성 {len(surviving_var)}개 유지")

    surviving_corr = remove_correlated(feature_matrix, threshold=0.9)
    print(f"  상관관계 필터(0.9) 이후: 특성 {len(surviving_corr)}개 유지")

    binary_prices = [1 if p > sum(prices) / len(prices) else 0 for p in prices]
    print("\n  타깃과의 상호 정보량(Mutual information):")
    feature_names = ["sqft", "age", "sqft_missing", "age_missing"] + [f"neigh_{c}" for c in ohe_cats]
    for j in range(len(feature_matrix[0])):
        col = [feature_matrix[i][j] for i in range(len(feature_matrix))]
        mi = mutual_information(col, binary_prices, n_bins=10)
        print(f"    {feature_names[j]}: MI={mi:.4f}")

    print("\n  가격과의 상관관계(Correlation):")
    for j in range(len(feature_matrix[0])):
        col = [feature_matrix[i][j] for i in range(len(feature_matrix))]
        corr = correlation(col, prices)
        print(f"    {feature_names[j]}: r={corr:.4f}")

사용하기

scikit-learn에서는 이런 변환을 조합 가능한 파이프라인(composable pipeline)으로 묶습니다.

from sklearn.preprocessing import StandardScaler, OneHotEncoder, PolynomialFeatures
from sklearn.impute import SimpleImputer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import mutual_info_classif, VarianceThreshold
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

numeric_pipe = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),
    ("scaler", StandardScaler()),
])

categorical_pipe = Pipeline([
    ("encoder", OneHotEncoder(sparse_output=False)),
])

preprocessor = ColumnTransformer([
    ("num", numeric_pipe, ["sqft", "age"]),
    ("cat", categorical_pipe, ["neighborhood"]),
])

직접 구현한 버전은 각 변환(transform) 내부에서 어떤 계산이 일어나는지 보여줍니다. 라이브러리 버전은 경계 사례(edge case) 처리, 희소 행렬(sparse matrix) 지원, 파이프라인 조합(pipeline composition)을 더하지만 수학은 같습니다.

출하하기

이 lesson의 산출물은 다음입니다.

  • outputs/prompt-feature-engineer.md — 원시 데이터에서 체계적으로 특성(feature)을 설계하기 위한 프롬프트(prompt)

연습문제

  1. (쉬움) 강건 스케일링(Robust scaling)을 추가합니다. 평균과 표준편차 대신 중앙값과 사분위수 범위(IQR; Interquartile range)를 사용합니다. 극단적 이상치가 있는 데이터에서 표준 스케일링(standard scaling)과 비교합니다.

  2. (중간) 단일 제외 타깃 인코딩(Leave-one-out target encoding)을 구현합니다. 각 행(row)에 대해 자기 타깃 값을 제외하고 범주별 타깃 평균을 계산합니다. 단순 타깃 인코딩(naive target encoding)보다 과적합이 줄어드는지 보입니다.

  3. (어려움) 분산 기준, 상관관계 필터링, 상호정보량 순위를 결합한 자동 특성 선택 파이프라인을 만듭니다. 주택 데이터셋(housing dataset)에 적용하고, 단순 선형 회귀로 전체 특성과 선택된 특성의 성능을 비교합니다.

핵심 용어

용어흔한 설명실제 의미
특성 공학(Feature engineering)새 열 만들기모델이 패턴을 찾기 쉽도록 원시 데이터를 표현으로 변환하는 작업
표준화(Standardization)정규화하기평균을 빼고 표준편차로 나누어 특성 평균을 0, 표준편차를 1로 만드는 작업
원-핫 인코딩(One-hot encoding)더미 변수(dummy variable) 만들기범주마다 이진 열을 만들고 각 행에서 정확히 하나만 1이 되게 하는 방식
타깃 인코딩(Target encoding)정답을 써서 인코딩범주를 해당 범주의 평균 타깃 값으로 바꾸는 방식. 평활화(smoothing)가 필요하며 데이터 누수 위험이 큼
TF-IDF고급 단어 빈도(word count)단어 빈도(Term Frequency)와 역문서 빈도(Inverse Document Frequency)를 곱해 말뭉치(corpus)에서 구별력 있는 단어에 더 큰 가중치를 주는 표현
대치(Imputation)빈칸 채우기결측값(missing value)을 평균, 중앙값, 최빈값 또는 모델 예측값으로 대체하는 작업
특성 선택(Feature selection)나쁜 열 버리기신호보다 잡음이나 중복(redundancy)을 더하는 특성을 제거하는 작업
상호정보량(Mutual information)한 값이 다른 값을 얼마나 알려주는지X를 관찰했을 때 Y의 불확실성이 얼마나 줄어드는지 측정하는 값
데이터 누수(Data leakage)실수로 부정행위(cheating)하기예측 시점에는 사용할 수 없는 정보를 학습 중 특성에 넣어 성능이 과대평가되는 문제

더 읽을거리

실습 코드

이 강의의 실습 코드 1개

features
Code

산출물

이 강의에서 생성된 프롬프트, 스킬, 코드 산출물 1개

prompt-feature-engineer

Systematic prompt for engineering features from raw tabular data

Prompt

확인 문제

3문제 · 모두 맞추면 완료 표시가 가능합니다

1.타깃 인코딩(Target encoding)에서 데이터 누수(Data leakage) 위험은 무엇인가요?

2.TF-IDF는 단어에 역문서빈도(Inverse document frequency)를 곱합니다. 그 효과는 무엇인가요?

3.두 피처(feature)의 상관관계가 0.98입니다. 하나를 제거할 수 있는 이유는 무엇인가요?

0/3 답변 완료