2024-07-26

강대·2024년 7월 26일
post-thumbnail

안녕하세요
벌써 금요일이네요 !!
오늘도 저희(다비치)는 열심히 회의하고 플젝 진행 중이었습니다 !!
오늘 회의록 정리하는 TIL 써보겠습니다 😇






♾️ Data EDA 및 가설 검증


일반 카드사 데이터와 지역화폐 데이터를 비교하여
지역화폐의 현황과 지역별, 연령별, 성별 등 두드러지는 특징을 파악

Data : 2023년 | 경기도 수원, 하남, 포천 (3개 지역 한정)
► 수원 - 경기도 인구수 1위 도시
► 하남 - '삶에 대한 만족도 조사' 상위(과천시, 가평군, 하남시 순으로 높음)
► 포천 - 인구 수, '삶에 대한 만족도 조사' 하위권
|
ex) 2023년 수원 카드 결제 데이터 + 2023년 수원 지역화폐 결제 데이터셋 병합


지역화폐 오픈 API를 가져올 때 조작법이 너무 익숙치 않아 소현튜터님께
도움을 요청했는데요 ...,
다행히 해결돼서 지역화폐 데이터를 가져올 수 있었습니다 !!!!!
😭😭😭


https://developevolvify.tistory.com/106
블로그주인님께 무한감사 압도적감사 동서남북 절 올립니다


import requests
import json
import pandas as pd

#재시도 로직 구현 라이브러리
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

apiEndPointUrl = 'https://apis.data.go.kr/B190001/localGiftsPaymentV3/paymentsV3'
apiKeyDecoding= '일반인증키'
regions = {'41111': '수원시 장안구', '41117': '수원시 영통구', '41115': '수원시 팔달구', '41113': '수원시 권선구'}
for rgn_cd, rgn_name in regions.items():
    page = 1
    combined_df = pd.DataFrame()
    while True:
        try:
            params = {
                'serviceKey': apiKeyDecoding,
                'page': page,
                'perPage': 10000,
                'cond[crtr_ym::GTE]': '202301',
                'cond[crtr_ym::LTE]': '202312',
                'cond[usage_rgn_cd::EQ]': rgn_cd,
            }
            # 재시도 로직
            session = requests.Session() # HTTP 요청을 보낼때 세션 생성(세션, 연결 유지 & 재사용 → 성능 개선됨 )
            retry = Retry(total=5, backoff_factor=1, status_forcelist=[500, 502, 503, 504])
                         # 5번까지 재시도,  재시도 간격,  특정 HTTP 상태코드가 발생할 때만 재시도
            adapter = HTTPAdapter(max_retries=retry) # 위에서 설정한 재시도 옵션 재사용
            session.mount('http://', adapter) # HTTP 요청중 http://프로토콜 사용하는 경우 어댑터를 세션에 연결
            session.mount('https://', adapter) # HTTP 요청중 https://프로토콜 사용하는 경우 어댑터를 세션에 연결
            # API 요청 보내기
            response = session.get(apiEndPointUrl, params=params)
            response.raise_for_status() # HTTP 오류가 발생하면 예외시킴
            data = response.json()
            # 데이터 프레임으로 만들고 이어붙인뒤 저장
            if 'data' in data and data['data']:
                df = pd.json_normalize(data['data'])
                combined_df = pd.concat([combined_df, df], ignore_index=True)
                print(f"데이터를 {rgn_name}_{page} 페이지에서 가져옵니다.")
                page += 1
            else:
                print(f"{rgn_name} 지역 데이터 수집 완료.")
                combined_df.to_csv(f'{rgn_name}.csv', encoding='utf-8-sig', index=False)
                break
        except requests.exceptions.RequestException as re:
            print(f"오류 발생: {re}")
            continue

이렇게 이쁘게 작성해주신 코드덕분에
API 아주 빠르게 가져올 수 있었습니다 😭




- 수원 지역화폐 결제정보 데이터
101,704 rows × 11 columns

컬럼 순서 바꾸는 법
> 순서대로 컬럼명 써주기
new_order = ['crtr_ym', 'usage_rgn_cd', 'emd_cd', 'emd_nm', 'par_gend', 'par_ag', 'stlm_nocs', 'stlm_amt', 'card_use_amt', 'mbl_user_cnt', 'mbl_use_amt']

# 컬럼 순서 변경
dp = df[new_order]
> 본 데이터프레임에서 새로운 변수명으로 입력

# 새로운 csv 파일로 저정하기
dp.to_csv('new_file.csv', index=False)



  • 가설 1 : 30-40대 사용빈도가 높을 것이다
    실제 수원 지역화폐 데이터에서 40-50-30-20대들 순으로 이용 빈도가 나타남
    par_ag : 결제자연령대(01 : ~19세, 02 : 20~29세, 03 : 30~39세 ...)



# 결측치 확인 1
pp.isnull().sum()

crtr_ym            0
usage_rgn_cd       0
emd_cd             0
emd_nm           794 > 읍면동명 ex) 우만동, 고색동 등
par_gend        1945
par_ag             0
stlm_nocs          0
stlm_amt           0
card_use_amt       0
mbl_user_cnt       0
mbl_use_amt        0
dtype: int64

