Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Polars로 운석 데이터 처리하기

운석 입력을 준비하고 환경에 Polars를 추가합니다. 다음의 ROOT를 실제 프로젝트 폴더로 바꿉니다. 이 구현은 단일 노드에서 실행하며 수치형 year와 mass, 문자열 nametype과 class를 사용합니다.

필터, 평균과 비교

src/myproject/datasets/meteor_analysis.py:

import polars as pl
from transforms.api import Input, Output, transform

ROOT = "/Example Project/Meteorites"


@transform.using(
    output=Output(f"{ROOT}/meteorite_landings_cleaned"),
    meteorite_landings=Input(f"{ROOT}/meteorite_landings"),
)
def clean(output, meteorite_landings):
    rows = meteorite_landings.polars().filter(
        (pl.col("nametype") == "Valid") & (pl.col("year") >= 1950)
    )
    output.write_table(rows)


@transform.using(
    output=Output(f"{ROOT}/meteorite_stats"),
    meteorite_landings=Input(f"{ROOT}/meteorite_landings"),
)
def stats(output, meteorite_landings):
    averages = (
        meteorite_landings.polars()
        .group_by("class")
        .agg(pl.col("mass").mean().alias("avg_mass_per_class"))
    )
    output.write_table(averages)


@transform.using(
    output=Output(f"{ROOT}/meteorite_enriched"),
    meteorite_landings=Input(f"{ROOT}/meteorite_landings"),
    meteorite_stats=Input(f"{ROOT}/meteorite_stats"),
)
def enriched(output, meteorite_landings, meteorite_stats):
    landings = meteorite_landings.polars()
    averages = meteorite_stats.polars()
    joined = landings.join(averages, on="class", how="inner")
    compared = joined.with_columns(
        (pl.col("mass") > pl.col("avg_mass_per_class")).alias("greater_mass")
    )
    output.write_table(compared.filter(pl.col("greater_mass")))

Clean은 Valid 및 1950 이상 조건을 적용합니다. Stats와 Enriched는 원본 전체를 사용하여 class별 평균보다 큰 질량을 찾습니다. 평균과 같은 값은 엄격한 > 조건을 통과하지 않습니다.

Class별 출력 생성

src/myproject/datasets/meteor_class.py:

import polars as pl
from transforms.api import Input, Output, transform

ROOT = "/Example Project/Meteorites"


def make_class_transform(class_name):
    @transform.using(
        output=Output(f"{ROOT}/meteorite_{class_name}"),
        my_input=Input(f"{ROOT}/meteorite_enriched"),
    )
    def filter_by_class(output, my_input):
        selected = my_input.polars().filter(pl.col("class") == class_name)
        output.write_table(selected)

    filter_by_class.__name__ = f"filter_{class_name}"
    return filter_by_class


TRANSFORMS = [make_class_transform(name) for name in ["L6", "H5", "H4"]]

Factory 호출이 각 class 값을 고정하고 리스트에 세 변환을 보관합니다. 기본 datasets 패키지의 자동 등록으로 발견되며 출력은 L6, H5, H4별로 분리됩니다.

다른 데이터로 확장할 때는 class가 null인 행의 집계 및 조인 정책도 명시해야 합니다. 같은 키 이름을 사용하더라도 엔진별 null 처리까지 자동으로 같아지는 것은 아닙니다.