본문 바로가기
AI SCHOOL/TIL

[DAY 44] 스토리지, 메모리 사용량 관리 parquet, downcast

2023. 2. 27.

오전에 미드프로젝트1 발표와 회고를 진행했다. 총 8개 팀이 모두 열심히 하신 결과물을 봤다. 거의 모든 팀이 발표 시간 10분이 부족할 정도로 열정이 보였다. 강사님의 피드백은 우리 팀에 대한 것이 아니더라도 귀담아들을 부분이 많았다.

기억에 남는 프로젝트(팀) 선정, 셀프 리뷰, 피어 리뷰, 프로젝트 멘토진에 대한 만족도 조사를 완료하니 오전 시간이 지났다.
오후에는 parquet 포맷과 downcast에 대한 강의가 있었다.

parquet

효율적인 데이터 저장 및 검색을 위해 설계된 오픈 소스, 열 지향 데이터 파일 형식
데이터 파일은 csv, xml, excel, json 등 다양한 포맷으로 저장이 가능하다. parquet도 그 중 하나다.
parquet 파일 포맷을 통해 스토리지 사용량을 줄일 수 있다.

parquet
데이터 저장 형식 - csv와 parquet

csv는 행 단위로 저장이 되는 반면 parquet는 열 단위로 관리한다.
열 단위로 관리하는 경우의 장점은?
- 동일한 데이터 타입이기 때문에 압축과 저장에 유리하다
- 필요한 열의 데이터만 읽어서 처리하기 때문에 자원 활용 측면에서 유리하다

csv vs parquet 실습

conda install -c conda-forge fastparquet
conda install -c conda-forge pyarrow

우선 anaconda prompt에서 위 명령어를 통해 fastparquet, pyarrow를 설치했다.

df_small = pd.DataFrame(data={'col1': [1, 2], 'col2': [3, 4]})
df_small.to_csv('df_small_csv.csv', index=False)
df_small.to_parquet('df_small_parquet.gzip')

2행 2열의 작은 데이터프레임을 만들어 df_small에 할당한 후 이를 csv와 parquet로 각각 저장한다.

csize = os.stat('df_small.csv').st_size
psize = os.stat('df_small_parquet.gzip').st_size
print(f"csv : {format(csize, ',')}바이트, parquet : {format(psize, ',')}바이트")

# 실행 결과
csv : 21바이트, parquet : 2300바이트

csv와 parquet 형식으로 각각 저장된 파일의 사이즈를 비교한 결과 csv에 비해 parquet가 훨씬 컸다.
csv는 메타 정보를 포함하지 않지만 parquet는 메타 정보를 포함하기 때문에 데이터가 아주 작은 경우에는 parquet로 저장하면 오히려 파일 사이즈가 더 클 수 있다.


이번에는 큰 사이즈의 데이터를 사용하여 비교해보자.

df = pd.read_csv('drug_sample.csv')
df.shape

# 실행 결과
(317677, 15)

30만 행이 넘는 의약품 처방 정보 데이터를 사용한다.

df.to_csv('df_csv.csv', index=False)
df.to_parquet('df_parquet.gzip', compression='gzip')

csv와 parquet로 각각 저장한다.

csize = os.stat('df_csv.csv').st_size
psize = os.stat('df_parquet.gzip').st_size
print(f"csv : {format(csize, ',')}바이트, parquet : {format(psize, ',')}바이트")

# 실행 결과
csv : 26,064,481바이트, parquet : 2,835,602바이트

사이즈가 큰 데이터로 결과를 확인했더니 parquet을 사용했을 경우 훨씬 작은 용량이 된 것을 확인할 수 있다.

csize / psize

# 실행 결과
9.191868604973477

parquet를 사용한 결과 csv에 비해 사이즈가 약 1/9이 된 결과를 볼 수 있다.

downcast

pandas를 사용하여 데이터프레임을 다룰 때, 다운캐스트를 통해 메모리 부담을 줄일 수 있다.

parquet 실습에서도 사용했던 의약품 처방 데이터를 로드하고 df에 저장한 후 요약정보를 확인한다.

df = pd.read_csv('drug_sample.csv')
df.info(memory_usage='deep')

info의 인자로 memory_usage='deep'을 주어 데이터프레임의 실제 메모리 사용량을 확인했다.

info
downcast 전

각 컬럼의 dtype을 확인할 수 있고, 메모리 사용량이 89.7MB인 것을 알 수 있다.

describe

describe()를 통해 기술통계값을 확인한 결과, 음수 값이 없고 최댓값이 크지 않아 int64를 사용할 필요가 없다고 생각할 수 있다. 이런 경우 downcast를 사용하는 것이다.

for col in df.columns:
    dtypes_name = df[col].dtypes.name
    if dtypes_name.startswith("float"):
        df[col] = pd.to_numeric(df[col], downcast="float")
    elif dtypes_name.startswith("int"):
        # 음수가 있을 때는 integer로 변경
        if df[col].min() < 0 :
            df[col] = pd.to_numeric(df[col], downcast="integer")
        # 음수가 없을 때는 unsigned로 변경
        else:
            df[col] = pd.to_numeric(df[col], downcast="unsigned")
    elif dtypes_name.startswith("bool"):
        df[col] = df[col].astype("int8")
    # 문자일 때는 category 로 변경
    elif dtypes_name.startswith("object"):
            df[col] = df[col].astype("category")

컬럼을 순회하며 데이터의 용량을 줄인다. downcast 할 때 pandas의 to_numeric을 사용하며 문자 데이터일 경우 astype을 통해 category로 변경한다.

downcastinfo
downcast 후

다시 df.info(memory_usage='deep')을 통해 데이터프레임의 요약정보를 확인 결과 각 컬럼의 dtype이 변경되었고 메모리 사용량이 10.5MB인 것을 확인할 수 있다.
=> downcast를 활용하여 최초 89.7MB였던 데이터프레임의 메모리 사용량을 10.5MB로 줄였다.


용량은 곧 돈이며 시간이기 때문에 사이즈를 줄이는 것은 매우 중요하다.
심지어 본인의 메모리에 따라 pandas를 사용하더라도 일정 사이즈 이상의 데이터를 로드하는 것조차 힘들 수 있는데, 이 문제를 해결할 수 있다.
오늘 배운 내용은 나중에 활용하게 될 상황이 반드시 생길 것 같다.
parquet, downcast 잊어버리지 않고 꼭 활용해야겠다.

반응형

댓글