촉촉한초코칩

[부스트코스] 데이터 사이언스 (3) 본문

Study/Big Data

[부스트코스] 데이터 사이언스 (3)

햄친구베이컨 2023. 3. 22. 14:04

공공데이터 상권정보 분석

 

필요한 라이브러리 불러오기 (pandas, numpy, seaborn)

 

import pandas as pd   #엑셀
import numpy as np    #수치 계산
import seaborn as sns #시각화

 

시각화를 위한 폰트 설정 (matplotlib.pyplot)

 

import matplotlib.pyplot as plt
#Window 한글 폰트 설정
plt.rc('font', family='Malgun Gothic')
#Mac 한글 폰트 설정
# plt.rc('font', family='AppleGothic')
# plt.rc('axes', unicode_minus=False)  #한글 폰트 깨지는 것 방지 

#그래프가 노트북 안에 보이게 하기 위해
%matplotlib inline

 

데이터 로드하기 (read_csv, shape)

 

  • 판다스에서 데이터를 로드할 때는 read_csv를 사용한다.
  • 데이터를 로드해서 df라는 변수에 담는다.
  • shape를 통해 데이터 갯수를 찍는다.
  • 결과는 (행, 열) 순서로 출력된다.
df = pd.read_csv("/data.csv")
df.shape
df = pd.read_csv("/content/drive/MyDrive/Colab Notebooks/hospitalList.csv", encoding="cp949")
df.shape

 

데이터 미리보기 (head, tail, sample)

 

df.head()

#tail > 마지막에 있는 데이터 불러오기
df.tail(1)

df.sample()

 

데이터 요약하기 (info, columns, dtypes)

 

#info
df.info()

#컬럼명만 출력
df.columns

#데이터 타입만 출력
df.dtypes

 

결측치 (isnull, plot)

 

  • 데이터가 null값인지 아닌지 
#false > 값이 있음
#true > 값이 없음 (null)
df.isnull()

#결측치가 몇개 있는지
null_count = df.isnull().sum() 
null_count

#결측치를 plot.bar를 통해 막대그래프로 표현하기
null_count.plot()

null_count.plot.barh(figsize=(5,7))

#dataframe형태로 변환 
df_null_count = null_count.reset_index()
df_null_count

 

* 내가 가져온 데이터는 결측치가 없음

 

칼럼명 변경하기 (columns)

 

df_null_count.columns = ["컬럼명", "결측치 수"]
df_null_count

 

정렬하기 (sort_values)

 

  • 데이터프레임에 있는 결측치수 칼럼을 sort_values를 통해 정렬
  • 데이터프레임에 있는 칼럼으로 by를 써야 한다. 
#결측치가 많은 순으로 상위 10개만 출력하기
df_null_count_top = df_null_count.sort_values(by="결측치 수", ascending=False).head(10)
df_null_count_top

 

특정 컬럼만 불러오기 (tolist, head)

 

  • NaN == Not a Number = 결측치
df["지점명"]

drop_columns = df_null_count_top["컬럼명"].tolist()
drop_columns

df[drop_columns].head()

 

제거하기 (drop)

 

#결측치 제거하기
print(df.shape)
df = df.drop(drop_columns, axis=1) #칼럼 기준 > 1, 행 기준 > 0 
print(df.shape)

#제거한 후 확인
df.info()

 

기초 통계값 보기 (mean, median, max, min, count, describe, unique, nunique)

 

#평균값
df["위도"].mean()

#중앙값
df["위도"].median()

#최댓값
df["위도"].max()

#최소값
df["위도"].min()

#개수
df["위도"].count()

#기초통계값 요악하기 > describe
df["위도"].describe()

#2개의 컬럼 요약하기 > list 형태로 가져와야 한다. 
df[["위도","경도"]].describe()

#문자열 데이터타입 요약보기
df.describe(include="object")
#freq : 빈도수 

#중복 제거한 값 보기
#unique로 중복을 제거한 값을 보고 nuniue로 개수를 세어본다.
df["상권업종대분류명"].unique()
df["상권업종대분류명"].nunique()

df["상권업종중분류명"]
df["상권업종중분류명"].unique()
df["상권업종중분류명"].nunique()

df["상권업종소분류명"]
df["상권업종소분류명"].unique()
df["상권업종소분류명"].nunique()

#len
len(df["상권업종소분류명"].unique())

 

그룹화된 요약값 보기 (value_counts)

 

#그룹화된 요악값 보기 > value_counts (카테고리 형태의 데이터 갯수를 세어볼 수 있다.)
df["시도명"].head()

#시도명 세어보기
city = df["시도명"].value_counts()
city 

#normalize=True 옵션을 사용해서 비율 구하기
city_normalize = df["시도명"].value_counts(normalize=True) 
city_normalize

