불균형 데이터셋을 위한 균형 잡힌 배치 생성

PythonBeginner
지금 연습하기

소개

이 프로젝트에서는 불균형 데이터 세트를 처리하고, 클래스 분포가 대략적으로 균형을 이루는 배치를 생성할 수 있는 불균형 데이터 파이프라인을 구현하는 방법을 배우게 됩니다. 이는 머신 러닝에서 흔히 발생하는 작업으로, 데이터 세트가 다른 클래스에 비해 한 클래스에서 훨씬 더 많은 샘플을 가질 수 있으며, 이는 편향된 모델 훈련과 성능 저하로 이어질 수 있습니다.

🎯 과제

이 프로젝트에서 다음을 배우게 됩니다:

  • 배치 내 샘플 분포를 균형 있게 하기 위해 업샘플링 (upsampling) 및 다운샘플링 (downsampling) 기능을 구현하는 방법.
  • 배치 크기와 동일한 샘플 수를 가진 샘플 배치를 출력하는 방법, 여기서 배치 내 레이블의 분포는 가능한 한 균등합니다.
  • 불균형 데이터 파이프라인이 예상대로 작동하는지 확인하기 위해 테스트하는 방법.

🏆 성과

이 프로젝트를 완료하면 다음을 수행할 수 있습니다:

  • 머신 러닝에서 불균형 데이터 세트를 처리할 수 있습니다.
  • 클래스 분포를 균형 있게 하기 위해 업샘플링 (upsampling) 및 다운샘플링 (downsampling) 기술을 적용할 수 있습니다.
  • 불균형 데이터 세트에서 균형 잡힌 배치를 생성할 수 있는 데이터 파이프라인을 구현할 수 있습니다.

업샘플링 및 다운샘플링 구현

이 단계에서는 배치 내 샘플 분포를 균형 있게 하기 위해 업샘플링 (upsampling) 및 다운샘플링 (downsampling) 기능을 구현하는 방법을 배우게 됩니다.

/home/labex/project 디렉토리에 있는 unbalanced_data_pipeline.py 파일을 엽니다.

unbalanced_data_pipeline 함수에서, 특징 벡터와 해당 원 - 핫 (one-hot) 레이블 벡터를 저장하기 위해 defaultdictcounter를 생성하는 것으로 시작합니다.

    counter = defaultdict(list)
    for x, y in data:
        counter[tuple(y)].append(x)

이렇게 하면 데이터를 레이블 벡터별로 그룹화하여 업샘플링 및 다운샘플링을 더 쉽게 수행할 수 있습니다.

다음으로, 각 레이블에 대해 각 배치에 포함될 샘플 수를 계산합니다. 이는 배치 크기를 고유한 레이블 수로 나누고, 나머지를 num_left 변수에 저장하여 수행할 수 있습니다.

    batch_data = []
    pre_num = batch_size // len(counter.keys())
    num_left = batch_size % len(counter.keys())

이제 counter 딕셔너리를 반복하고 각 레이블에 대해 필요한 수의 샘플을 무작위로 샘플링합니다. 이러한 샘플을 batch_data 목록에 추가합니다.

    for y, x in counter.items():
        samples = random.sample(x, pre_num)
        batch_data.extend([[sample, list(y)] for sample in samples])

마지막으로, 나머지 샘플을 처리하기 위해 레이블과 해당 목록에서 샘플을 무작위로 선택하고 batch_data 목록에 추가합니다.

    for _ in range(num_left):
        y = random.choice(list(counter.keys()))
        x = random.choice(counter[y])
        batch_data.append([x, list(y)])

batch_data 목록을 반환합니다.

    return batch_data

이 단계에서는 배치 내 샘플 분포를 균형 있게 하기 위해 업샘플링 (upsampling) 및 다운샘플링 (downsampling) 기능을 구현했습니다. 이제 unbalanced_data_pipeline 함수는 입력 데이터와 배치 크기를 가져와 대략적으로 균형 잡힌 클래스 분포를 가진 배치 목록을 반환합니다.

