* 데이터 출처: App_review_data
1. csv 파일 병합 후 전처리하여 parquet로 저장하기
1) 고용량 데이터 불러오기
- glob 라이브러리 및 함수: 인자로 받은 패턴과 이름이 일치하는 모든 파일과 디렉터리의 리스트 반환
- tqdm 라이브러리 및 함수: 코드 진행률을 파악할 수 있는 프로세스바 지원
from glob import glob
from datetime import timedelta
from tqdm import tqdm
import pandas as pd
import matplotlib.pyplot as plt
glob(".../app_review_data/*.csv")
# ['.../app_review_data\\FACEBOOK_REVIEWS.csv',
# '.../app_review_data\\FLIPKART_REVIEWS.csv',
# '.../app_review_data\\INSTAGRAM_REVIEWS.csv',
# '.../app_review_data\\SPOTIFY_REVIEWS.csv',
# '.../app_review_data\\TIKTOK_REVIEWS.csv',
# '.../app_review_data\\TWITTER_REVIEWS.csv',
# '.../app_review_data\\WHATSAPP_REVIEWS.csv']
# 데이터를 추출하는 함수 작성
def extract_csvs():
res = []
for path in tqdm(glob("D:/2024 내일배움캠프/스파크/app_review_data/*.csv")):
app_name = path.split("/")[-1].replace(".csv","")
df_temp = pd.read_csv(path)
df_temp = df_temp.assign(app_name=app_name)
res.append(df_temp)
df = pd.concat(res)
return df
df = extract_csvs()
# 100%|██████████| 7/7 [01:14<00:00, 10.65s/it]
# 2분 20초 소요
2) 데이터 기본 정보 확인 및 전처리
- 데이터 기본 정보 파악 및 칼럼 정리
- 현재 메모리는 2.7GB
df.info()
df.isna().mean()
df.review_rating.value_counts()
df.review_rating.sort_values()
# 필요한 칼럼 값만 불러오기
target_columns = [
'review_id', 'pseudo_author_id', 'author_name', 'review_text', 'review_rating',
'review_likes' , 'review_datetime_utc', 'review_timestamp'
]
df_target = df[target_columns]
# 기존 df에 새로 생성한 데이터 프레임 할당 후 삭제
df = df_target
del df_target
- 데이터 전처리: 시간 데이터
└ 데이터 타입 수정 및 결측치 처리
df.isna().sum()
# 심상치 않은 null 개수 차이
# review_datetime_utc 19716190
# review_timestamp 8438195
df['review_timestamp'].dropna().head(2) # 2009-09-09 07:36:50 # object
df['review_datetime_utc'].dropna().head(2) # 2011-07-08T05:26:10.000Z # object
# 형식이 다른 timestamp와 datetime_utc를 datetime으로 변환
df['review_timestamp'] = pd.to_datetime(df['review_timestamp']) # object > datetime64[ns]
df['review_datetime_utc'] = pd.to_datetime(df['review_datetime_utc']) # object > datetime64[ns, UTC]
# timestamp와 datetime_utc이 동시에 존재하면 에러가 발생하도록 설정
if (df.review_timestamp.notna() & df.review_datetime_utc.notna()).sum() > 0:
raise Exception("review_timestamp와 review_datetime_utc가 동시에 존재합니다.")
# timestamp의 null값에 datetime_utc 데이터 추가
df['review_timestamp'].fillna(df['review_datetime_utc']).notna().mean()
└ 시간대 타임존 확인
# datetime_utc은 utc인데, timestamp도 utc 시간대가 맞을까?
# 시간대별로 그래프 차이를 확인
# 2개 그래프의 추이는 유사한 것으로 파악되어 원본 데이터는 UTC로 추정
df['review_timestamp'].dt.hour.value_counts(normalize=True).sort_index().plot()
df['review_datetime_utc'].dt.hour.value_counts(normalize=True).sort_index().plot()
plt.legend(['review_timestamp','review_datetime_utc'])
plt.show()
└ 시간대 현지시간에 맞춰서 수정
: tz_localize() 로 타임존 정보 기입 가능
# 데이터 원본은 utc나 실제 사용국은 미국인 것으로 추정
# 1. 앱스토어가 미국 것이고
# 2. 24시쯤 트래픽이 최저 흐름을 보이고 있음(국가 막론 새벽 4~5시 트래픽 최저 > 미국은 UTC랑 5시간 차이가 남)
# 하여, 미국 현지 시간에 맞춰 타임 정보 조정
# 미국 시간으로 조정할 거니까 타임존 정보는 none으로 없애기
df['review_datetime_utc'] = df['review_datetime_utc'].dt.tz_localize(None)
# 각 UTC 시간에 5시간 더 해주기
df['review_datetime_utc'] += timedelta(hours=5)
df['review_timestamp'] += timedelta(hours=5)
# timestamp 칼럼 null값에 datetime 넣기
df['review_timestamp'].fillna(df['review_datetime_utc'])
#datetime_utc는 제거하기
df = df.drop(['review_datetime_utc'], axis = 1)
- 파일 내보내기
└ 파일 병합 후 메모리 2.7GB에서 전처리 작업 후 1.7GB로 약 37% 경량화
df.info()
df.to_parquet("./target_raw.parquet")
2. I/O
- csv와 parquet 파일별 입출력 시간 확인
import pandas as pd
%%time
df = pd.read_parquet("target_raw.parquet")
# parquet #불러오는 시간
# CPU times: total: 32 s
# Wall time: 1min 34s
%%time
df.to_parquet("target_raw.parquet")
# parquet #저장하는 시간
# CPU times: total: 15.7 s
# Wall time: 1min 5s
%%time
df.to_csv("target_raw.csv", index=False)
# csv #저장하는 시간
# CPU times: total: 28.7 s
# Wall time: 1min 58s
%%time
df = pd.read_csv("target_raw.csv")
# csv #불러오는 시간
# CPU times: total: 33.4 s
# Wall time: 3min 40s
- 데이터 타입 규모 확인
# null 값 확인
# null 값이 섞여 있으면 float(실수)가 됨
df.isna().mean()
# 샘플링
df_raw = df.copy()
df = df_raw.sample(frac=0.1)
df.info()
# 각 칼럼별 데이터 규모 확인 (데이터 타입 축소를 위함)
# df.dtypes.items 입력 시 칼럼명, 데이터 타입이 출력
for col, data_type in df.dtypes.items():
if data_type == 'object':
ser_target = df[col].value_counts()
print(f"{col}({data_type}): {len(ser_target):,}가지")
elif ('int' in str(data_type)) or ('float' in str(data_type)):
max_value = df[col].max()
min_value = df[col].min()
# null을 제외하고 1로 나눈 값의 나머지가 0이 아니다 = 실수(null 값 때문에 실수로 변환)
# 그래서 4.0, 5.0과 같이 실수 형태이나 나머지를합친 값이 0이면 int로 변환!
if (((df[col].dropna() % 1) != 0).sum() == 0) or (('int') in str(data_type)):
target_data_type = 'int'
else:
target_data_type = 'float'
print(f'{col}({target_data_type}): {min_value: ,.2f} ~ {max_value: ,.2f}')
elif ('datetime') in str(data_type):
target_data_type = 'datetime'
print(f"{col}({data_type}): {len(ser_target):,}가지")
else:
raise Exception('New data type:', data_type)
# review_id(object): 1,971,519가지
# app_name(object): 7가지
# pseudo_author_id(object): 1,959,195가지
# author_name(object): 583,877가지
# review_text(object): 1,465,193가지
# review_rating(int): 0.00 ~ 5.00
# review_likes(int): 0.00 ~ 108,000.00
# review_timestamp(datetime64[ns]): 1,465,193가지
- 데이터 규모에 맞춰서 데이터 타입 수정
└ df.memory_usage() : 각 컬럼별 메모리 사용량 조회
└ assert: assert는 뒤의 조건이 True가 아니면 AssertError를 발생
df = df_raw
del df_raw
df.info()
# 변경할 칼럼 설정
int32_cols = ['review_likes']
int8_cols = ['review_rating']
cate_cols = ['app_name']
# 변경 전 메모리 사용량
memory_usage_before = df.memory_usage().sum()
memory_usage_before
# 데이터 타입 범위를 넘어가면 오류가 발생하도록 설정
for col in int32_cols:
assert abs(df[col].max()) < 2_147_483_647 # False 시 오류 발생
df[col] = df[col].astype(pd.Int32Dtype())
for col in int8_cols:
assert abs(df[col].max()) < 127 # False 시 오류 발생
df[col] = df[col].astype(pd.Int8Dtype())
for col in cate_cols:
assert df[col].nunique() < 10_000 # False 시 오류 발생
df[col] = df[col].astype("category")
df.info()
# 변경 후 메모리 사용량과 감소율
memory_usage_after = df.memory_usage().sum()
reduction_ratio = 1 - (memory_usage_after / memory_usage_before)
print(f"Memory Usage: {memory_usage_before:,} -> {memory_usage_after:,} ({reduction_ratio*100:.2f}% reduced)")
# Memory Usage: 1,801,880,768 -> 1,351,410,964 (25.00% reduced)
'TIL' 카테고리의 다른 글
[240326] 파이썬: 코드카타 47 & SQL: 코드카타 165 (0) | 2024.03.26 |
---|---|
[240325] 파이썬: 코드카타 46 & SQL: 코드카타 161~164 (0) | 2024.03.25 |
[240321] 파이썬: 코드카타 45 & SQL: 코드카타 158~160 (0) | 2024.03.21 |
[240321] 클러스터링 분석 - ② 차원 축소: 주성분 분석(PCA)과 t-SNE (0) | 2024.03.21 |
[240320] 파이썬으로 하는 클러스터링 분석 - ① 기본 개념과 거리 계산 (0) | 2024.03.20 |