#Pandas는 plot 기능을 내장하고 있음
#시도명 수를 막대그래프로 표현하기
city.plot.line
city_normalize.plot.pie(figsize=(7,7))
city.plot.pie(figsize=(7,7))
city_normalize.plot.line

 

* 지역을 기준으로 하면 너무 많아서 그래프에 다 담기지 않음
기준을 세세하게 정해야 할 듯

* groupby 참고 : 04.3.6.2. GroupBy - 파이썬을 활용한 회계프로그래밍 (wikidocs.net)

 

city = df.groupby(["지역"]).value_counts()
city

 

seaborn 으로 빈도수 시각화 하기

 

#seaborn의 countplot으로 그려보기
sns.countplot(data=df, x="시도명")
sns.countplot(data=df, y="시도명")

#상권업종대분류명으로 갯수 세어보기
df["상권업종대분류명"].value_counts()
#normalize=True 사용해서 비율 구하기
df["상권업종중분류명"].value_counts(normalize=True)

#판다스의 plot.bar()을 사용해서 막대그래프 그려보기
c.plot.bar(rot=0) #rot = 0 : rotation(얼만큼 글자를 회전시킬 것인지)
#판다스의 plot.pie() 사용해서 파이그래프 그려보기
n.plot.pie()

#상권업종소분류명에 대한 그룹화된 값 카운트
c = df["상권업종소분류명"].value_counts()

#상권업종소분류명으로 갯수 세어보기
#판다스의 plot.bar() 사용해서 막대그래프 그려보기
c.plot.bar(figsize=(7,8), grid=True) #figsize : 글자크기, grid : 격자

 

* 지역을 기준으로 하면 너무 많아서 그래프에 다 담기지 않음
기준을 세세하게 정해야 할 듯

#seaborn의 countplot으로 그려보기
sns.countplot(data=df, x="지역")
sns.countplot(data=df, y="지역")

#상권업종대분류명으로 갯수 세어보기
df["병상수"].value_counts()
#normalize=True 사용해서 비율 구하기
df["진료과수"].value_counts(normalize=True)

#판다스의 plot.bar()을 사용해서 막대그래프 그려보기
c.plot.bar(rot=0) #rot = 0 : rotation(얼만큼 글자를 회전시킬 것인지)
#판다스의 plot.pie() 사용해서 파이그래프 그려보기
n.plot.pie()

#상권업종소분류명에 대한 그룹화된 값 카운트
c = df["연번"].value_counts()

#상권업종소분류명으로 갯수 세어보기
#판다스의 plot.bar() 사용해서 막대그래프 그려보기
c.plot.bar(figsize=(7,8), grid=True) #figsize : 글자크기, grid : 격자

 

원하는 데이터만 따로 추출해 오기 - 데이터 색인하기

 

#상권업종중분류명이 약국/한약방이 데이터만 가져와서
#df_medical 변수에 담기
df_medical = df[df["상권업종중분류명"] == "약국/한약방"].copy()
df_medical.head()

#상권업종대분류명에서 의료만 가져오기
#df.loc를 사용하면 행, 열을 함께 가져올 수 있다. 
#가져온 결과를 value_counts를 사용해서 중분류의 개수를 세어본다.
df.loc[df["상권업종대분류명"] == "의료","상권업종중분류명"].value_counts()

m = df["상권업종대분류명"] == "의료"
df.loc[m, "상권업종중분류명"].value_counts()

#유사의료업만 따로 모아본다.
df[df["상권업종중분류명"] == "유사의료업"].shape

#상호명 그룹화해서 개수 세어보기
#value_counts 사용해서 상위 10개를 출력한다.
#하위 10개 > tail
df["상호명"].value_counts().head(10)

#df_medi 변수에서 상호명으로 갯수 세어보기
#가장 많은 상호 상위 10개 출력
df_medi["상호명"].value_counts().head(10)

 

여러 조건으로 색인하기 

 

#상권업종소분류명이 약국인 것과
#시도명이 서울특별시인 데이터 가져오기
df_seoul_dr = df[(df["상권업종소분류명"] == "약국") & (df["시도명"] == "서울특별시")]
print(df_seoul_dr.shape)
df_seoul_dr

#위에서 색인한 데이터로 '시군구명'으로 그룹화해서 개수 세어보기
#구별로 약국이 몇 개 있는지 확인한다.
c = df_seoul_dr["시군구명"].value_counts()
c.head()

#normalize=True 통해서 비율 구해보기
n = df_seoul_dr["시군구명"].value_counts(normalize=True)
n.head()

