Polars 데이터 유형 변환 알아보기

이번 포스팅에서는 Polars 라이브러리에서의 데이터 유형 변환 방법에 대해서 알아보겠습니다. Polars Casting (캐스팅)은 열의 기본 데이터 유형을 새 데이터 유형으로 변환합니다. Polars는 Arrow를 사용하여 메모리의 데이터를 관리하고 Rust 구현의 컴퓨팅 커널을 사용하여 변환을 수행합니다. Cast() 메소드로 캐스팅이 가능합니다.

cast 메서드에는 소스 데이터 유형에서 대상 데이터 유형으로 변환할 수 없는 값이 발견될 때 Polars의 동작 방식을 결정하는 엄격한 매개 변수가 포함되어 있습니다. 기본적으로 strict = True입니다. 이는 Polars가 오류를 발생시켜 사용자에게 실패한 변환을 알리고 캐스팅할 수 없는 값에 대한 세부 정보를 제공한다는 의미입니다. 반면 strict = False인 경우 대상 데이터 유형으로 변환할 수 없는 모든 값은 조용히 null로 변환됩니다.

수치형 변수(Numeric)

정수와 부동 소수점 숫자를 모두 포함하는 아래 데이터프레임을 살펴보겠습니다.

import polars as pl

tempData = pl.DataFrame(
    {
        "integers": [1, 2, 3, 4, 5],
        "big_integers": [1, 10000002, 3, 10000004, 10000005],
        "floats": [4.0, 5.0, 6.0, 7.0, 8.0],
        "floats_with_decimal": [4.532, 5.5, 6.5, 7.5, 8.5],
    }
)

print(tempData)

부동 소수점과 정수 사이에서 캐스팅 작업을 수행하거나 그 반대로 수행하려면 Cast() 함수를 호출하여 사용할 수 있습니다.

outTempData = tempData.select(
    pl.col("integers").cast(pl.Float32).alias("integers_as_floats"),
    pl.col("floats").cast(pl.Int32).alias("floats_as_integers"),
    pl.col("floats_with_decimal")
    .cast(pl.Int32)
    .alias("floats_with_decimal_as_integers"),
)

print(outTempData)

소수 값의 경우 정수로 변환할 때 버림 처리(아래로 반올림)됩니다.


다운캐스트(Downcast)

값에 할당된 비트 수를 수정하여 메모리 공간을 줄이는 것도 가능합니다. 예를 들어, 아래 코드는 Int64에서 Int16으로, Float64에서 Float32로 캐스팅하여 메모리 사용량을 줄이는 방법을 보여줍니다.

outTempData = tempData.select(
    pl.col("integers").cast(pl.Int16).alias("integers_smallfootprint"),
    pl.col("floats").cast(pl.Float32).alias("floats_smallfootprint"),
)

print(outTempData)


오버플로우(Overflow)

다운캐스팅을 수행할 때 선택한 비트 수(예: 64, 32 또는 16)가 열의 가장 큰 숫자와 가장 작은 숫자를 수용하기에 충분한지 확인하는 것이 중요합니다. 예를 들어, 32비트 부호 있는 정수(Int32)를 사용하면 -2147483648에서 +2147483647 범위 내의 정수를 처리할 수 있는 반면, Int8을 사용하면 -128에서 127 사이의 정수를 처리할 수 있습니다.

너무 작은 데이터 유형으로 캐스팅하려고 하면 다음과 같은 결과가 발생합니다. 작업이 지원되지 않기 때문에 Polars에서 발생한 ComputeError입니다.

try:
    outErrorData = tempData.select(pl.col("big_integers").cast(pl.Int8))
    print(outErrorData)
    
except Exception as e:
    print(e)

---------------------------------------------------------------------------------------------------------------------
conversion from `i64` to `i8` failed in column 'big_integers' for 3 out of 5 values: [10000002, 10000004, 10000005]

strict 매개변수를 False로 설정하면 오버플로되는 값이 null 값으로 변환됩니다.

try:
    outErrorData = tempData.select(pl.col("big_integers").cast(pl.Int8, strict = False))
    print(outErrorData)
    
