ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬으로 시작하는 데이터 사이언스 - 4. 데이터 전처리
    공부일기/부스트코스 2020. 11. 24. 19:02

    앞서 사용한 csv파일을 그대로 사용해 서울에 위치한 종합병원만을 찾아보자.

     

    • 텍스트 데이터 색인하기

    .str.contains()

    df_seoul_hospital.loc[~df_seoul_hospital["상호명"].str.contains("종합병원"), "상호명"].unique()

    .str.contains()를 사용하게 되면 해당 컬럼에서 ()안에 들어있는 문자가 포함됐는지를 boolean 타입으로 출력한다.

    ~df_seoul_hospital["상호명"].str.contains("종합병원") 을 하게되면 ()안의 문자가 포함 안 된 인덱스를 나타낸다.

    .loc을 사용해 "상호명"에 종합병원이 포함된 인덱스들을 필터링하고,  "상호명" 컬럼만 가져와 unique()로 어떤 값들이 있는지 list로 표현한다.

    실행 결과

    위의 코드를 실행한 모습.

     

    이름에 꽃배달, 의료기, 장례식장 등 종합병원이 아닌 것으로 보이는 값들을 drop_row라는 변수로 지정하고 tolist()함수를 이용해 리스트 형태로 만든다.

    drop_row = df_seoul_hospital[df_seoul_hospital["상호명"].str.contains("꽃배달|의료기|장례식장|상담소|어린이집")].index
    drop_row = drop_row.tolist()
    drop_row

    코드를 실행하면

    [1917, 2803, 4431, 4644, 7938, 10283, 47008, 60645, 70177]

    의 값을 출력한다. 현재 drop_row에는 contains()의 괄호 부분 안에 있는 문자열들을 포함하는 값들의 인덱스를 리스트형태로 저장하고 있다.

     

    마찬가지로 "상호명"이 의원으로 끝나는 업체를 필터링하는 코드를 작성한 후 drop_row2 변수에 담아준다.

    drop_row2 = df_seoul_hospital[df_seoul_hospital["상호명"].str.endswith("의원")].index
    drop_row2 = drop_row2.tolist()
    drop_row2

    실행해보면 [8479, 12854, 13715, 14966, 16091, 18047, 20200, 20415, 30706, 32889, 34459, 34720, 35696, 37251, 45120, 49626, 51575, 55133, 56320, 56404, 56688, 57551, 62113, 76508] 가 출력된다.

     

    두 변수를 더하면 "상호명"에 꽃배달, 의료기, 장례식장, 상담소, 어린이집, 의원이 포함된 값들의 인덱스를 리스트형태로 지니게 되고, 이를 다시 drop_row에 대입하고, 서울 종합병원의 데이터프레임에서 제거한다.

     

    drop_row = drop_row + drop_row2
    
    print(df_seoul_hospital.shape)
    df_seoul_hospital = df_seoul_hospital.drop(drop_row, axis=0)
    print(df_seoul_hospital.shape)

    위의 코드를 실행하면

    (91, 29)

    (58, 29)

    가 출력되고, 이는 "서울특별시"에 있는 "상권업종분류명"이 종합병원인 값들에서 꽃배달, 의료기, 장례식장, 상담소, 어린이집, 의원을 상호명에 지니고 있는 값들을 제거한 데이터가 58개로 전처리되었음을 보여준다.

     

    시각화해서 표현하면

    plt.figure(figsize=(15,4))
    sns.countplot(data=df_seoul_hospital, x="시군구명", 
                  order=df_seoul_hospital["시군구명"].value_counts().index)

    x축의 값들이 많기 때문에 글자가 겹치는 걸 방지하기 위해, figsize를 지정해주고, x축 값을 지정하고 내림차순 정렬을 위해 order 속성을 사용해주면 아래와 같은 실행결과를 얻을 수 있다.

    실행 결과

     

    다시 df_seoul_hospital["상호명"].unique() 를 입력해 상호명 리스트를 살펴보면, 연구소, 인공신장실, 마취과 등등 종합병원이 아닌 것으로 보이는 값들이 아직 남아있긴 하다. 

     

     

    • 특정 지역만 보기

    "시도명"을 필터링 하는 작업으로 각 시도별 의료기관 데이터를 얻을 수 있다. 얻어진 데이터를 지도에 표기하거나, 시각적으로 표현하고 싶다면? scatter plot를 사용하거나, Folium을 사용해 지도 위에 체크포인트를 만들 수도 있다.

     

     

    scatter()

    df_seoul = df[df["시도명"] == "서울특별시"].copy()
    # df_seoul에 "시도명"이 서울특별시에 해당하는 데이터프레임을 만들어 복사한다.
    # copy()를 사용해 df_seoul의 데이터가 변해도 원본 데이터는 유지될 수 있도록 한다.
    
    # 1
    df_seoul["시군구명"].value_counts().plot.bar(figsize=(10,4), rot=30)
    # 판다스의 기본 막대그래프를 이용해 서울에 있는 의료기관을 각 구별로 나눈 모습을 확인.
    
    # 2
    df_seoul[["경도", "위도", "시군구명"]].plot.scatter(x="경도", y="위도", figsize=(8,7), grid=True)
    # scatter를 사용해 경도와 위도를 각 x축, y축 에 대입해 지도형태로 나타낸다.

    1 실행 결과
    2 실행 결과

    scatter plot을 사용해 위도와 경도 값을 입력해보니 서울지도 모양의 그래프가 나타났다. 가운데는 한강. 중간에 구멍난 부분들은 산이 있는 곳일 것이다.

     

    마찬가지로 seaborn의 scatter plot을 이용할 수도 있다.

    # 1
    plt.figure(figsize=(15,4))
    sns.countplot(data=df_seoul, x="시군구명")
    # 서울특별시의 구별 의료기관 분포를 막대그래프 형태로 나타낸다.
    
    # 2 
    sns.scatterplot(data=df_seoul, x="경도", y="위도", hue="시군구명")
    # 구별 의료기관 분포를 나타낸 그래프, 경도와 위도 값을 각각 x,y 축으로 잡고 hue를 통해 색상 구별을 줬다.

     

    1 실행 결과
    2 실행 결과

     

    seaborn을 활용하는 경우 hue 값을 정해줌으로써 색상을 달리해 시각적으로 더 직관적인 구별을 할 수 있게 해준다. 물론 위의 그래프 같은 경우 중구와 도봉구, 은평구와 강북구 등은 색이 너무 비슷해 지리를 모르는 경우 찾기가 쉽지 않을 것 같다.. 어떤 정보의 암묵적인 동의가 없다면 파이그래프처럼 값이 많으면 더 구별하기 힘들수도 있겠구나

     

    plt.figure(figsize=(9, 8))
    sns.scatterplot(data=df_seoul, x="경도", y="위도", hue="상권업종중분류명")

    이것은 같은 데이터를 "상권업종중분류명"에 따라 구별한 것이다.

    실행 결과

     

    파란색 병원이 압도적으로 많이 분포돼 있고, 주황색, 빨간색 순으로 분포돼 있는 듯하다.

    다음으로 전국에 있는 의료기관을 "시도명"으로 나눠보자.

     

    plt.figure(figsize=(9, 8))
    sns.scatterplot(data=df, x="경도", y="위도", hue="시도명")

    실행 결과

    실행하면 대한민국의 지도가 나타난다 !

    울릉도에는 의료기관이 하나 있는 듯하고, 제주도의 경우 한라산때문에 가장자리에 의료기관들이 분포해 있는 것 같다.

    동쪽을 보면 태백산맥이 위치한 부분들을 피해 의료기관들이 분포해 있는 모습도 확인할 수 있다.

     

    지금까지는 위도와 경도 값으로 그래프를 지도형태로만 확인했지만 실제 지도에 데이터의 값을 입력하려면?

    Folium을 사용하면 된다.

     

     

    • Folium으로 지도 활용하기

    folium.Map(location = ?, zoom_start = ?)

    import folium
    
    folium.Map()

    실행 결과

     

    folium을 import하고 실행하면 세계지도가 나타난다.

    서울의 종합병원 값을 지도에 표시해보고 싶다면 서울의 위도 평균값과 경도 평균값을 location 값으로 주면 된다.

     

    x = df_seoul_hospital["경도"].mean()
    y = df_seoul_hospital["위도"].mean()
    # x, y에 각각 서울 종합병원 "경도", "위도" 값의 평균을 대입한다.
    
    map = folium.Map(location=[df_seoul_hospital["위도"].mean(), df_seoul_hospital["경도"].mean()], zoom_start=12)
    map

    실행 결과

    location은 위도와 경도 값을 입력해주면 되고, zoom_start는 얼만큼 확대해서 보여줄 것인지를 입력해주면 된다.

    map에 위의 확대된 지도를 대입해주고, for 문을 이용해 "상호명"과 "도로명주소"를 보여주는 마커를 생성해보자.

     

    folium.Marker()

    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.save("index.html")
    # folium 자체에서 글자가 깨지는 현상이 발생해 html형식으로 저장하고 따로 확인했다. 반드시 저장할 필요는 없음.
    map

    .Marker()의 ()안에 location, popup을 이용해서 마커를 찍을 위치, 마커를 클릭했을 때 팝업에 나오는 정보를 입력할 수 있다.

     

    실행 결과

     

     

    가설을 세우고, 원하는 데이터를 얻기 위해 데이터를 색인하고 전처리하는 작업은 많은 시간을 필요로 한다.

    제대로 전처리 되지 않은 데이터는 낮은 신뢰도를 지니게 될 것이고, 이는 데이터를 분석하는데 의미가 없지 않을까.

    데이터를 필터링할 수 있는 코드를 아는 것도 중요하지만 어떤 데이터를 어떻게 처리할지가 더 중요하게 배워야 할 점인 것 같다. 아직 어떤 가설을 세우면 좋을지 많이 고민하고 연습해야하면 좋을까 싶었는데, 예시로 주제를 던져준 부분이 있어 다음엔 해당 주제들을 분석하고 배운 내용을 정리해야겠다!

Designed by Tistory.