☑️ 문제6. SQL 문법 → 파이썬 문법
[문제]
- orders 테이블에서 월별(년-월) 주문 건수를 계산하되, 주문이 없는 달도 0건으로 포함하고, 지난달 대비 주문 건수 증감율(growth_rate)을 계산하세요. 결과는 년-월(month) 순서대로 정렬하며, 증감율은 소수점 둘째 자리까지 반올림 해주세요.
[문제 풀이]
내 코드
import pandas as pd
orders = pd.read_csv("orders.csv")
orders
# 1) df 시리즈 "%Y-%m" 형태로 변형 : dt.strftime 메소드 (날짜형 -> 문자열로 반환)
orders.info()
orders['month'] = pd.to_datetime(orders['order_purchase_timestamp']).dt.strftime('%Y-%m')
# 2) 월별 주문 건수 계산 및 누락 월 확인
df = orders.groupby('month')['order_id'].count().sort_values(by='month',ascending=True)# 월별 카운팅 & 정렬
df
# 3) 누락월 생성 하기 :date_range 메소드 & 리스트로 저장되니까 날짜 변환 함수 strftime 활용
date_index = pd.date_range(start=df.index.min(),end=df.index.max(),freq='MS').strftime('%Y-%m')
date_index
# 4) 생성한 리스트 인덱스로 교체 후, 결측값 0 처리 :reindex
df = df.reindex(labels=date_index,fill_value=0)
# 5) month 다시 컬럼화 -> 데이터 프레임 변환 or reset_index()
df=pd.DataFrame(df)
df.rename(columns={'order_id':'cnt_orders'},inplace=True) # 이름 변경
# 조건별 전월대비 증감율 계산 (함수화 & apply 적용)
df["prev_orders"] = df["cnt_orders"].shift() # 이전값 가져오기
df['growth_rate'] = 0
df.loc[df['prev_orders'] == 0, "growth_rate"] = round(df['cnt_orders'] * 100,1)
df.loc[df['prev_orders'] != 0, "growth_rate"] = round(((df['cnt_orders'] / df['prev_orders'])-1 * 100),1)
수정 코드
def calculate_growth_rate(row, prev_col, cur_col):
if pd.isna(row[prev_col]): # prev_orders IS NULL
return None
elif row[prev_col] == 0: # prev_orders = 0
return row[cur_col] * 100
else:
return round(((row[cur_col] - row[prev_col]) / row[prev_col]) * 100, 2)
df["growth_rate"] = df.apply(calculate_growth_rate,prev_col = 'prev_orders',cur_col = 'cnt_orders',axis = 1)
이슈 및 해결 과정
- 날짜 데이터 누락시 `pd.date_range` & `reindex` 함수 사용 (날짜 데이터 인덱스로!!! 설정 해야 편함)
- `date_range` ( start = ,end= , periods= 생성날짜의 갯수 ,freq= 간격 )
- 두 인접 지점 간의 차이가 지정되는 등 간격 시간 지점의 범위를 datetimeindex 타입으로 반환
- 시작-끝점 포함하는게 디폴트
- 위에 파라미터 옵션중 3개는 필수 지정
- freq= 옵션 : D(일) M(월)ME(월말) MS(월초) 3ME(3개월말) ▷ 대소문자 주의!!
- index 의 최소, 최대값이면 → `start = df.index.min()` / `end= df.index.max() `
- 컬럼의 최소, 최대값이면 → `start = df['컬럼'].min()` / `end= df['컬럼'].max() `
- `reindex`인덱스 재 설정해주는 메소드, 기존 인덱스는 제거됨. label= fill_value= 옵션 있음
- 생성월을 인덱스로 재 설정하여 기존 df에 연결 해줌.
- label = 생성한 인덱스명 , fill_value= 결측치 대체값
- 인덱스 -> 컬럼으로 변경 시 reset_index or pd.DateFrame 2가지 방식이 있음
- `조건별 ( 이전값이 null, 0,일때) 증감율 계산시` 사용자 정의 함수 생성 후 apply 로 행 단위 적용
- 행단위 함수 받을때 apply 파라미터로 옵션으로 axis=1 설정
- row 는 각 행을 나타내는 시리즈타입의 객체 → `각각의 열의 값을 row ['컬럼명'] 으로 참조함`
- 옵션으로 `raw=True` 시 row 인덱싱 가능
▼ DF 에서 행단위 apply( --- , axis=1) 함수 사용 예제
더보기
#데이터프레임에 행단위로 함수 적용시
ex) a 컬럼의 값이 2보다 크면 '큰값' 아니면 '작은값'을 가지는 컬럼 생성
df = pd.DataFrame({
'A': [1, 2, 3, 4],
'B': [5, 6, 7, 8]
})
def categorize(row): #row 매캐변수
if row['A'] > 2: #A컬럼 각각의 값 ( 행 별) 이 2보다 클때
return '큰 값'
else:
return '작은 값'
df['size'] = df.apply(categorize, axis=1) # size 컬럼에 행단위로 함수 적용
print(df)
한줄 포인트
- 누락월 생성 후 병합하는 코드 작성시, 인덱스&컬럼으로 적절하게 변환하는게 핵심. (누락월 생성 & 병합시 인덱스로 놓고처리해주고 (` date_change ` , `reindex` ) 이름 변경시 다시 컬럼화 시켜주는게 편함)
- 행단위 apply 적용시, 파라미터 옵션으로 axis=1 , 열의 값은 row['컬럼명'] 으로 참조 → 즉, 함수 생성 후 참조시 매개변수로 `row, 컬럼` 을 받아야함
참고
https://pandas.pydata.org/docs/reference/api/pandas.date_range.html#pandas.date_range
pandas.date_range — pandas 2.2.3 documentation
Time zone name for returning localized DatetimeIndex, for example ‘Asia/Hong_Kong’. By default, the resulting DatetimeIndex is timezone-naive unless timezone-aware datetime-likes are passed.
pandas.pydata.org
'PYTHON' 카테고리의 다른 글
프로젝트 회고 | Kaggle 스타벅스 마케팅 데이터 분석 : 데이터 전처리 (0) | 2024.12.31 |
---|---|
프로젝트 회고 | Kaggle 스타벅스 마케팅 데이터 분석 : 분석 개요 (0) | 2024.12.30 |
실습 | PANDAS 결측값 및 IQR 기준 이상치 처리하기(dropna/drop /quantile/str.contains/apply/isdigit) (0) | 2024.12.26 |
실습 | PANDAS 삼성전자 종가 데이터 전월비 증감율 구하기 (strftime / pct_change/shift) (1) | 2024.12.26 |
실습 | PANDAS 집계 함수/ 상관관계 / 산점도 그리기 ( agg/corr/ matplotlib vs seaborn) (0) | 2024.12.26 |