Day1
Ch02. 파이썬을 이용한 데이터 분석 - 02.데이터 시각화
plotly 이해하기
: 인터랙티브한 그래프를 그릴 수 있는 라이브러리
: 인터랙티브한 그래프를 html로 저장하기 용이
*인터랙티브하다: 그래프에 커서를 대면 값에 대 설명이 나옴
: 기본 문법
- fig = px.그래프종류(data_frame=데이터, x=X축 컬럼, y=Y축 컬럼, color=범례 컬럼, title=제목,
labels=dict(X축 컬럼=X축 라벨, Y축 컬럼=Y축 라벨),
width=그래프 가로길이, height=그래프 세로길이, text_auto=True/False)
fig.show()
- 문법 수식 안에 추가하여 사용하기 좋은 것들
- barmode, text_auto 등
: 간단한 수식과 한글도 추가 코드 없이 구현 가능한 것이 장점
: 스타일 설정하기
- template=템플릿명
- color_discrete_sequence = 컬러맵명 : 범주형 데이터
- color_continuous_scale= 컬러맵명 : 연속형 데이터
- 컬러맵 리스트 표기
- fig = px.colors.sequential.swatches_continuous()
fig.show()
- fig = px.colors.qualitative.swatches()
fig.show()
: html 파일로 저장하기
- fig.write_html(파일경로 및 파일명)
plotly로 유형별 그래프 그리기
: 산점도
- px.scatter(data_frame=데이터, x=X축 컬럼, y=Y축 컬럼, color=색, trendline='ols')
* trendline은 추세선 추가
*facet_col은 추가 컬럼별로 산점도 따로 추출
: 분포 살펴보기
- px.histogram(data_frame=데이터, x=X축 컬럼, color=색) : 히스토그램
- px.box(data_frame=데이터, x=X축 컬럼, y=Y축 컬럼, color=색) : 상자그림
: 막대 그래프
- px.bar(data_frame=데이터, x=X축 컬럼, y=Y축 컬럼, color=색, barmode='group')
*쌓아서 올리지 않으려면 barmode = 'group'을 추가한다
*text_auto는 컬럼별 값을 그래프에 표기함
: 선 그래프
- px.line(data_frame=데이터, x=X축 컬럼, y=Y축 컬럼, color=색)
: 히트맵
- px.imshow(데이터, text_auto=텍스트포맷, color_continuous_scale=컬러맵)
: 파이차트
- px.pie(data_frame=데이터, values=값, names=라벨)
folium 이해하기
: import folium
: 특정 장소의 지도 시각화하기
- 네이버 지도에서 원하는 위치를 검색한 후 url을 통해 위도와 경도 확인
- f = folium.Figure(width=가로길이, height=세로길이)
m = folium.Map(location=[위도, 경도], zoom_start=줌할정도).add_to(f)
m
- m.save('test.html') : 지도 저장
: 마커 추가하기
- 장소 표시 마커
- folium.Marker([위도, 경도]
, tooltip=마우스 오버시 나타남
, popup=클릭시 나타남
, icon=folium.Icon(color=색, icon=모양)).add_to(지도)
*popup : 이미지 추가 기능
- 원 형태 마커
- folium.CircleMarker([위도, 경도] , radius=범위, color=색).add_to(지도)
folium으로 지리 데이터 시각화하기(실습)
: 서울시 내 이디야와 투썸플레이스 개수 시각화
- 서울시 구별 경계 데이터, 서울시 상가 정보 데이터 로드
- 카페 별 데이터 전처리
- cafe = df.query('상권업종소분류명 == "카페"')
- 이디야 : ediya = cafe.loc[cafe['상호명'].str.contains('이디야'),]
- 투썸플레이스 : twosome = cafe.loc[cafe['상호명'].str.contains('투썸플레이스'),]
- 데이터프레임화
- 이디야 : ediya_count = ediya.groupby('시군명').size().to_frame().reset_index().rename({0:'count'}, axis=1).sort_values('count', ascending=False)
- 투썸플레이스 : twosome_count = twosome.groupby('시군명').size().to_frame().reset_index().rename({0:'count'}, axis=1).sort_values('count', ascending=False)
*to_frame() : 데이터를 프레임화
- 데이터를 시각화 : plotly 이용
: folium으로 지도에 시각화하기
- 서울시 지도 로드(적당한 크기로 서울시가 한 눈에 보일 수 있도록)
- f = folium.Figure(width=700, height=500)
m = folium.Map(location=[37.566535, 126.9779692], zoom_start=11).add_to(f)
- 위 지도에 서울시 구별 경계 데이터 삽입
- folium.Choropleth(geo_data = geo_json, fill_color = 'gray').add_to(m)
*. Choropleth : 특정 통계나 데이터를 사전 정의된 영역과 관련해 시각화
- 브랜드별 매장 분포를 지도에 시각화
- 이디야 :
f = folium.Figure(width=700, height=500)
m = folium.Map(location=[37.566535, 126.9779692], zoom_start=11).add_to(f)
folium.Choropleth(geo_data = geo_json
, data=ediya_count
, columns=['시군구명', 'count']
, key_on='properties.name'
, fill_color = 'YlGn'
, fill_opacity = 0.7
, line_opacity = 0.7
, legend_name = '서울시 구별 이디야 매장수').add_to(m)
- 투썸플레이스 :
f = folium.Figure(width=700, height=500)
m = folium.Map(location=[37.566535, 126.9779692], zoom_start=11).add_to(f)
folium.Choropleth(geo_data = geo_json
, data=twosome_count
, columns=['시군구명', 'count']
, key_on='properties.name'
, fill_color = 'BuPu'
, fill_opacity = 0.7
, line_opacity = 0.7
, legend_name = '서울시 구별 투썸플레이스 매장수').add_to(m)
- 이디야와 투썸플레이스 간의 상대성 비교
- 이디야와 투썸플레이스 위치 리스트화
- 위 리스트를 통한 이디야와 투썸플레이스 산점도 시각화
- from _plotly_utils.basevalidators import TitleValidator
f = folium.Figure(width=700, height=500)
m = folium.Map(location=[37.566535, 126.9779692], zoom_start=11).add_to(f)
for idx in dff.index:
lat = dff.loc[idx, '위도']
long = dff.loc[idx, '경도']
title = dff.loc[idx, '상호명']
if dff.loc[idx, 'kind'] == "이디야":
color = '#1d326c'
else:
color = '#D70035'
folium.CircleMarker([lat, long]
, radius=3
, color = color
, tooltip = title).add_to(m)
Ch03. 파이썬 데이터 분석 프로젝트 - 실습1. 데이터 수집
다양한 공개데이터 플랫폼 살펴보기
: 국내 사이트
- 서울 열린데이터 광장
- 공공데이터포털
- 통계청
: 해외 사이트
- 캐글
- awesomedata
Pandas 활용하기
: pandas를 활용한 웹크롤링 실습
- url = 'https://finance.naver.com/item/main.nhn?code=035720'
table_df_list = pd.read_html(url, encoding='euc-kr')
table_df = table_df_list[3]
: 코스피에 상장된 주요 종목의 주요 재무정보 크롤링 실습
- !pip install finance-datareader
- import FinanceDataReader
kospi = FinanceDataReader.StockListing("KOSPI")
- 상위 10개의 주요 재무 정보 리스트화
- kospi_info_list = []
for code in kospi['Code'][:10]:
url = f'https://finance.naver.com/item/main.nhn?code={code}'
table_df_list = pd.read_html(url, encoding='euc-kr')
table_df = table_df_list[3]
kospi_info_dic = {}
kospi_info_dic['code'] = code
kospi_info_dic['table'] = table_df
kospi_info_list.append(kospi_info_dic)
BeautifulSoup 활용하기
: 크롤링의 과정
- 파이썬으로 웹서버에 정보 요청 후 html 데이터 가져오기
- 데이터 파싱
- 원하는 정보 저장
: 실습
- 네이버에 제주도를 검색 후 블로그 탭의 제목, 날짜, 간략내용 크롤링하기
Ch03.파이썬 데이터 분석 프로젝트 - 실습2. 영화 데이터를 활용한 영화 흥행 요인 분석
데이터 둘러보기&질문 만들기
: 데이터 살펴보기
- 데이터 별 범주 확인
: 질문을 생각해 가설 만들기
- 연도별 흥행 수익, 가장 흥행한 영화 10개, 가장 흥행 성공한 감독과 배우
- 장르와 흥행 수익 : 흥행 수익이 좋은 장르, 시간에 흐름에 따른 장르 유행 여부, 월별 흥행 장르 여부
- 수익과 예산, 투표수, 평점 간 상관관계
- ROI(예산 대비 수익)이 높으면서 흥행에 성공한 영화의 특
: 데이터 전처리
: 분석
: 정리
데이터 전처리하기
: 필요한 컬럼만 남긴 후 merge 함수로 데이터 결합
: ROI 컬럼 만들기
- data[revenue]/data[bugdet]
: 감독 컬럼 만들기
- data['crew'][0]
- import ast ( 파이썬 자료형 데이터를 변환하는데 유용한 라이브러리)
print(ast.literal_eval(data['crew'][0])
* ast.literal_eval : 문자열 속 표현식 인식
- def get_director(x):
for i in x:
of i['job']=='Director':
return i['name']
data['director'] = data['crew'].apply(get_director)
: 배우 컬럼 만들기
- data['cast'][0]
- data['cast_name'] = data['cast'].apply(lambda x: [i['name'] for i in ast.literal_eval(x)])
: 장르 컬럼 만들기
- data['genre'][0]
- data['genres'] = data['genres'].apply(ast.literal_eval)
- def get_genres(x):
if len(x) > 0:
return x[0]['name']
- data['main_genre'] = data['genres'].apply(get_genres)
: 데이터 타입 변경
- data['release_date'] = pd.to_datetime(data['release_date'], format='%Y-%m-%d')
- data['id'] = data['id'].astype(str)
: 연도, 월 컬럼 만들기
- data['year'] = data['release_date'].dt.year
- data['month'] = data['release_date'].dt.month
: 결측치 제거
- data.dropna(inplace=True)
: 데이터 확인
EDA, 시각화 분석(1)
: 연도별 흥행 수익
- import plotly.express as px
- revenue_by_year = data.groupby('year')[['revenue']].sum().reset_index()
- fig = px.line(data_frame=revenue_by_year, x="year", y="revenue")
: 가장 흥행한 영화 10개
- 흥행 수익 top10
- top = data.groupby('title')['revenue'].sum().reset_index().sort_values('revenue', ascending=False).head(10)
- fig = px.bar(data_frame=top, x='title', y='revenue', title=f"흥행 수익 TOP 10 영화")
- 예산, 투표수 Top10
- title_dic = {'budget':'예산', 'vote_count':'투표수'}
for y in ['budget','vote_count']:
top = data.groupby('title')[[y]].sum().reset_index().sort_values(y, ascending=False).head(10)
fig = px.bar(data_frame=top, x='title', y=y, title=f"{title_dic[y]} TOP 10 영화")
: 흥행에 가장 성공한 감독과 배우
- 가장 수익이 많은 감독
- top_director = data.groupby(['director']['revenue'].sum().reset_index().sort_values('revenue', ascending=False).head(10)
- fig = px.bar(data_frame=top_director, x='director', y='revenue', title=f"흥행 수익 TOP 10 감독")
- 가장 수익이 많은 배우
- revenue_cast = data[['revenue', 'cast_name']].explode('cast_name')
*.explode() : 리스트 형태의 값을 여러 형태로 전개
- top_cast = revenue_cast.groupby('cast_name')\[['revenue']].sum().reset_index().sort_values('revenue', ascending=False).head(10)
- fig = px.bar(data_frame=top_cast, x='cast_name', y='revenue', title=f"흥행 수익 TOP 10 배우")
: 장르와 흥행 수익
- 장르별 흥행 수익 분포
- fig = px.box(data_frame = data, y = 'main_genre', x = 'revenue', hover_name = 'title')
- 장르별 흥행 수익 평균
- genre_avg_revenue = data.groupby('main_genre')[['revenue']].mean().reset_index()
- fig = px.bar(data_frame = genre_avg_revenue, x = 'main_genre', y = 'revenue', title = '장르별 흥행 수익 평균')
- 장르별 흥행 수익 합계
- genre_sum_revenue = data.groupby('main_genre')[['revenue']].sum().reset_index()
- fig = px.bar(data_frame = genre_sum_revenue, x = 'main_genre', y = 'revenue', title = '장르별 흥행 수익 합계')
- 연도별 장르별 수익
- revenue_by_year_genre = data.query('year >= 1990').groupby(['year','main_genre'])[['revenue']].sum().reset_index()'
- fig = px.bar(data_frame=revenue_by_year_genre, x='year', y='revenue', color='main_genre', color_discrete_sequence=px.colors.qualitative.Light24_r)
EDA, 시각화 분석(2)
: 수익과 예산, 투표수, 평점과의 상관관계
- data[['budget','revenue','vote_average','vote_count']].corr()
- fig = px.imshow(data[['budget','revenue','vote_average','vote_count']].corr(), text_auto='.2f', color_continuous_scale='Purp')
- for x in ['budget', 'vote_count', 'vote_average']:
- fig = px.scatter(data_frame = data, x = x, y = 'revenue', hover_name = 'title', size = 'revenue', color = 'revenue', color_continuous_scale = px.colors.sequential.Sunsetdark, width = 700, height = 600, trendline = 'ols')
: 흥행 수익 Top100만 필터링해서 보기
- top100 = data.sort_values('revenue', ascending=False).head(100)
- fig = px.imshow(top100[['budget','revenue','vote_average','vote_count']].corr(), text_auto='.2f', color_continuous_scale='Mint')
- for x in ['budget', 'vote_count', 'vote_average']:
fig = px.scatter(data_frame = top100, x = x, y = 'revenue', hover_name = 'title', size = 'revenue', color = 'revenue'
, color_continuous_scale = px.colors.sequential.Emrld, width = 700, height = 600, trendline = 'ols', trendline_color_override='green')
fig.show()
: ROI가 높으면서 흥행에 성공한 영화의 특징
- top300 = data.sort_values('revenue', ascending=False).head(300)
- fig = px.scatter(data_frame = top300, x = 'roi', y = 'revenue', hover_name = 'title', size = 'revenue', color = 'main_genre',
color_discrete_sequence=px.colors.qualitative.Light24, width = 700, height = 600)
- fig = px.box(data_frame = top300, y = 'main_genre', x = 'roi', hover_name = 'title')
Ch03. 파이썬 데이터 분석 프로젝트 - 실습3. 유통 데이터를 활용한 리텐션과 RFM 분석
데이터 둘러보기&질문 만들기
: 데이터 살펴보기
- 데이터 별 범주 확인
: 질문 만들기
- 시간의 흐름에 따라 매출, 주문고객수, 주문단가의 추이는 어떻게 달라지는가?
- 리텐션 분석 : 시간의 흐름에 따라 고객들은 얼마나 남고 얼마나 이탈했는가?
- RFM 분석 : 고객의 행동에 따른 고객 유형화
* 리텐션 분석
: 유저가 제품을 사용한 이후 일정 기간이 지난 시점에 제품을 계속 사용하고 있는지 유저의 잔존과 이탈을 트래킹하는 분석
: Day0에 앱에 방문한 유저 중 Day1에 다시 재방문한 유저의 비율이 리텐션
: 일반적으로 리텐션이 높으면 유저가 서비스를 주기적으로 사용한다는 뜻으로 해석할 수 있어, 유저의 참여와 충성도 같은 지표를 높이기 위한 제품 방향성을 정하는데 중요한 지표로 활용된다.
* RFM 분석이란?
: Recency, Frequency, Monetary를 기반으로 고객을 유형화하는 방법
- Recency (최근성): 고객이 얼마나 최근에 구매를 했는지
- Frequency (빈도): 고객이 얼마나 자주 구매를 하는지
- Monetary (금액): 고객이 구매한 총 금액
: 고객 유형을 세분화하여 맞춤형 전략을 구상할 수 있다.
- 예: 총 구매금액은 낮지만 자주 방문하는 유저 vs 최근에 큰 금액을 구매했지만 자주 방문하지는 않았던 유저
: 데이터 전처리
: 분석
데이터 전처리하기
: 데이터 확인
- data.info()
: 결측치 제거
- data.dropna(subset=['CustomerID'], inplace=True)
: 데이터 타입 변경
- data['InvoiceDate']=pd.to_datetime(data['InvoiceDate'], format='%m%d%Y %H:%M')
- data['CustomerID']=data['CustomerID'].astype(int).astype(str)
: 날짜 컬럼 추가하기
- data['date_ymd']=data['InvoiceDate'].dt.date.astype('dateime64')
- date['year']=data['InvoiceDate'].dt.year
: 매출 컬럼 추가하기
- data['amount']=data['Quantity']*data['UnitPrice']
: 분석의 편의를 위하여 취소 주문 제외
- data.data.query('Quantity>0')
EDA, 시각화 분석(1)
: 시간의 흐름에 따라 매출, 주문고객수, 주문단가의 추이는 어떻게 달라지는가
- 매출
- amount_by_date=data.groupby('date_ymd')[['amount']].sum().reset_index()
- fig=px.line(data_frame=amount_by_date, x='date_ymd', y='amount')
- 주문고객수
- customer_count_by_date=date.groupby('date_ymd')[['CustomerID']].nunique.reset_index().rename( {'CustomerID':'customer_count'}, axis=1 )
- fig=px.line(data=customer_count_by_date, x='date-YMD', y=customer_count')
- 주문단가
- amount_by_date.head()
- invoice_count_by_date = data.groupby('date_ymd' [['InvoiceNo']].nunique().reset_index().rename({'InvoiceNo':'invoice_count'}, axis=1)
- invoice_amount = pd.merge(amount_by_date, invoice_count_by_date, on='date_ymd')
- invoice_amount['amount_per_invoice'] = invoice_amount['amount'] / invoice_amount['invoice_count']
- fig = px.line(data_frame=invoice_amount, x='date_ymd', y='amount_per_invoice')
EDA, 시각화 분석(2)
리텐션 분석 - 시간의 흐름에 따라 고객들은 얼마나 남고 얼마나 이탈했는가
: 연월 단위로 고객 번호, 영수증 번호 전처리
- retention_base = data[["CustomerID", "InvoiceNo", "date_ymd"]].drop_duplicates()
- retention_base['date_ym'] = retention_base['date_ymd'].dt.to_period('M')
: 날짜 범위 수정
- print(min(data['date_ymd'].unique()))
- print(max(data['date_ymd'].unique()))
- retention_base = retention_base.query('date_ymd <= "2011-11-30"')
: 리텐션 계산
- date_ym_list = sorted(list(retention_base['date_ym'].unique()))
- from tqdm.notebook import tqdm
- retention = pd.DataFrame()
for s in tqdm(date_ym_list):
for t in date_ym_list:
period_start = s
period_target = t
if period_start <= period_target:
period_start_users = set(retention_base.query('date_ym == @period_start')['CustomerID'])
period_target_users = set(retention_base.query('date_ym == @period_target')['CustomerID'])
retained_users = period_start_users.intersection(period_target_users)
retention_rate = len(retained_users) / len(period_start_users)
temp = pd.DataFrame({'cohort':[period_start], 'date_ym':[period_target], 'retention_rate':[retention_rate]})
retention = pd.concat([retention, temp])
- retention['cohort_size(month)'] = retention.apply(lambda x: (x['date_ym'] - x['cohort']).n, axis=1)
- retention['cohort'] = retention['cohort'].astype(str)
- retention['date_ym'] = retention['date_ym'].astype(str)
- retention_final = pd.pivot_table(data=retention, index='cohort', columns='cohort_size(month)', values='retention_rate')
: 시각화
- fig = px.imshow(retention_final, text_auto='.2%', color_continuous_scale='Burg')
: 리텐션 커브
- retention_curve = retention.groupby('cohort_size(month)')[['retention_rate']].mean().reset_index()
- fig = px.line(data_frame = retention_curve, x='cohort_size(month)', y='retention_rate', title='리텐션 커브')
- fig.update_yaxes(tickformat='.2%')
EDA(, 시각화 분석(3)
RFM 분석: 고객의 행동에 따라 고객을 유형화
: Recency, Monetary 요소 기반 RM 분석
- today_date = max(data['date_ymd'])
rfm = data.groupby('CustomerID').agg({'InvoiceDate': lambda x: (today_date - x.max()).days, 'amount': lambda x: x.sum()})
* (today_date - x.max()).days, 'amount' : 오늘로부터 며칠이 지났는지
* x.sum() : 주문금액
rfm.columns = ['recency', 'monetary']
: 각 팩터를 3등급으로 나누어 등급 산정
- pd.qcut(컬럼, 등급개수, 라벨)
- pd.qcut(rfm["recency"], 5, labels=[5, 4, 3, 2, 1])
- rfm['recency_score'] = pd.qcut(rfm["recency"], 3, labels=[3, 2, 1])
- rfm['monetary_score'] = pd.qcut(rfm["monetary"], 3, labels=[1, 2, 3])
- rfm['rm_score'] = rfm['recency_score'].astype(str) + rfm['monetary_score'].astype(str)
- rfm.reset_index(inplace=True)
- rm_score = rfm.groupby('rm_score')[['CustomerID']].nunique().reset_index().rename({'CustomerID':'customer_count'}, axis=1)
- def categorize_customer(score):
if score == '33':
return '최우수' → 최신성, 구매 모두 상당히 높음
elif score in ['32','23','22']:
return '우수' → 최신성, 구매 모두 높음
elif score =='11':
return '휴면' → 최신성, 구매 모두 낮음
elif score in ['12','13']:
return '이탈 방지' → 구매는 높으나 최신성은 낮음 -> 다시 불러들어야 함
elif score in ['31','21']:
return '구매 유도' → 최신성은 높으나 구매는 낮음 -> 구매를 유도해야 함
rm_score['category'] = rm_score['rm_score'].apply(categorize_customer)
- fig = px.treemap(data_frame = rm_score, path=['category'], values='customer_count', color_discrete_sequence=px.colors.qualitative.Pastel1)
Day2
구글 뉴스 크롤링: 멀티 데이터 수집
1페이지 뉴스 다 가져오기
: 기본 서식 - browser.find_elements(By.찾는 기준, '개발자 도구 확인용 코드').~~
: .~~ 예시
- .text : 텍스트 가져오기
- get_attribute('href') : 링크 가져오기
: 기타 유용한 코드
- import time
time sleep(초)
: 코드를 n초마다 실행
- import panda as pd
df=pd.DataFrame(데이터리스트)
df.to_csv('저장이름.확장자명', 한글의 경우 encoding='euc=kr')im
: 판다스 실행 후 csv 파일로 저장
: 특수문자로 인해 csv 저장이 불가능할시 한글 encoding='utf-8-sig'
- import os
os.getcwd()
: 저장한 파일경로 확인
1~n페이지 뉴스 다 가져오기
: XPATH를 이용해 다른 페이지로 이동하기
- XPATH : 고유한 경로를 의미. 단수의 값 위주 사용.
- browser.find_element(By.XPATH, '//*[@id="botstuff"]/div/div[3]/table/tbody/tr/td[3]/a').click()
: 링크를 이용해 연속으로 다른 페이지로 이동하기
- 링크 형식
- url=https://www.google.com/search?q=검색어&start={i}
- 구글 기준 검색 결과 1페이지는 start=0, 다음페이지로 넘어갈 때마다 start는 10씩 증가
-예시
- import time
for i in range(0, 30, 10):
url= f'https://www.google.com/search?q=%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D%EA%B0%80&newwindow=1&sca_esv=fc0f42412f6fa1c1&tbm=nws&ei=m-pCZou-Geba1e8P5bKQ-Ak&start={i}&sa=N&ved=2ahUKEwjL98eCqYyGAxVmbfUHHWUZBJ84MhDy0wN6BAgDEAQ&biw=1251&bih=753&dpr=1.5'
browser.get(url)
time.sleep(3)
페이지 이동과 리스트.append를 이용하여 웹 데이터 크롤링 및 정리하기
: import time
data_list=[]
for i in range(0, 60, 10):
url= f'https://www.google.com/search?q=%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D%EA%B0%80&newwindow=1&sca_esv=fc0f42412f6fa1c1&tbm=nws&ei=m-pCZou-Geba1e8P5bKQ-Ak&start={i}&sa=N&ved=2ahUKEwjL98eCqYyGAxVmbfUHHWUZBJ84MhDy0wN6BAgDEAQ&biw=1251&bih=753&dpr=1.5'
browser.get(url)
time.sleep(3)
containers=browser.find_elements(By.CLASS_NAME, 'SoaBEf')
for i in containers:
title=i.find_element(By.CLASS_NAME, 'n0jPhd').text
storyline=i.find_element(By.CLASS_NAME, 'GI74Re').text
link=i.find_element(By.CLASS_NAME, 'WlydOe').get_attribute('href')
company=i.find_element(By.CLASS_NAME, 'MgUUmf').text
when_written=i.find_element(By.CLASS_NAME, 'OSrXXb').text
data_list.append({
'제목':title,
'내용':storyline,
'언론사':company,
'시간':when_written,
'링크':link
})
DBpia 논문 사이트 크롤링
논문사이트에서 키워드를 검색한 결과 바로가기 만들
: keyword=input('검색하려는 키워드: ')
url=f'https://www.dbpia.co.kr/search/topSearch?searchOption=all&query={keyword}'
print(url)
browser.get(url)
페이지의 링크 데이터 수집하기
: links = browser.find_elements(By.CLASS_NAME, 'thesis__link')
link_list=[]
for i in links:
link=i.get_attribute('href')
link_list.append(link)
상세페이지로 이동하기
: import time
data_list=[]
for link in link_list:
browser.get(link)
time.sleep(0.5)
논문 제목, 저자, 초록-키워드 수집:
title=browser.find_element(By.CLASS_NAME, 'thesisDetail__tit').text
authors=browser.find_element(By.CLASS_NAME,'authorList').text
try:
abstract=browser.find_element(By.CLASS_NAME, 'abstractTxt').text
except:
abstract=' '
data_list.append({
'논문 제목':title,
'논문 저자':authors,
'초록, 키워드':abstract
})
SRT 사이트 예매 시도하기
사이트 로그인(휴대전화번호 기준)
: browser.find_element(By.ID, 'srchDvCd3').click()
- 로그인 창에서 휴대폰 번호 입력 클릭
: browser.find_element(By.ID, 'srchDvNm03').send_keys('phone')
browser.find_element(By.ID, 'hmpgPwdCphd03').send_keys('pw')
browser.find_element(By.XPATH, '//*[@id="login-form"]/fieldset/div[1]/div[1]/div[4]/div/div[2]/input').click()
- 휴대폰 번호로 로그인 시도
기차 도착지 변경하기
: browser.find_element(By.ID, 'arvRsStnCdNm').click()
browser.find_element(By.ID, 'arvRsStnCdNm').clear()
browser.find_element(By.ID, 'arvRsStnCdNm').send_keys('대전')
기차 시간표, 좌석 조회하기
: browser.find_element(By.XPATH, '//*[@id="search_top_tag"]/input').click()
매진 좌석 예매 시도하기
: import time
for i in range(30):
print(f'{i}번째 시도중입니다')
arrive_btn=browser.find_element(By.XPATH, '//*[@id="result-form"]/fieldset/div[6]/table/tbody/tr[3]/td[7]/a')
if arrive_btn.text == '매진':
browser.refresh() #새로고침
time.sleep(0.3)
else:
arrive_btn.click()
Day3
구글 플레이스토어 리뷰 수집
데이터 수집 후 텍스트 마이닝
: 어플 상세 페이지 진입 후 리뷰창 클릭
- app_url=browser.find_element(By.CLASS_NAME, 'Qfxief').get_attribute('href')
- browser.get(app_url)
- browser.find_element(By.XPATH, '//*[@id="ow90"]/section/header/div/div[2]/button').click()
리뷰 닉네임, 평점, 날짜, 상세리뷰, 유용하다 평가한 사람 수 추출하기
: containers=browser.find_elements(By.CLASS_NAME, 'RHo1pe')
data_list=[]
for elem in containers:
nickname=elem.find_element(By.CLASS_NAME, 'X5PpBb').text
score=elem.find_element(By.CLASS_NAME, 'iXRFPc').get_attribute('aria-label')[10]
when=elem.find_element(By.CLASS_NAME, 'bp9Aid').text
content=elem.find_element(By.CLASS_NAME, 'h3YV2d').text
try:
liked=elem.find_element(By.CLASS_NAME, 'AJTPZc').text.split()[1][:-2]
except:
liked='0'
data_list.append({
'유저명':nickname,
'평점':score,
'작성일':when,
'내용':content,
'좋아요':liked
})
여담_자바스크립트를 활용해 스크롤하기
: modal=browser.find_element(By.CLASS_NAME, 'fysCi')
js_code='arguments[0].scrollTo(0, arguments[0].scrollHeight);'
import time
for i in range(3):
browser.execute_script(js_code, modal)
time.sleep(3)
: 많은 양의 리뷰데이터를 얻고 싶을 시 이 스크롤 코드를 먼저 실행 후 데이터 리스트를 추출해야한다
수집한 데이터를 슬랙으로 전송하기
1차로 나만의 워크스페이스(내가 모든 권한을 갖고 있는) 필요
: 워크스페이스와 api 생성 후, api에서 'Your App’s Presence in Slack' 설정
: 설정 후 Incoming Webhooks 설정
slack api로 메세지 보내기
: import requests
import json
msg='안녕하세요, 저는 봇입니다.'
slack_url='https://hooks.slack.com/services/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'
payload={
'text': msg
}
response=requests.post(
slack_url,
data=json.dumps(payload),
headers={'Content-type': 'application/json'}
)
print(response)
: import requests는 url을 요청, import json은 딕셔너리를 제이슨으로 변경해줌
: requests에는 .get, .post, .put, .delete 등 다양한 method 사용 가능
특정 사이트의 표 데이터 수집
: 기본 세팅
import pandas as pd
import io
import requests
url = 'https://finance.naver.com/'
: URL에서 HTML 페이지를 요청하여 가져오는 코드
response = requests.get(url)
response.encoding = 'euc-kr' # 인코딩을 맞춰줍니다.
: HTML 콘텐츠를 StringIO 객체로 감싸는 코드
html = io.StringIO(response.text)
: HTML 테이블을 읽는 코드
dfs = pd.read_html(html, encoding='euc-kr')
: 필요한 데이터프레임을 선택하는 코드
df = dfs[1]
print(df)
여담_크롤링한 데이터 사용의 법적 이슈
: robots.txt
- 웹 로봇을 제어하기위한 규칙
- 웹 크롤링의 허용 범위 명시
: (1) 모든 문서에 대해 접근 허용
- User-agent: *
- Allow: /
: (2) 모든 문서에 대해 접근 불허
- User-agent: *
- Disallow: /
: (3) 모든 문서에 대해 접근 불허하나 첫 번째 페이지만 허용
- User-agent: *
- Disallow: /
- Allow : /$
*주의: robots.txt가 법적 보장을 받는 것은 아니나 데이터 활용도에 따라 법적 분쟁이 있을 수 있다.
파이썬을 이용한 데이터 분석 기초
데이터 사이언스 영역
: 데이터 분석가
- 데이터에서 인사이트를 뽑아내는 역할
- 통계지식이 필요+도메인(메인)+데이터+분석스킬
- pm으로서의 DS 혹은 데이터 분석가
- 성과 측정 지표 정의, MECE 기법(분석방법론), 결제전환율 개선, 데이터 로그 설계, AB테스트
- 마케터로서의 DS 혹은 데이터 분석가
: 데이터 엔지니어링
- 데이터를 수집 및 저장하는 역할(빅데이터 시스템 구축)
- 기존 백엔드 엔지니어 분들이 Hadoop에 대한 이해를 바탕으로 커리어 전환
: Data Visualization
- 데이터를 시각화
- 기존 프론트엔드 엔지니어가 많이 포진
대표적인 데이터 분석 패키지
: 대화형 파이썬 툴 (Jupyter - Colab)
: 통계 및 수학적 계산을 도와주는 라이브러리 (Numpy)
: 데이터 핸들링(엑셀) - 데이터 정제, 전처리 (Garbage in Garbage out)
- Pandas / SQL / 테블로
: 데이터 시각 (설득, 데이터의 숨겨진 패턴 발견)
- Matplotlib ⇒ Seaborn ⇒ Plotly
: 머신러닝 / 딥러닝 → 미래를 예측하기 위해서 활용하여 패턴 찾기
⇒ 어떤 결과를 분석(연구)해서 결과를 내놓았다고 해봅시다.
⇒ 그 다음 사람들의 반응은 뭘까요? ⇒ 잘봤습니다. 그래서 앞으로는 어떻게 되나요? (예측)
- Scikit-learn
- Tensorflow
- Keras
Numpy
: 수학 및 과학 연산을 위한 파이썬 패키지
: 벡터 및 행렬을 사용하느 선형 대수 계산에 주로 사용
: 순수 파이썬에 비해 속도가 빠름
: 설치
- !pip install numpy
- import numpy as np
: 기본 문법
- array1=np.array([1, 2, 3]) : 1차원 배열
- array2=np.array([[1,2,3], [4,5,6]]) : 2차원 배열
- array2.shape : (2, 3)이란 값이 나오며 2행 3열을 의미
- array2.ndim : 차원(1차원, 2차원 등) 표시
- array2.dtype : 데이터 타입 표기
- arr.astype('int64') : 데이터 타입 변환
- np.sort(arr) : 데이터 정렬
Pandas
: panel data analysis의 줄임말
: 데이터 조작 및 분석을 위한 파이썬 패키지
: 테이블 형태의 데이터를 다루는 DataFrame(=Excel, CSV) 제공
: SQL과 같은 데이터 생성, 조회, 분석, 삭제, 수정 등의 작업이 가능
- CRUD : Create, Read, Update, Delete 외의 다른 행위는 없음
: Numpy 기반에서 개발
: 대용량 데이터를 다룰 때 속도가 빠름
: 설치
- !pip install pandas
- import pandas as pd
: 기본 문법
- pd.Series(data)
- se.name : 이름 붙이기. 인덱스에도 명칭 붙이기 가능
- se[0:3] : 레인지 설정 가능
DataFrame
: pandas에서 사용하는 데이터프레임
- data = {
'country':['kor','usa','china','japan'],
'rank':[1,2,3,4],
'grade':['A','B','C','D']}
- pd.DataFrame(data)
- df.set_index(['country', 'rank'])
Read(데이터 셀렉션)
: df.컬럼명 = df['컬럼명']
: df.loc[인덱스값, 컬럼명]
: df.iloc[인덱스값, 컬럼인덱스]
- 위치(숫자) 기반으로 값 추출
- loc는 [0:2]라고 입력하면 0~2의 인덱스값을 추출하지만, iloc은 0~1까지의 값을 추출
Create(행 또는 열 데이터를 추가하는 방법)
: 열 데이터 추가
- president=pd.Series(['A','B',C','D'])
df['president']=president
- df['gdp']=[1000,2000,3000,4000]와 같이 리스트를 바로 추가하는 것도 가능
- 파생컬럼
- df['new_gdp']=df['gdp']>=3000
: 행 데이터 추가
- df.loc[4]=['singapole',2,'B','Tharman',3500,True]
: 행 열 데이터 삭제
- df.drop('new_gdp',axis=0 or 1)
- 셀이 실제로 지워진 것은 아니고 보이지 않게만 한 것
- 완전히 지우고 싶다면 inplace=True를 추가로 삽입함
- 그러나 만일을 위해 inplace는 사용 비추천
: 예시
- df.drop([0,1]) : 0행에서 1행의 데이터 삭제
집합함수(aggregation)
: 기술통계 데이터
- df.sum()
df.mean(numeric_only=True)
df.max()
df.min()
- df.describe() : 숫자값의 카운트, 평균, 표준편차, 최솟값, 4분위값, 최댓값 표기
- df.sort_values(by=['gdp','grade'], ascending=[False, True]) : 정렬
: NaN데이터는 어떻게 처리할 것인가
- NaN이 포함된 컬럼 혹은 행 데이터를 제거 후 분석
- df.dropna()
- 적절한 값을 채워넣은 뒤 분석
- df.fillna()
- df.isna() : NaN이 있는지 확인
연습문제
: 전체 데이터 중에서 '영화' 정보만 출력하시오.
- df['영화']
: 전체 데이터 중에서 '영화','평점' 정보를 출력하시오.
- df[['영화','평점']]
: 3) 2015년 이후에 개봉한 영화 데이터 중에서 '영화','개봉연도' 정보를 출력하시오.
* (0) 개봉 연도
* (1) 2015년 이후에 개봉한 영화
* (2) 추출한 데이터에서 컬럼값이 '영화', '개봉연도' 인 데이터를 출력한다.
- df_2015=df.loc[df['개봉 연도']>=2015]
- df_2015[['영화','개봉 연도']]
: 4) 주어진 계산식을 참고하여 '추천 점수' Column을 추가하시오.
* 추천 점수 = (관객수 * 평점) // 100
- df['추천 점수']=df['관객 수']*df['평점']//100
: 5) 전체 데이터를 '개봉연도' 기준 내림차순으로 출력하시오
- df.sort_values(by='개봉 연도', ascending=False)
Day4
CH03. 파이썬 데이터 분석 프로젝트 - 실습4. 사용자 행동 로그 데이터를 활용한 퍼널 분석
데이터 둘러보기&질문 만들기
: 데이터 살펴보기
: 질문 만들기
- DAU 추이는 어떤지, 어느 요일에가장 많이 방문하는지
- 사이트 평균 체류시간은 어떤지
- 조회만 한 유저, 카트에 담은 유저, 구매한 유저별로 체류시간이 어떻게 다른지
- 퍼널 분석. 어느 단계에서 유저들이 가장 많이 이탈하는지
: 데이터 전처리
: 데이터 분석
데이터 전처리하기
: 날짜의 데이터 타입을 datetime64[ns]로 변경
: 결측치 제거
- 카테고리와 브랜드에 너무 많은 결측치가 있고, 카테고리 및 브랜드 별로 분석할 계획이 없기 때문에 해당 컬럼 제거
- 날짜 컬럼 추가 및 타입 변경
- data['date_ymd']=data['event_time'].dt_date
- data['date_ymd']=pd.to_datetime(data['date_ymd'], format='%Y-%m-%d')
DAU 추이
: 어느 요일에 가장 많이 방문하는가
- dau=data.groupby('date_ymd')[['user_id']].nunique().reset_index().rename({'user_id':'dau'}, axis=1)
: 라인그래프로 시각화 및 추이 확인
- fig=px.line(data_frame=dau, x='date_ymd', y='dau', title='DAU 추이')
: 요일 별 추이 확인
- dau['day_of_week']=dau['date+ymd'].dt.day_name()
- dau['day_of_week1']=dau['date_ymd'].dt.day_of_week
- avg_dau_by_dow=dau.groupby(['day_of_week', 'day_of_week1']).mean().reset_index()
- avg_dau_by_dow.sort_values('day_of_week1', inplace=True)
: 요일 별 추이 시각화
- px.bar(data_frame=avg_dau_by_dow, x='day_of_week', y='dau', title='요일별 DAU 평균')
사이트 평균 체류시간
: 체류시간의 정의(한 세션의 끝에서 시작시간을 뺀 값)
- 유저 세션 별로 순서 정돈 후 이벤트 타임 최댓값에서 최솟값을 뺀다
- duration=data.groupby('user_session)[['event_time']].agg(max, min).reset_index()
- duration['duration']=duration['event_time']['max']-duration['event_time']['min']
- duration_columns=['user_session', 'max', 'min', 'duration]
: 체류시간 평균 구하기
- duration['duration'].mean()
: 조회만 한 유저, 카트에 담은 유저, 구매한 유저 별 체류 시간
- session_pivot=pd.pivot_table(data=data, index='user_session', columns='event_type', values='event_time', aggfunc='count').reset_index().fillna(0)
- cart_session=list(session_pivot.query('cart'>0)['user_session'])
- purchase_session=list(session_pivot.query('purchase'>0)['user_session'])
- view_session_avg_duration=duration.query('user_session not in @ cart_session and user_session not in @ purchase_session')['duration'].mean()
- cart_session_avg_duration=duration.query('user_session in @ cart_session')['duration'].mean()
- purchase_session_avg_duration=duration.query('user_session in @ purchase_session')['duration'].mean()
퍼널 분석
: 어느 단계에서 유저들이 가장 많이 이탈하는가
- funnel=funnel.session_pivot[['view', 'cart', 'remove_from_cart', 'purchase']].sum().to_frame().reset_index()
- funnel.columns['event_type', 'count']
- funnel=funnel.query['event_type!="remove_from_cart" ']
- fig=px.funnel(data_frame=funnel, x='event_type', y='count')
- fig.update_traces(texttemplate="%{value:,.0f}")
: 뷰에서 다음 단계로 넘어간 정도
- view_to_cart_rate=list(funnel['count'])[1]/list(funnel['count'])[0]
- view_to_purchase_rate= list(funnel['count'])[2]/list(funnel['count'])[0]
- funnel['retain_rate']=[1, view_to_cart_rate, veiw_to_purchase_rate]
- fig=px.funnel(data_frame=funnel, x='event_type', y='retain_rate')
- fig.update_traces(texttemplate="%{value:,.2%}")
* fig.update_traces(texttemplate="%{value:,.n}") : 시각화 자료에서 숫자를 소숫점 n자리까지 표기함
CH03.파이썬 데이터 분석 프로젝트 - 실습5. 교통 데이터를 활용한 지리 데이터 시각화
데이터 둘러보기_질문 만들기
: 데이터 살펴보기
- 서울시 지하철 승하차인원의 월별 합계
- 2018년 이후, 2호선만, 승차 인원만 분석 예정
: 질문 만들기
- 승차인원이 가장 많은 역
- 연도 혹은 월별 승차 인원 추이의 차이
- 시간대별 승차인원이 가장 많은 역
- 지하철역 시간대별 인원 유형 군집화
- 지도에 분석 결과 시각화
: 데이터 전처리
: 분석
데이터 전처리하기
: 날짜 컬럼 추가
- data['연도']=pd.to_datetime(data['사용월'], format=%Y%m).dt.year
- data['월']=pd.to_datetime(data['사용월'], format=%Y%m).dt.month
: 2018년 이후 2호선만 필터링
- data=data.query('호선명=="2호선" and 연도>=2018')
: 지하철역명 통일
- sorted(data['지하철역'].unique())
- data['지하철역']=[i[0] for i in data['지하철역'].str.split('(')]
- sorted(data['지하철역'].unique())
: 승차인원만 추출하기
- on_col=[i for i in data.columns if '승차' in i]
- data=data[['사용월', '연도', '월', '지하철역']+on_col]
승차 인원이 가장 많은 역
: 합계 컬럼 만들기
- data['합계']=data[on_col].sum(axis=1)
: 지하철역별 월평균 승차 인원 구하기
- data_mean=data.groupby('지하철역')[['합계']].mean().reset_index().rename({'합계':'월평균'}, axis=1).sort_values('월평균', ascending=False)
- fig=px.bar(data_frame=data_mean, x='지하철역', y='월평균', title='지하철역별 월평균 승차인원')
연도별로 혹은 월별로 승차 인원 추이의 차이
: 연도별 추이
- year_sum=data.query('연도'<=2022).groupby('연도')[['합계']].sum().reset_index()
- year_sum['연도']=year_sum['연도'].as_type(str)
- fig=px.line(data_frame=year_sum, x='연도' y='합계')
: 월별 추이
- month_sum=data.query('월'<=2022).groupby('월')[['합계']].sum().reset_index()
- year_sum['월]=year_sum['월'].as_type(str)
- fig=px.line(data_frame=year_sum, x='' y='합계')
시간대별 승차인원이 가장 많은 역
: 월평균 승차인원이 가장 많은 역 상위 10개
- top10=data_mean.sort_values('월평균', ascending=False).head(10)['지하철역']
: 주요 역 10개를 기준으로 시간당 월평균 인원수 구하기
- top10_mean_hour=data.query('지하철역' in @top10).groupby('지하철역')[on_col].mean()
- top10_mean_hour.columns=[i[:3] for i in top10_mean_hour.columns]
- 시각화를 위해 시간 컬럼에서 앞 세글자만 꺼내옴
: 전체 기준 히트맵
- top10_mean_hour.style.background_gradient(cmap='pink_r', axis=None).format('{:.0f}')
: 행 기준 히트맵
- top10_mean_hour.style.background_gradient(cmap='pink_r', axis=1).format('{:.0f}')
지하철역 시간대별 인원 유형 군집화
: 승차 인원으로 유형 군집화
- hour_mean=data.groupby('지하철역').[on_col}.mean()
- hour_mean.columns= [i[:3] for i in hour_mean.columns]
- hour_mean.pct= hour_mean.div( hour_mean.sum(axis=1), axis=0)
- from sklearn.cluster import KMeans
from yellowbrick.cluster import KElbowVisualizer
model = KMeans()
visualizer = KElbowVisualizer(model, k=(1,10))
visualizer.fit(hour_mean_pct)
- k = 3
model = KMeans(n_clusters = k, random_state = 10) : KMeans 모델을 정의
model.fit(hour_mean_pct) : 학습
hour_mean_pct['cluster'] = model.fit_predict(hour_mean_pct).astype(str) : 클러스터 열 만들기
: 시각화
- fig=px.scatter(data_frame=hour_mean_pct[['08시', '18시', 'cluster']].reset_index(), x='08시', y='18시', color='cluster', title='시간대별 승차 인원 비중 군집화, hover_name='지하철역')
: 클러스터 별 역 확인
- for i in range(k):
print(f'cluster {i}')
print(list(hour_mean_pct.query(f'cluster == "{i}"').index))
지도에 분석 결과 시각화
: 2호선 역사별 위도 경도 정리
- coordinate=coordinate.query('호선=="2호선" ')
- coordinate['역사명']=[i[0] fo i in coordinate['역사명'].str.split('(')]
- coordinate.rename({'역사명':'지하철역'}, axis=1, inplace=True)
: 역사별 8시와 18시 승차 인원 정리
- hour_mean_merge = hour_mean.reset_index()[['지하철역','08시','18시']]
- coordinate_merge = coordinate[['지하철역','위도','경도']]
- hour_mean_coor = pd.merge(hour_mean_merge, coordinate_merge, on='지하철역')
- hour_mean_coor['cluster'] = model.fit_predict(hour_mean_pct).astype(str)
: 지도에 시각화(08시 기준)
- import folium
from folium import plugins
- center = [37.541, 126.986] : 서울 중간
m = folium.Map(location=center, zoom_start=12)
m.add_child(plugins.HeatMap(zip(hour_mean_coor['위도'], hour_mean_coor['경도'], hour_mean_coor['08시'])))
: 승차 인원 유형 시각화
- m = folium.Map(location=center, zoom_start=12)
for idx in hour_mean_coor.index:
lat = hour_mean_coor.loc[idx, '위도']
long = hour_mean_coor.loc[idx, '경도']
title = hour_mean_coor.loc[idx, '지하철역']
if hour_mean_coor.loc[idx, 'cluster'] == "0":
color = '#000000'
elif hour_mean_coor.loc[idx, 'cluster'] == "1":
color = '#3A01DF'
else:
color = '#DF0101'
folium.CircleMarker([lat, long]
, radius=18
, color = color
, fill = color
, tooltip = title).add_to(m)
CH03. 파이썬 데이터 분석 프로젝트 - 실습6. 직접 크롤링하기 - 부동산 데이터 분석을 통해 최적의 자취방 구하기
크롤링하기&질문만들기
: 크롤링하여 1페이지에서 100페이지까지의 부동산 정보 크롤링하기
- article_list = []
for i in tqdm(range(1, 101)):
try:
url = f'https://m.land.naver.com/cluster/ajax/articleList?itemId=&mapKey=&lgeo=&showR0=&rletTpCd=OPST%3AVL%3AOR&tradTpCd=B2&z=12&lat=37.481021&lon=126.951601&btm=37.3398975&lft=126.6762562&top=37.6218785&rgt=127.2269458&totCnt=8360&cortarNo=1162000000&sort=rank&page={i}'
user_agent = generate_user_agent()
headers = {'User-Agent':user_agent}
res = requests.get(url, headers=headers)
time.sleep(1)
article_json = res.json()
article_body = article_json['body']
article_list.append(article_body)
except:
break
: 질문 만들기
- 최적의 자취방 구하기
- 보증금 3000만 이하
- 월세는 저렴할수록 좋음
- 지하, 반지하, 꼭대기 x
- 전용면적이 클수록 좋음
- 북향x
- 연식이 오래되지 않을수록 좋음
- 지하철역에서 가까울수록 좋음
: 데이터 전처리
: 분석
데이터 전처리하기
: 월세 0원인 경우 제외
- data=data.query('월세>0')
: 보증금은 숫자로 변환
- data['보증금'].unique()
- data=data.query('~보증금.str.contains("억")')
- data=data.query('보증금.str.contains("억") == False')로도 사용 가능
*~보증금.str.contains("억") : 억대의 보증금 쿼리는 제외함
- data['보증금]=data['보증금].str.replace(',','').astype(int)
: 물건층과 전체층 분리 후 1층과 꼭대기층 유무 컬럼 만들기
- 지하의 경우 마이너스로 표시
- data[['물건층','전체층']] = data['층수(물건층/전체층)'].str.split('/', expand=True)
- def floor_info(target, total):
try:
if target in ['B1','B2']: #지하이면
return 'y'
elif int(target) == 1 or int(target)/int(total) == 1: #1층이거나 꼭대기층이면
return 'y'
else:
return 'n'
except ValueError:
return 'n'
- data['비선호층여부'] = data.apply(lambda x: floor_info(x['물건층'], x['전체층']), axis=1)
: 완전히 제외할 수 있는 조건은 일차적으로 제외
- data_filtered = data.query('300 <= 보증금 <= 3000 and 비선호층여부 == "n" and 전체층 != "1" and ~방향.str.contains("북")')
: 연식 컬럼 추가
- data_filtered[['tag1','tag2','tag3','tag4']] = data_filtered['태그'].str.replace("\'|\[|\]","").str.split(', ', expand=True)
- data_filtered = data_filtered.query('tag1.str.contains("년")') : 연식 정보가 있는 데이터만 필터링
- data_filtered['연식'] = [int(i[0]) for i in data_filtered['tag1'].str.replace("['","").str.split('년')]
: 필요한 컬럼만 남기기
- data_filtered = data_filtered[['물건번호','월세','보증금','전용면적(m2)','방향','위도','경도','물건층','전체층','연식']]
: 위도 경도를 이용하여 역까지의 거리 재기
- coordinate = pd.read_csv('/content/drive/MyDrive/서울시 역사마스터 정보.csv의 사본', encoding='cp949')
coordinate = coordinate.query('호선 == "2호선"')
station_list = ['신대방', '신림', '봉천', '서울대입구(관악구청)', '낙성대', '사당']
coordinate.query('역사명 in @station_list')
- def distance(station_name, lat, long):
station_lat = coordinate.query(f'역사명 == "{station_name}"')['위도'].values[0]
station_long = coordinate.query(f'역사명 == "{station_name}"')['경도'].values[0]
distance = haversine((station_lat, station_long), (lat, long), unit = 'm')
return distance
- for s in station_list:
data_filtered[s] = data_filtered.apply(lambda x: distance(s, x['위도'], x['경도']), axis=1)
- data_filtered['역까지최소거리'] = data_filtered.apply(lambda x: min([x['신대방'], x['신림'], x['봉천'], x['서울대입구(관악구청)'], x['낙성대'], x['사당']]), axis=1)
- data_filtered.drop(station_list, axis=1, inplace=True)
데이터 분석
: 각 항목 분포 확인하기
- for x in ['월세','보증금','전용면적(m2)','연식','역까지최소거리']:
fig = px.box(data_frame = data_filtered, x=x, width=700, height=400)
: 월세, 전용면적, 연식, 지하철까지의 거리 점수 매기기
- data_filtered['월세_등급'] = pd.qcut(data_filtered['월세'], 5, labels=[1,2,3,4,5])
- data_filtered['전용면적_등급'] = pd.qcut(data_filtered['전용면적(m2)'], 5, labels=[5,4,3,2,1])
- data_filtered['연식_등급'] = pd.qcut(data_filtered['연식'].rank(method='first'), 5, labels=[1,2,3,4,5])
- data_filtered['역까지최소거리_등급'] = pd.qcut(data_filtered['역까지최소거리'], 5, labels=[1,2,3,4,5])
- data_filtered_final = data_filtered.query('월세_등급 <= 3 and 전용면적_등급 <= 1 and 연식_등급 <= 2 and 역까지최소거리_등급 <= 2')
: 최종 매물 리스트 시각화
- f = folium.Figure(width=700, height=500)
m = folium.Map(location=[37.486313, 126.935378], zoom_start=14).add_to(f)
for idx in data_filtered_final.index:
lat = data_filtered_final.loc[idx, '위도']
long = data_filtered_final.loc[idx, '경도']
num = data_filtered_final.loc[idx, '물건번호']
folium.Marker([lat, long]
, popup=f"<a href=https://m.land.naver.com/article/info/{num}>링크</a>"
).add_to(m)
'스터디' 카테고리의 다른 글
[7주차]SQL 입문 (0) | 2024.06.07 |
---|---|
[5주차] 파이썬 실습2 및 1차 미니 프로젝트 (0) | 2024.05.24 |
[3주차] 파이썬 기초 (0) | 2024.05.10 |
[2주차] 엑셀을 통한 통계 및 데이터 분석, 파이썬 입문 (1) | 2024.05.03 |
[1주차] 데이터 분석과 빅데이터, 엑셀 (0) | 2024.04.26 |