except Exception as e:
    print(e)



문자열 변수(String)

문자열은 숫자 데이터 유형으로 변환될 수 있으며 그 반대의 경우도 마찬가지입니다.

tempStringData = pl.DataFrame(
    {
        "integers": [1, 2, 3, 4, 5],
        "float": [4.0, 5.03, 6.0, 7.0, 8.0],
        "floats_as_string": ["4.0", "5.0", "6.0", "7.0", "8.0"],
    }
)

outTempStringData = tempStringData.select(
    pl.col("integers").cast(pl.String),
    pl.col("float").cast(pl.String),
    pl.col("floats_as_string").cast(pl.Float64),
)

print(outTempStringData)

열에 숫자가 아닌 값이 포함된 경우 Polars는 변환 오류를 자세히 설명하는 ComputeError를 발생시킵니다. strict = False로 설정하면 float가 아닌 값이 null로 변환됩니다.

tempStringData = pl.DataFrame({"strings_not_float": ["4.0", "not_a_number", "6.0", "7.0", "8.0"]})

try:
    outTempStringData = tempStringData.select(pl.col("strings_not_float").cast(pl.Float64))
    print(out)
except Exception as e:
    print(e)
------------------------------------------------------------------------------------------------------------------
conversion from `str` to `f64` failed in column 'strings_not_float' for 1 out of 5 values: ["not_a_number"]
​


부울 변수(Boolean)

부울은 1(True) 또는 0(False)으로 표현될 수 있습니다. 숫자형 데이터 유형과 부울 사이에서 캐스팅 작업을 수행할 수 있으며 그 반대도 가능합니다. 그러나 문자열(String)에서 부울로의 변환은 허용되지 않습니다.

booleanTempData = pl.DataFrame(
    {
        "integers": [-1, 0, 2, 3, 4],
        "floats": [0.0, 1.0, 2.0, 3.0, 4.0],
        "bools": [True, False, True, False, True],
    }
)

outBooleanTempData = booleanTempData.select(pl.col("integers").cast(pl.Boolean), pl.col("floats").cast(pl.Boolean))

print(booleanTempData)


날짜형 변수(Dates)

날짜 또는 날짜/시간과 같은 임시 데이터 유형은 에포크 이후의 일수(Date) 및 마이크로초(Datetime)로 표시됩니다. 따라서 숫자 유형과 시간 데이터 유형 간의 캐스팅이 허용됩니다.

from datetime import date, datetime

dateTempData = pl.DataFrame(
    {
        "date": pl.date_range(date(2022, 1, 1), date(2022, 1, 5), eager = True),
        "datetime": pl.datetime_range(
            datetime(2022, 1, 1), datetime(2022, 1, 5), eager = True
        ),
    }
)

outDateTempData = dateTempData.select(pl.col("date").cast(pl.Int64), pl.col("datetime").cast(pl.Int64))
print(outDateTempData)

문자열과 날짜/날짜/시간 사이를 변환하려면 dt.to_string 및 str.to_datetime이 활용됩니다. Polars는 형식 지정을 위해 크로노 형식 구문을 채택합니다. str.to_datetime에는 시간대 기능을 지원하는 추가 옵션이 있으니, 이는 참고하시면 됩니다.

dateTempData = pl.DataFrame(
    {
        "date": pl.date_range(date(2022, 1, 1), date(2022, 1, 5), eager = True),
        "string": [
            "2022-01-01",
            "2022-01-02",
            "2022-01-03",
            "2022-01-04",
            "2022-01-05",
        ],
    }
)

outDateTempData = dateTempData.select(
    pl.col("date").dt.to_string("%Y-%m-%d"),
    pl.col("string").str.to_datetime("%Y-%m-%d"),
)

print(outDateTempData)


결론

이상으로 Polars 라이브러리에서 제공하는 데이터 유형 변환 함수 및 그 방법에 대해서 알아보았습니다. 다음 포스팅에서는 문자열 변수의 조작을 다루는 방법에 대해서 알아보겠습니다.

감사합니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다