# 읍면동명 결측값만 추출
mi_nm = pp[pp['emd_nm'].isnull()]
mi_nm

# 읍면동 결측값 / 읍면동코드 고유값 및 갯수 확인
cc = mi_nm['emd_cd'].value_counts()
cc

> emd_cd
41111000    295
41117000    271
41115000    160
41113000     68
Name: count, dtype: int64

원래 읍면동 코드는 41113129
이런 식으로 8자리가 형성되어야하는데요 !!
41113 = 시구 행정코드 / 129 = 읍면동 코드
라서 맨 뒤 3자리는 0이 아닌 여러 숫자들로 채워져야 정상인데

000으로만 채워진 경우는 결측값들의 읍면동코드들은
수원시 팔달구, 권선구, 장안구, 영통구 이 자체로만 존재 !



결측치 확인 2
pp.isnull().sum()

crtr_ym            0
usage_rgn_cd       0
emd_cd             0
emd_nm           794 
par_gend        1945 > 결제자성별(M: 남성 F: 여성)
par_ag             0
stlm_nocs          0
stlm_amt           0
card_use_amt       0
mbl_user_cnt       0
mbl_use_amt        0
dtype: int64

# par_gend가  null값인 경우 결제자 연령대가 모두 1 (미성년자의 경우)
mi_par_gend = pp[pp['par_gend'].isnull()]
mi_par_gend




✓ 성별 컬럼의 결측값의 경우 모두 연령대가 10대인 걸로 파악이 됐는데요 !
무려 2000건에 달하는데 제 생각으로는 부모님들께서 애들 명의(?)카드로 쓰는 걸로 생각이 돼서 결제금액이 높은 순대로 봐보려고 합니다

그 전에 수원 지역화폐 데이터셋 전체에서 제일 높은 결제금액은 275,991,080원(2억7천)

그리고 수원시 지역화폐는
만 14세 이상부터 발급이 가능하기 때문에
10대의 나이대는 최소 중2~갓성인 정도로 생각하면 됩니다 !



# 성별컬럼 결측값의 결제금액이 제일 높은 row 
# 최대 2,282,400원 ~ 600,000원 정도

mi_par_gend.sort_values(by='stlm_amt', ascending=False).head(1)

crtr_ym	usage_rgn_cd	emd_cd	emd_nm	par_gend	par_ag	stlm_nocs	stlm_amt	card_use_amt	mbl_user_cnt	mbl_use_amt
202304  41117          41117101 매탄동    NaN	         1	     56       	2282400	    2282400	        0	             0

>> 2,282,400



이제 여기서 들었던 의문은
그렇다면 10,647명의 10대들 중에 성별 결측값이 없던 친구들의 제일 높은 결제금액이 궁금해졌습니다 !!!
코드를 쓰기 전까지는 저는 성별 결측값이 없는 친구들이 조금 더 결제금액이 적을 거 같다고 생각됐습니다
(왜냐고 물으시면.. 그냥.. 성별 결측값이 있는 건 그냥.. 엄마아빠가 썼을 거 같아서?)




# 성별 결측치가 없는 / 연령대 10대 / 결제금액이 높은 순 (2400만원 ~ 1300만원)
# 변수명 멋대로 지은 거 정말 죄송(하지 않음 내맘임)

fr = pp[pp['par_gend'].notnull() & (pp['par_ag'] == 1)]
fr.sort_values(by='stlm_amt', ascending=False).head(30)

crtr_ym	usage_rgn_cd	emd_cd	emd_nm	par_gend	par_ag	stlm_nocs	stlm_amt	card_use_amt	mbl_user_cnt	mbl_use_amt
202305	41117	     41117105	영통동	M          	1	    84	        24529600	21639600      	9	            2890000

> 24,529,600

어라....
결제금액이 0이 하나 더 생기는 수준이네요 .....

요약통계량으로 확인해보면
첫번째 코드가 성별 결측값이 없는 10대 결제 데이터
두번째 코드가 성별 결측값이 있는 10대 결제 데이터인데요
평균만 봐도 결측값이 없는 10대의 결제 금액이 압도적이라 놀랍네요....

1개 row = 1명의 1개월 간 결제 내역
한 달 동안 2000만원을 대체 어디서 긁은 건지 궁금해죽겠는데
지역화폐 데이터는 결제처를 알 수 없어서 ...
😭😭😭😭
다음주 동안은 조금 더 자세한 분석을 진행해야 할 것 같습니다 !







이번주도 끝났네요...
네 ..
암튼 그냥 주말동안 푹 쉽시다 ~~~
고생 많으셨습니다 🍀🍀🍀

profile
걍 달려

1개의 댓글

comment-user-thumbnail
2024년 7월 29일

금액 확인할 때 지수로 표현되는 게 거슬리신다면
pd.options.display.float_format = '{:,.2f}'.format 옵션을 활용해보시는 걸 추천 드립니다 : )

답글 달기