#상권업종소분류명이 종합병원인것과
#시도명이 서울특별시인 데이터 가져오기
# df_seoul_hospital에 할당해서 재사용한다. 
#copy하지 않고 할당하게 되면 df_seoul_hospital 값이 바뀌면 df의 데이터 값도 변경될 수 있다.
df_seoul_hospital = df[(df["상권업종소분류명"] == "종합병원") & (df["시도명"] == "서울특별시")].copy()
df_seoul_hospital

#시군구명으로 그룹화해서 구별로 종합병원의 수를 세어보기
df_seoul_hospital["시군구명"].value_counts()

 

텍스트 데이터 전처리하기

 

#텍스트 데이터 색인하기 전에 상호명 중 종합병원이 아닌 데이터 찾기
# ~ : 아닌 것 찾기
df_seoul_hospital[~df_seoul_hospital["상호명"].str.contains("종합병원")]
df_seoul_hospital.loc[~df_seoul_hospital["상호명"].str.contains("종합병원"),"상호명"].unique()

#상호명에서 특정 단어가 들어가는 데이터만 가져오기
df_seoul_hospital[df_seoul_hospital["상호명"].str.contains("꽃배달")]
#상호명에서 특정 단어가 들어가는 데이터만 가져오기 - 의료기
df_seoul_hospital[df_seoul_hospital["상호명"].str.contains("의료기")]

#꽃배달|의료기|장례식장|상담소|어린이집
#정러리를 위해 해당 텍스트를 한 번에 검색한다. 
#제거할 데이터의 인덱스만 drop_row에 담아주고 list 형태로 변환한다.
drop_row = df_seoul_hospital[df_seoul_hospital["상호명"].str.contains("꽃배달|의료기|장례식장|상담소|어린이집")].index
drop_row = drop_row.tolist()
drop_row

#의원으로 끝나는 데이터도 인덱스를 찾아서
#drop_row2에 담아주고 list 형태로 변환한다. 
drop_row2 = df_seoul_hospital[df_seoul_hospital["상호명"].str.endswith("의원")].index
drop_row2 = drop_row2.tolist()
drop_row2

#삭제할 행을 drop_row에 합쳐준다.
drop_row = drop_row + drop_row2
len(drop_row)

#해당 셀을 삭제하고 삭제 전과 후의 행 개수를 비교한다.
print(df_seoul_hospital.shape)
df_seoul_hospital = df_seoul_hospital.drop(drop_row, axis=0)
print(df_seoul_hospital.shape)

#시군구명에 따라 종합병원이 숫자를 countplot으로 그린다.
df_seoul_hospital["시군구명"].value_counts().plot.bar()
plt.figure(figsize=(15,4))
sns.countplot(data=df_seoul_hospital, x="시군구명", order=df_seoul_hospital["시군구명"].value_counts().index)

 

위경도 데이터 scatterplot 으로 표현하기

 

#Pandas의 plot.scatter를 통해 경도와 위도 표시하기
df_seoul[["경도","위도","시군구명"]].plot.scatter(x="경도",y="위도", figsize=(8,7),grid=True)

#seaborn의 scatterplot을 통해 구별 위도와 경도 표시하기
plt.figure(figsize=(9,8))
sns.scatterplot(data=df_seoul, x="경도", y="위도", hue="시군구명")

#seaborn의 scatterplot을 통해 상권업종중분류명 경도와 위도 표시하기
plt.figure(figsize=(9,8))
sns.scatterplot(data=df_seoul, x="경도", y="위도", hue="상권업종중분류명")

#seaborn의 scatterplot을 통해 전국 데이터(df)로 구별 위도와 경도 표시하기
plt.figure(figsize=(16,12))
sns.scatterplot(data=df[:1000], x="경도", y="위도", hue="시도명")

 

folium 으로 위경도와 주소 데이터를 활용해 지도에 표현하기

 

Anaconda Prompt에서 conda install -c conda-forge folium 명령어를 실행해 folium을 설치한다. 

#folium : 지도 시각화를 위한 라이브러리
import folium

#지도 중심을 지정하기 위해 위도와 경도의 평균을 구한다.
df_seoul_hospital["위도"].mean()
df_seoul_hospital["경도"].mean()
folium.Map(location=[df_seoul_hospital["위도"].mean(), df_seoul_hospital["경도"].mean()], zoom_start=12)

map = folium.Map(location=[df_seoul_hospital["위도"].mean(), df_seoul_hospital["경도"].mean()], zoom_start=12)

for n in df_seoul_hospital.index:
  name = df_seoul_hospital.loc[n, "상호명"]
  address = df_seoul_hospital.loc[n, "도로명주소"]
  popup = f"{name}-{address}"
  location = [df_seoul_hospital.loc[n, "위도"], df_seoul_hospital.loc[n, "경도"]]
  folium.Marker(
      location=location,
      popup = popup,
  ).add_to(map)
map