✨ 솔루션 확인 및 연습

불균형 데이터 파이프라인 테스트

이 단계에서는 unbalanced_data_pipeline 함수가 예상대로 작동하는지 테스트합니다.

unbalanced_data_pipeline.py 파일에 다음 코드를 추가합니다.

if __name__ == "__main__":
    data = [
        [[1, 2, 5], [1, 0]],
        [[1, 6, 0], [1, 0]],
        [[4, 1, 8], [1, 0]],
        [[7, 0, 4], [0, 1]],
        [[5, 9, 4], [0, 1]],
        [[2, 0, 1], [0, 1]],
        [[1, 9, 3], [0, 1]],
        [[5, 5, 5], [0, 1]],
        [[8, 4, 0], [0, 1]],
        [[9, 6, 3], [0, 1]],
        [[7, 7, 0], [0, 1]],
        [[0, 3, 4], [0, 1]],
     ]
    for epoch in range(10):
        batch_data = unbalanced_data_pipeline(data, 6)
        batch_data = list(batch_data)
        print(f"{epoch=}, {batch_data=}")

if __name__ == "__main__": 블록에서 샘플 데이터와 배치 크기 6 으로 unbalanced_data_pipeline 함수를 호출합니다.

unbalanced_data_pipeline.py 파일을 실행하여 출력을 확인합니다.

python unbalanced_data_pipeline.py

출력은 원래 과제에서 제공된 예시와 유사해야 합니다.

epoch=0, batch_data=[[[1, 2, 5], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 6, 0], [1, 0]], [[2, 0, 1], [0, 1]], [[7, 0, 4], [0, 1]], [[5, 9, 4], [0, 1]]]
epoch=1, batch_data=[[[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[2, 0, 1], [0, 1]], [[9, 6, 3], [0, 1]], [[1, 9, 3], [0, 1]]]
epoch=2, batch_data=[[[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[5, 5, 5], [0, 1]], [[7, 0, 4], [0, 1]], [[8, 4, 0], [0, 1]]]
epoch=3, batch_data=[[[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[7, 7, 0], [0, 1]], [[8, 4, 0], [0, 1]], [[0, 3, 4], [0, 1]]]
epoch=4, batch_data=[[[4, 1, 8], [1, 0]], [[1, 6, 0], [1, 0]], [[1, 2, 5], [1, 0]], [[5, 5, 5], [0, 1]], [[0, 3, 4], [0, 1]], [[8, 4, 0], [0, 1]]]
epoch=5, batch_data=[[[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[2, 0, 1], [0, 1]], [[7, 0, 4], [0, 1]], [[7, 7, 0], [0, 1]]]
epoch=6, batch_data=[[[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[8, 4, 0], [0, 1]], [[5, 9, 4], [0, 1]], [[0, 3, 4], [0, 1]]]
epoch=7, batch_data=[[[1, 2, 5], [1, 0]], [[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[2, 0, 1], [0, 1]], [[0, 3, 4], [0, 1]], [[1, 9, 3], [0, 1]]]
epoch=8, batch_data=[[[1, 6, 0], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 2, 5], [1, 0]], [[7, 7, 0], [0, 1]], [[2, 0, 1], [0, 1]], [[0, 3, 4], [0, 1]]]
epoch=9, batch_data=[[[1, 2, 5], [1, 0]], [[4, 1, 8], [1, 0]], [[1, 6, 0], [1, 0]], [[7, 0, 4], [0, 1]], [[0, 3, 4], [0, 1]], [[5, 5, 5], [0, 1]]]

이 단계에서는 unbalanced_data_pipeline 함수가 예상대로 작동하는지 테스트했습니다. 이제 이 함수는 불균형 데이터를 처리하고 대략적으로 균형 잡힌 클래스 분포를 가진 데이터 배치를 반환할 수 있습니다.

✨ 솔루션 확인 및 연습

요약

축하합니다! 이 프로젝트를 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 기술을 향상시킬 수 있습니다.