728x90
반응형

데이터프레임 시각화 정리

1. 데이터프레임 정리

🍒행단위 합치기

  • 임시 데이터 생성
# 임시 데이터 1
data = [["Dog", 3], ["Cat", 5], ["Tiger", 2]]
index = [0, 1, 2]
columns = ["동물", "나이"]

df_temp1 = pd.DataFrame(data,
                       index=index,
                       columns=columns)
# 임시 데이터 2
data = [["집", 0], ["초원", 0], ["초원", 1]]
index = [0, 1, 2]
columns = ["사는 곳", "뿔의 갯수"]

df_temp2 = pd.DataFrame(data,
                       index=index,
                       columns=columns)

 

  • df_temp1과 df_temp2를 행단위로 합치기(행으로 추가)
result_df = pd.concat([df_temp1, df_temp2], axis=0, ignore_index=True)
result_df

 

🍒 열단위 합치기

  • 열단위로 합칠 때는 행의 갯수가 동일해야 함
pd.concat([df_temp1, df_temp2], axis=1)

 

🍒 열단위 합치기 : 키값을 이용해서 합치는 방식

  • 임시 데이터 생성
# 임시데이터
# 딕셔너리형태로 생성 
# key = columns
data1 = {"국적코드" : [1001, 1002, 1003],
       "국가" : ["한국", "미국", "인도"]}
df_info1 = pd.DataFrame(data1)

data2 = {"국적코드" : [1001, 1002, 1005],
       "인구" : [100, 200, 300]}
df_info2 = pd.DataFrame(data2)
df_info1, df_info2

  • 국적코드 같은 값들에 대해서 합치기
    - merge() : 같은 컬럼끼리 합치기
    - 기준은 df_info1
pd.merge(left=df_info1,
        right=df_info2,
        how="inner",
        left_on="국적코드",
        right_on="국적코드")

 

  • 국적코드가 같은 값은 같은데로, 같지 않으면 NaN으로 합치기
    - 기준 =  df_info1
pd.merge(left=df_info1,
        right=df_info2,
        how="left",
        left_on="국적코드",
        right_on="국적코드")

  • 국적코드가 같은 값은 같은데로, 같지 않으면 NaN으로 합치기
    - 기준 =  df_info2
pd.merge(left=df_info1,
        right=df_info2,
        how="right",
        left_on="국적코드",
        right_on="국적코드")

 

2. 전처리

🍒 bicycle.csv 파일 읽어들이기

df = pd.read_csv("./data/bicycle.csv",
                encoding="euc_kr")

 

🍒 결측치 확인

df.info()

 

  • 결측치 데이터 확인하기
    - 결측 데이터 값 True, 정상 데이터는 False
df.isnull()

❗결측치 처리 방법
1. 결측치가 있는 부분의 데이터를 사용할지 / 말지 결정
2. 사용 안한다면 컬럼과 행 주엥 어느 부분을 제거할지 결정
3. 사용한다면 어떻게 대체할지 결정

 대체 방법
3.1. 결측치가 있는 해당 컬럼의 평균으로 모두 대체
3.2. 범주형 데이터인 경우에는 범주의 비율대비로 대체
3.3. 숫자값인 경우 모두 0으로 대체
3.4. 결측데이터가 속한 주변 컬럼들의 데이터 유형과 유사한 데이터들의 평균으로 대체
3.5. 결측치가 있는 컬럼의 직전/직후 데이터의 평균으로 대체

 

  • 결측 데이터 현황 확인
    - 컬럼별 결측 현황
    - sum(0) : 0의 의미는 각 열의 행단위를 의미
    df.isnull().sum(0)​



    - 행별 결측 현황
    - sum(1) : 1의 의미는 각 행의 컬럼 단위를 의미
    df.isnull().sum(1)​

🍒 결측치 처리

  • 결측치가 있는 모든 행들 삭제하기
df_drop = df.dropna(axis=0)
df_drop.info()

 

  •  결측치가 있는 모든 컬럼 삭제하기
df_drop_col = df.dropna(axis=1)
df_drop_col.info()

 

  • 결측치 대체하기
# null값 0으로 대체
df["이용거리"].fillna(0)

# null값 문자로 대체
df["이용거리"].fillna("missing")

# null값 평균으로 대체
df["이용거리"].fillna(df["이용거리"].mean())

 

🍒 중복데이터 처리

  • 중복데이터가 있는 행의 위치 확인하기
    - True - 중복
df.duplicated(["이용거리"])​

 

  • 중복데이터 데이터프레임 형식으로 확인하기
    - 162개
df[df.duplicated(["이용거리"])]​

 

  • keep : 중복 중에 몇 번째 중복을 False(남겨 둘 것인지)로 할 것인지 설정
  • keep : first, last, False
    - first : 첫번째만 False (뒤쪽 중복 데이터는 모두 True), default, 생략가능
    - last : 마지막만 False (앞쪽 중복 데이터는 모두 True)
    - False : 중복데이터 전체 True 
df.duplicated(["이용거리"], keep="first")
df.duplicated(["이용거리"], keep="last")
df.duplicated(["이용거리"], keep="False")

 

  • 중복데이터 삭제
    - 중복 데이터는 사용할지 말지만 결정하면 된다.
    - 전체 행 420개에서 중복 행162개 삭제 > 258 행 남음
df.drop_duplicates(["이용거리"])

 

🍒 이상데이터 처리

  • 이상 데이터 처리 순서
    1. 결측치 처리가 선행되어야 한다.
     - 결측치도 데이터로 인식되기 때문이다.
    2. 이상데이터에는 범주형, 숫자형 데이터 처리 방식이 다르다.
     - 일반적으로 이상데이터는 숫자형 데이터 처리를 주로 한다.
    3. 이상 데이터 확인은 시각화(boxplot)를 통해서 확인한다.
    4. 실제 처리는 계산에 의해 처리된다.
  • 데이터 불러와서 전처리
### 시각화 라이브러리 :
import matplotlib.pyplot as plt

### 사용할 데이터 읽어 들이기
df = pd.read_csv("./data/bicycle_out.csv",
                encoding="euc_kr")
                
### 결측치 처리하기
df["대여거치대"] = df["대여거치대"].fillna(int(df["대여거치대"].mean()))
df["반납거치대"] = df["반납거치대"].fillna(int(df["반납거치대"].mean()))
df["이용시간"] = df["이용시간"].fillna(int(df["이용시간"].mean()))
df["이용거리"] = df["이용거리"].fillna(int(df["이용거리"].mean()))
df.info()

### 행단위 중복체크
# - 중복 없음
df.duplicated().value_counts()

 

  • 이상치 확인
    - 나이 max 값
df.describe()

 

  • 나이 데이터를 기준으로 이상데이터 시각적으로 확인하기
    - 박스플롯(boxplot)을 용해서 시각화
    - 주황색 선 : 중앙값
plt.boxplot(df["나이"])
plt.show()

 

 

 - 박스 상 선 : Max Outliers
 - 박스 하단 선 : Min Outliers
 - 이상치로 의심되는 데이터 : Max 및 Min Outlier를 벗어난 데이터들 
 - 주황색 선 : 중앙값

 

 

 

 

 

 

 

 

❗이상치 계산을 위한 그림 설명

 

 

<이상치 계산 공식>

IQR = Q3 - Q1

최대 = Q3 + (1.5 * IQR)
최소 = Q1 - (1.5 * IQR)

 

 

 

 

 

 

 

  • 이상치 계산 하기
import numpy as np

### 25% 및 75% 시점의 값 추출하기
q1, q3 = np.percentile(df["나이"], [25, 75])

### IQR 계산
iqr = q3 - q1

### max outliers 계산
upper_bound = q3 + (1.5 * iqr)

### min outliers
lower_bound = q1 - (1.5 * iqr)

upper_bound, lower_bound

 

  • 이상치로 의심되는 max 또는 min을 벗어나는 데이터 추출하기
    - max값을 벗어난다고 해도 무조건 이상치로 처리 하지 않는다. 나이를 보면 60대일 경우는 이상치로 보긴 어렵다.
    - 이상치 처리는 필터링으로 하면 된다.
df[((df["나이"] > upper_bound) | (df["나이"] < lower_bound))]

728x90
반응형
728x90
반응형

영화 긍정 / 부정 리뷰 데이터 빈도 분석 및 워드 클라우드 시각화

 

1. 데이터 전처리

🧀데이터 셋 읽어들이기

### 라이브러리 정의하기
import pandas as pd

# 데이터프레임 변수명 : df_org
file_path = "./data/df_new.csv"
df_org = pd.read_csv(file_path)
df_org


🧀 긍정 및 부정에 대해서만 각각 데이터 필터링하기

 

  • 긍정 리뷰 데이터 필터링
  • 데이터 프레임 변수명 : pos_reviews
pos_reviews = df_org[df_org["label"] == 1]
pos_reviews

 

  • 부정 리뷰 데이터 필터링
  • 데이터 프레임 변수명 : neg_reviews
neg_reviews = df_org[df_org["label"] == 0]
neg_reviews

 


🧀 리뷰데이터 전처리

  • 긍정 및 부정 리뷰 데이터에서 한글 이외 모두 제거하기
  • 정규표현식 라이브러리 활용
import re

 

  • 긍정 리뷰에서 한글 이외 모두 제거 처리하기
    • re.sub(pattern, replace, text)
      : text 중 pattern에 해당하a는 부분을 replace로 대체한다.
    • 코드에선 "ㄱ-ㅣ가-힣"가  아닌 것은 " "로 대체
    • [^] : 부정
pos_reviews.loc[ : , "comment"] = [re.sub(r"[^ㄱ-ㅣ가-힣+]", " ", data) for data in pos_reviews["comment"]]
pos_reviews

 

  • 부정 리뷰에서 한글 이외 모두 제거 처리하기
neg_reviews.loc[ : , "comment"] = [re.sub(r"[^ㄱ-ㅣ가-힣+]", " ", data) for data in neg_reviews["comment"]]
neg_reviews


🧀긍정 및 부정 리뷰 형태소 추출하기

  • 형태소 분석 라이브러리
# jpype : java 라이브러리를 python에서 사용할 수 있도록 도와주는 라이브러리
# - konlpy는 java로 만들어진 라이브러리
import jpype

# Okt : 한국어 형태소 분석 라이브러리
# - Okt(Open Korean Text) : 대표적 한글 형태소 분석기
from konlpy.tag import Okt

 

  • 형태소 분석기 객체 생성하기
okt = Okt()
okt

 

  • 긍정 리뷰 데이터에서 명사만 추출하기
## - 명사만 담아 놓을 리스트 변수 선언
pos_comment_nouns = []

for cmt in pos_reviews["comment"] :
    #print(okt.nouns(cmt)) # 리스트 형태로 뽑아줌
    pos_comment_nouns.extend(okt.nouns(cmt))

print(pos_comment_nouns)

 

 부정 리뷰 데이터도 똑같이 생성


🧀 긍정 및 부정 리뷰 데이터에서 1글자는 모두 제외 시키기

  • 긍정 리뷰 명사 데이터에서 1글자 모두 제외하기
pos_comment_nouns2 = [word for word in pos_comment_nouns if len(word) > 1]
print(pos_comment_nouns2)

 

→ 부정 리뷰 데이터도 똑같이 생성


🧀긍정 및 부정 명사들의 빈도 분석

  • 리뷰 명사들에 대한 워드 카운트
from collections import Counter
  • 긍정 명사 워드카운트 처리
  • 딕셔너리 형태로 추출 된다.
pos_word_count = Counter(pos_comment_nouns2)
print(pos_word_count)

 

→ 부정 명사 워드카운트도 똑같이 생성


🧀긍정 및 부정 워드카운트 상위 20개 단어만 추출

  • 긍정 > 워드카운트 상위 20개 단어 추출
  • Count() 지원 함수 중에 내림차순 함수 : most_common(20) > 내림차순 후에 상위 20개 추출하는 함수임
pos_top_20 = {}

# - 1
for k, v in pos_word_count.most_common(20) :
    pos_top_20[k] = v
print(pos_top_20)

# - 2
pos_top_20 = {k:v for k, v in pos_word_count.most_common(20)}

 

→ 상위 20개 부정 명사 워드카운트도 똑같이 생성

 

 

2. 데이터 시각화(1) - 막대 그래프

🧀긍정 및 부정 상위 20개 명사에 대한 빈도 시각화

  • 시각화 라이브러리
### 시각화 라이브러리
import matplotlib.pyplot as plt

### 폰트 설정 라이브러리
from matplotlib import font_manager, rc

### 폰트 설정
plt.rc("font", family="Malgun Gothic")

### 마이너스 기호 설정
plt.rcParams["axes.unicode_minus"] = False

 

  • 긍정 막대 그래프를 이용한 빈도 시각화
plt.figure(figsize=(10, 5))

### 제목 넣기
plt.title(f"긍정 리뷰의 단어 상위 (20개) 빈도 시각화", fontsize=17)

### 막대그래프 그리기
for key, value in pos_top_20.items() :
    ### 영화라는 단어는 의미가 없을 것으로 여겨지기때문에 제외 시키기
    if key == "영화" :
        continue
        
    plt.bar(key, value, color="lightgrey")

### x축과 y축 제목 넣기
plt.xlabel("리뷰 명사")
plt.ylabel("빈도(count)")

### x축 각도 조절
plt.xticks(rotation=70)

### 그래프 나타내기
plt.show()

 

→ 부정 리뷰의 막대 그래프도 똑같이 생성

 

3. 데이터 시각화(2) - 워드 클라우드

🧀긍정 및 부정 리뷰 단어 워드클라우드(wordcloud) 시각화

  • 워드클라우드 라이브러리
from wordcloud import WordCloud
  • 긍정 리뷰 단어 워드 클라우드 시각화
plt. figure(figsize=(8, 8))

### 그래프 제목
plt.title("[긍정] 리뷰 단어 워드클라우드 시각화")

### 사용할 폰트 파일 지정하기
# font_path = "C:/Windows/Fonts/malgunsl.ttf"
font_path = "C:/Users/user/Desktop/KCC-Ganpan.ttf"

### 워드클라우드 속성 설정
wc = WordCloud(
                ### 폰트 지정
                font_path=font_path,
                ### 배경색 지정
                background_color="ivory",
                ### 그래프 너비
                width=800,
                ### 그래프 높이
                height=600
            )

### 워드클라우드 그래프에 데이터 넣기
# - generate_from_frequencies() : 워드클라우드 이미지로 반환해줌
# cloud = wc.generate_from_frequencies(pos_top_20)

### 긍정 전체 단어 넣어보기
cloud = wc.generate_from_frequencies(pos_word_count)

### 워드클라우드 이미지 보여주기
plt.imshow(cloud)

### x, y좌표축 제외시키기
plt.axis("off")

### 저장하기
plt.savefig("./img/긍정_리뷰_단어_워드클라우드_시각화.png")

plt.show()

 

→ 부정 리뷰의 워드클라우드도 똑같이 생성

728x90
반응형
728x90
반응형

아래 글에 이어서 진행

https://mzero.tistory.com/98

 

[데이터 수집][Crawling] 영화 데이터 전처리 및 시각화

영화 데이터 전처리 및 시각화 1. 외부파일 읽어들이기 제목 : "title" , 평점 : "score", 리뷰 : "comment", 긍정/부정 : "label" ### 라이브러리 정의 # - 행렬데이터 처리 라이브러리 import pandas as pd file_path =

mzero.tistory.com

 

6. 영화별 평점 평균 시각화 (3) - 원형 그래프 그리기

🌳긍정, 부정, 기타에 대한 원형 그래프 시각화하기

fig, axs = plt.subplots(5, 2, figsize=(15, 25))

axs = axs.flatten()

### 빈도 비율별 색상 정의
colors = ["pink", "gold", "whitesmoke"]

### 라벨 정의(파이 쪼개기)
labels_dict = {0 : "부정(1~4점)", 1 : "긍정(8~10점)", 2 : "기타(5~7점)"}

### 긍정/부정에 대한 원형 그래프 그리기
for title, ax in zip(avg_score.keys(), axs) :
    ### 영화별 건수 필터링하기
    num_reviews = len(df_new[df_new["title"] == title])
    # print(f"num_reviews = {num_reviews}")

    ### label 컬럼의 범주별로 갯수 필터링 하기
    # df_new["title"]==title 이 값을 만족하는 데이터만 추출
    values = df_new[df_new["title"]==title]["label"].value_counts()
    #print(f"values = {values}")

    ### 원형 그래프에 표시할 라벨값 정의하기
    # - 영화별로 긍정 또는 부정 또는 기타 중에 하나라도 없으면 처리가 필요함
    label_list = df_new[df_new["title"]==title]["label"].unique()
    labels=[]
    for k in label_list : 
        ### 영화별 실제 존재하는 긍정/부정/기타 라벨 정의하기
        labels.append(labels_dict[k])
    
    ### 각 그래프 제목 넣기
    ax.set_title(f"{title} ({num_reviews}명)", fontsize=15)
    
        ### 원형(pie) 그래프 그리기
    ax.pie(values, 
          # 원형그래프에 표시할 라벨 지정
          labels = labels,
          # 원형 그래프에 표시할 값의 소숫점 자리수 지정
          autopct = "%1.1f%%",
          # 원형 그래프 각 영역의 색상 지정
          colors=colors,
          # 그림자 효과 지정하기
          shadow=True,
          # 그래프의 시작위치를 12시 방향으로
          startangle=90)

### 이미지 저장하기
plt.savefig("./img/긍정_부정_원형그래프_시각화.png")    

plt.show()

 

🌳 최종 전처리된 데이터는 파일로 관리하기

  • 파일명 df_new.csv
  • 인덱스 미포함
  • 저장 위치 : data 폴더
df_new.to_csv("./data/df_new.csv", index=False)

728x90
반응형
728x90
반응형

영화 데이터 전처리 및 시각화

1. 외부파일 읽어들이기

  • 제목 : "title" , 평점 : "score", 리뷰 : "comment", 긍정/부정 : "label"
### 라이브러리 정의
# - 행렬데이터 처리 라이브러리
import pandas as pd

file_path = "./data/movie_reviews.txt"
df_org = pd.read_csv(file_path,
                     ### 구분자 알려주기
                    delimiter = "\t",
                    names=["title", "score", "comment", "label"])
df_org

2. 데이터 전처리

🌳데이터 정보 확인 : 결측치 확인

df_org.info()


🌳 기초통계 확인 : 이상데이터 확인

df_org.describe()


🌳 평점(score) 현황데이터 확인

df_org["score"].value_counts()​


🌳중복데이터 확인하기

  • keep=False : 중복된 모든행 체크(중복이 있으면 True, 없으면 False)
df_org[df_org.duplicated(keep=False) == True]


🌳중복 데이터 추출하기

  • 중복 중에 하나는 제외하고 나머지 중복만 추출
df_del = df_org[df_org.duplicated() == True]
len(df_org[df_org.duplicated() == True])


🌳중복제거하기

df_new = df_org.drop_duplicates()
len(df_new)
df_new.info()

 

 

 

 

중복된 데이터 제거로 행수가 4073에서 4033으로 줄어들었다.

 

 

 

 

 

 

 

3. 데이터 탐색하기

🌳영화 제목만 추출하기

df_new["title"].unique()


🌳영화 제목별 리뷰갯수 현황 확인하기

df_new["title"].value_counts()


🌳각 영화별 평점 기초통계 확인하기

  • 영화제목별 평점에 대한 그룹집계하기
movie_info = df_new.groupby("title")["score"].describe()​

 

  • 기초통계 행단위 데이터 내림차순 정렬하기
movie_info = movie_info.sort_values(by=["count"], axis=0, ascending=False)
movie_info

 

4. 데이터 시각화

🌳 라이브러리

### 시각화 라이브러리
import matplotlib.pyplot as plt

### 폰트 설정 라이브러리
from matplotlib import font_manager, rc

### 한글폰트 설정
plt.rc("font", family="Malgun Gothic")

### 마이너스 기호 설정
plt.rcParams["axes.unicode_minus"] = False

 

 

5. 영화별 평점 평균 시각화 (1) - 막대그래프 

영화별 별점 평균이 가장 큰 영화는 orange 색으로, 나머지는 lightgrey 색으로 표현

🌳 라이브러리

### 평점 평균 계산을 위해 사용
import numpy as np

🌳 영화제목을 리스트 타입으로 받아오기

  •  array()
    • 넘파이 (numpy)에서 사용하는 배열(파이썬의 리스트와 동일)
    • 단, 하나의 타입만 저장 가능하다.
    • 이외 사용법은 파이썬의 리스트와 동일하다
  • unique() : numpy의 배열 타입으로 반환함
movie_title = df_new["title"].unique()
movie_title

  • tolist() : 파이썬의 리스트 타입으로 변환하는 함수
movie_title = df_new["title"].unique().tolist()
movie_title


🌳 영화별 평점 평균 추출하기

### 영화별 평점 평균 추출하기
# - 평점평균값을 저장할 딕셔너리 변수 선언
avg_score = {}

for m_title in movie_title:
    ### 평점 평균 계산하여 딕셔너리에 넣가
    avg = df_new[df_new["title"] == m_title]["score"].mean()
    # print(f"평점평균 : {avg}")

    ### 딕셔너리에 담기
    # key는 제목, value는 평점평균값
    avg_score[m_title] = avg

print(f"딕셔너리 최종값 : {avg_score}")


🌳 영화별 평점 평균 시각화

  • 컬러값 지정하기
    • array_str() : 문자열로 변환하는 함수
    • where() : 파이썬에서 if문과 동일한 조건문
    • where(조건, 참, 거짓) : 조건이 참이면 첫번째 값, 거짓이면 두번째 값 처리
# - 그래프 너비와 높이 지정
plt.figure(figsize=(10, 5))

# - 그래프 제목
plt.title("영화별 평점 평균 막대그래프", fontsize=17, fontweight="bold")

### 각 영화별 평점 평균 막대그래프 그리기
for k, v in avg_score.items() :
    color = np.array_str(np.where(v==max(avg_score.values()), "orange", "lightgrey"))
    #print(color)

    ### 막대 그래프 그리기
    plt.bar(k, v, color=color)

    ### 막대 그래프 상단에 평점평균 텍스트 표시하기
    plt.text(k, v, "%.2f"%v, horizontalalignment="center", verticalalignment="bottom")
    
### x축과 y축 제목 넣기
plt.xlabel("영화제목", fontweight="bold")
plt.ylabel("평점평균", fontweight="bold")

### x축의 값 각도 조절하기
plt.xticks(rotation = 75)

### 그래프를 이미지로 저장시키기
# - savefig() 함수는 plt.show() 전에 수행되어야 한다.
plt.savefig("./img/영화별 평점 평균 막대그래프.png")

plt.show()

 

6. 영화별 평점 평균 시각화 (2) - 점(분포) 그래프 그리기

🌳각 영화별 평점 분포도 그리기

      • 하나의 큰 그래프 안에 10개의 그래프를 넣어서 표현 → 이를 subplot 이라고 칭한다.
      • <이해를 위한 코드 설명 1>  
        • fig, axs = plt.subplots(5, 2, figsize=(15, 25)) : 그림(fig)과 5x2 그리드로 구성된 축(axs)을 만든다.
        • axs.flatten() : 5x2 그리드를 1차원 배열로 펼친다. 이렇게 하면 단일 루프에서 각 서브플롯을 반복하는 것이 더 쉬워진다.
        • avg_score.keys() 및 avg_score.values() : 나타낸 데이터 집합을 반복한다. 각 반복은 다른 영화 제목에 해당한다.
        • num_reviews = len(df_new[df_new["title"] == title]) : 현재 영화 제목의 리뷰 수를 계산한다.
        • x = np.arange(num_reviews) : 0에서 num_reviews - 1까지의 x값으로 이루어진 배열을 생성한다.
        • y = df_new[df_new["title"] == title]["score"] : DataFrame에서 현재 영화 제목의 평점을 추출한다.
        • subtitle = f"{title} ({num_reviews}명)" : 현재 서브플롯의 제목으로 영화 제목과 리뷰 수를 나타내는 부제목을 생성한다.
        • ax.set_title(subtitle, fontsize=15, fontweight="bold") : 서브플롯의 제목을 설정한다.
        • ax.plot(x, y, "o") : 점으로 평점을 리뷰 인덱스에 대해 나타내는 산점도를 생성한다.
        • ax.axhline(avg, color="red", linestyle="--") : 영화의 평균 평점을 나타내는 수평 대시된 선을 추가한다.
      • <이해를 위한 코드 설명 2>
        • fig, axs = plt.subplots(5, 2, figsize=(15, 25))
          서브플롯 함수 사용해서 큰 그래프 하나에 작은 그래프들을 넣으려는 작업을 함
          작은 그래프들을 몇행 몇열로 넣을 건지 지정 해야한다. 지금 코드는 5행 2열. figsize는 전체 크기
        • axs = axs.flatten() 
          for문을 사용하기 위해 flatten으로 틀 정렬 >> 이건 문법 적인 것
        • for title, avg, ax in zip(avg_score.keys(), avg_score.values(), axs)
          avg_score는 영화 제목을 키로, 해당 영화의 평균 평점을 값으로 가지는 딕셔너리로 avg_score.keys()는 딕셔너리의 키들을, avg_score.values()는 딕셔너리의 값들을 반환한다.

            axs는 5행 2열의 subplot들을 1차원 배열로 평탄화한 것이다. 따라서 zip(avg_score.keys(), avg_score.values(), axs)는 영화 제목, 평균 평점, 그리고 subplot을 하나의 튜플로 묶어 반환한다.
        • df_new[df_new["title"] == title]
          데이터프레임 df_new에서 영화 제목이 title인 행들을 선택하는 부분이다. len(df_new[df_new["title"] == title])은 해당 영화의 리뷰 개수를 반환한다.
          따라서 for title, avg, ax in zip(avg_score.keys(), avg_score.values(), axs):에서 각각의 반복마다 title에는 영화 제목, avg에는 해당 영화의 평균 평점, ax에는 subplot이 할당된다. 그리고 num_reviews에는 해당 영화의 리뷰 개수가 할당된다.
        • x = np.arange(num_reviews), y = df_new[df_new["title"] == title]["score"]
          x,y축을 지정해 주려는데 y는 평점이므로 0에서 10까지 범주가 정해져 있음
          그러나 x축은 갯수. 갯수는 데이터가 없음. 그렇기 때문에 전체 갯수를 뽑고 0부터 순차적으로 뽑아 냄
          →그려진 첫번째 그래프에선 500씩 범주를 알아서 잘라냄
          arange로 순차적인 리스트 값으로 반환 (일정한 범위로 쪼개준다)
          x,y는 범주형 데이터
        • ax.set_title
          해당공간(ax)의 제목 지정
        • ax.plot(x, y, "o")
          공간에 그래프 그린다.
        • ax.axhline(avg, color="red", linestyle="--")
          ax.axhline은 서브플롯 안에 또다른 그래프를 그리는 것 위에 것과 상관없음
          avg 수평선을 기준으로 y축값을 넣어서 나타낸다
    •  
# - 5행 2열의 subplot 생성하여 구현하기
# - subplots(행 갯수, 열 갯수, 전체 그래프 크기)
# - fig : 큰 그래프 정보
# - axs : 5행 2열의 내부 그래프 공간 정보
fig, axs = plt.subplots(5, 2, figsize=(15, 25))

### 여러개의 그래프를 for문을 이용해서 표현하고자 할 떼 아래 먼저 수행
# - flatten() : 틀 정렬하기 - > 5행 2열의 틀을 정렬해 놓기
axs = axs.flatten()

### 각 그래프를 행렬 공간의 subplot에 넣기
for title, avg, ax in zip(avg_score.keys(), avg_score.values(), axs):
    # print(f"{title} / {avg} / {ax}")
    
    ### x축에는 영화 리뷰 갯수, y축에는 평점 평균
    ### 리뷰 갯수 추출하기
    num_reviews = len(df_new[df_new["title"] == title])
    # - arange(num) : 0부터 num까지의 값을 순차적으로 만들기
    x = np.arange(num_reviews)
    # print(f"x ---------> {x}")

    ### y축에는 평점 추가
    y = df_new[df_new["title"] == title]["score"]
    # print(f"y ----------> {y}")

    ### 각 그래프에 제목 넣기
    subtitle = f"{title} ({num_reviews}명)"
    ax.set_title(subtitle, fontsize=15, fontweight="bold")
    

    ### 점 그래프 그리기
    # - "o" : 점으로 표현하는 마커 기호
    ax.plot(x, y, "o")


    ### 각 영화별 평점평균을 빨강색 점선으로 표시하기
    # - axhline() : 각 subplot 공간에 수평선 그리기
    ax.axhline(avg, color="red", linestyle="--")

plt.savefig("./img/각 영화별 평점 분포도.png")

plt.show()

728x90
반응형
728x90
반응형

영화 데이터수집 웹크롤링

크롤링 Crawling
소프트웨어 따위가 웹을 돌아다니며 유용한 정보를 찾아 특정 데이터베이스로 수집해 오는 작업. 또는 그러한 기술

다음 영화 사이트 웹크롤링

  • URL : http://movie.daum.net
  • 다음영화 > 랭킹 > 박스오피스 > 월간 위치의 데이터 수집
  • 수집데이터 : 영화제목, 평점, 댓글
  • 생성할 데이터 : 긍정/부정 ( 별점 점수 별 긍정인지 부정인지 판단하는 데이터 생성 )
  • 프로그램에서 https://movie.daum.net/ranking/boxoffice/monthly 주소를 열어서 크롬에서 제어

웹크롤링 라이브러리

  • 정적인 웹크롤링을 할 경우
    • BeautifulSoup : 하나의 페이지에 보이는 부분만 수집할 때 사용
  • 동적인 웹크롤링을 할 경우
    • selenium : 클릭과 같은 이벤트 등 페이지 전환을 하면서 수집할 때 사용
  • 동적 웹페이지 처리를 위한 라이브러리
    • Prompt에서 설치 필요 : pip install selenium
    • from selenium import webdriver
    • webdriver : 브라우저 자체를 컨트롤 함
  • 웹페이지 내에 데이터 추출을 위한 라이브러리
    • from selenium.webdriver.common.by import By
    • By : 페이지 안에 있는 html을 컨트롤 함
  • 시간 라이브러리
    • import time
    • 웹브라우저에 접근 할 때 페이지에 클릭이라는 동적 이벤트를 발생시킨다. 이때  네트워크 사양에 따라 느리게 실행 될 수 있고  다른 pc보다 빠르게 실행 될 수 있다. 즉, 사양에 따라 페이지 로딩 시간이 다르게 나타난다다. 그 로딩시간에 다른 행동을 하지 못하도록 즉, 외부에서 읽어들일 수 있는 시간을 주기 위해 time 사용

1. 크롬 브라우저 띄우기

  • 브라우저 컨트롤
driver = webdriver.Chrome()
  • url을 이용하여 페이지 접근
    • get() : 페이지에 접근 후 해당 html 코드 읽어 들이기
    • driver 객체가 모든 정보를 가지고 있음
driver.get("https://movie.daum.net/ranking/boxoffice/monthly")

 

2. 제목이 있는 부분의 html 태그 경로(패스) 추출하기

  • 크롬브라우저 → F12(개발자도구) → 영화제목 마우스 우클릭 → [검사] 클릭 → a 태그에 마우스 위치 후 우클릭 → copy → copy selector 클릭 → 해당 제목의 위치 저장

  • 영화 제목이 있는 a 태그 위치 경로 확인
    • li:nth-child(1)에서 :nth-child(1) 이걸 빼면 ol아래 모든 li가 해당 된다.
movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"

 

  • 현재 크롬브라우저에 보이는 영화제목 모두 추출하기
    • find_element() : 한건 조회
    • find_elements() : 여러건 조회(리스트 타입으로 반환)
    • By.CSS_SELECTOR : CSS 스타일 경로를 인식할 수 있도록 지정
   movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
    print(f"movie_elements length = {len(movie_elements)}")
    # 리스트 타입 0번째 제목 , 태그와 태그 사이에 text가 들어있다.( .text로 접근 )
    print(f"title[0] =>> {movie_elements[0].text}")
    print(f"movie_elements(제목) = {movie_elements}")

 

  • 웹크롤링 처리가 모두 완료되면, driver 종료해야 한다
driver.quit()
  •  try - except로 처리하기
try:
    driver = webdriver.Chrome()

    driver.get("https://movie.daum.net/ranking/boxoffice/monthly")

    movie_path = "#mainContent > div > div.box_boxoffice > ol > li > div > div.thumb_cont > strong > a"
    
    movie_elements = driver.find_elements(By.CSS_SELECTOR, movie_path)
    print(f"movie_elements length = {len(movie_elements)}")
    print(f"title[0] =>> {movie_elements[0].text}")
    print(f"movie_elements(제목) = {movie_elements}")

except Exception as e:
    print(e)
    driver.quit()

finally:
    driver.quit()

 

 

3. Click ( ) 이벤트 발생시키기 (1) - 상세 페이지

아래 코드는 모두 for i 문 안에 작성된 코드

  • 제목을 클릭 시켜서 상세 페이지로 이동하기
    • 마우스로 제목을 클릭하는 행위와 동일한 코드
    • click() 이벤트 발생
# 제목 10개만 추출하기
    for i in range(10) : 
        title = movie_elements[i].text.strip()
        print(f"No[{i}] / title[{title}] Start----------------")

        ### 제목을 클릭 시켜서 상세 페이지로 이동하기
        movie_elements[i].click()

 

  • 상세페이지로 접근했다라는 정보를 받아오기
    • 실제 상세페이지에 접근
    • window_handles : 페이지가 열릴때 마다 리스트타입으로 윈도우 정보를 순서대로 가지고 있는 객체이다. -1 은 마지막에 접근한 페이지를 의미한다.
      movie_handle = driver.window_handles[-1]
        # - 새로 열린 페이지로 전환하기
        driver.switch_to.window(movie_handle)

 

  • 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
time.sleep(1)

 

→ 여기까지 실행하면 웹 페이지 열리고 영화 '서울의 봄' 상세페이지까지 들어갔다가 종료됨


4. Click ( ) 이벤트 발생시키기 (2) - [평점] 

  • [평점] 탭 클릭 이벤트 발생 시키기

   tap_score_path = "#mainContent > div > div.box_detailinfo > div.tabmenu_wrap > ul > li:nth-child(4) > a"

 

  • a태그 정보 가지고 오기
 tap_score_element = driver.find_element(By.CSS_SELECTOR, tap_score_path)

 

  • [평점] 탭, 즉 a태그 클릭 이벤트 발생시키기[평점] 페이지로 접근했다라는 정보를 받아오기
	tap_score_handle = driver.window_handles[-1]
        # - 새로 열린 페이지로 전환하기
        driver.switch_to.window(tap_score_handle)

 

  • 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
        time.sleep(1)

 

5. 모든 평점 / 리뷰 데이터 추출하기

  • 모든 평점 데이터 추출하기
        score_path = "ul.list_comment div.ratings"
        score_lists = driver.find_elements(By.CSS_SELECTOR, score_path)
        print(f"평점 갯수 : {len(score_lists)}")

 

  • 모든 리뷰 데이터 추출하기
        comment_path = "ul.list_comment p.desc_txt"
        comment_lists = driver.find_elements(By.CSS_SELECTOR, comment_path)
        print(f"리뷰 갯수 : {len(comment_lists)}")

 

6. 평점을 이용하여 긍정 / 부정 값 생성하기

  • 평점 또는 리뷰 데이터가 없을 수 있기에 두개 리스트의 갯수 중 작은 값을 사용
  • 평점 또는 리뷰가 없으면, 수집에서 제외
  • 기존의  for j in range(len(score_lists))으로 for문을 돌릴 때, 리뷰가 없을 경우 len(comment_lists)는  len(score_lists)와 길이가 다르기 때문에 오류가 난다.
for_cnt = 0
        if len(score_lists) < len(comment_lists) :
            for_cnt = len(score_lists)
        elif len(score_lists) > len(comment_lists) :
            for_cnt = len(comment_lists)
        else :
            for_cnt = len(score_lists)

 

아래 코드는 모두 for j 문 안에 작성된 코드

  • 평점, 리뷰 추출하기
 for j in range(for_cnt) : 
            ### 평점 추출하기
            score = score_lists[j].text.strip()
            
            ### 리뷰 추출하기
            comment = comment_lists[j].text.strip().replace("\n", "")
            
            print(f"{title}  \t{score}  \t{comment} \n")

 

  • 평점을 이용해서 긍정/ 부정 데이터 생성
    • 긍정 : 평점이 8이상인 경우로, 긍정값은 1 사용
    • 부정 : 평점이 4이하인 경우로, 부정값은 0 사용
    • 기타 : 나머지, 기타값은 2 사용
   label = 0
            if  int(score) >= 8 :
                label = 1
            elif int(score) <= 4 :
                label = 0
            else :
                label = 2
                
    print(f"{title}  \t{score}  \t{comment} \t{label} \n")

 

7. 다시 메인으로 이동

아래 코드는 for j 문 밖에 작성된 코드

  • 영화 한편에 대한 정보수집이 끝나면 다시 메인으로 이동
  • execute_script() : 자바스크립트 문법 처리 함수
	driver.execute_script("window.history.go(-2)")
        time.sleep(1)

 

→ 여기까지 실행하면 영화 10개의 제목, 평점, 리뷰, 긍정/부정 데이터가 출력된다

 

8. 수집 데이터 저장하기

  • 수집데이터 txt 파일로 저장시키기 ( 아래 코드는 for i 문 위에 작성된 코드)
 f = open("./data/movie_reviews.txt", "w", encoding="UTF-8")
  • 파일에 쓰기  ( 아래 코드는 for j문 에 작성된 코드)
  f.write(f"{title}\t{score}\t{comment}\t{label}\n")
  • 파일 자원 닫기 (아래 코드는 except 문에 작성된 코드)
f.close()

9. 모두 펼치기(더보기) 수행한 뒤 데이터 추출

아래 코드는 for i 문 안에서 모든 평점 데이터 추출하기 전에 작성된 코드

  • [평점] 더보기 버튼 클릭하여 모든 평점 보이게 펼치기
  • 처음에 실행했다가 오류난 이유는 영화의 평점 중에 리뷰가 적히지 않은게 있었음. 6번으로 가서  if 문 추가.
	### - 펼친 갯수 확인 변수
        more_view_cnt = 0

        ### 모두 펼치기(더보기) 수행
         while True :
            try: 
                more_view_path = "#alex-area > div > div > div > div.cmt_box > div.alex_more > button"
                more_view_element = driver.find_element(By.CSS_SELECTOR, more_view_path)

                more_view_element.click()
                
                ### 상세페이지로 접근했다라는 정보를 받아오기
                movie_handle = driver.window_handles[-1]
                # - 새로 열린 페이지로 전환하기
                driver.switch_to.window(movie_handle)
                ### 페이지 로딩 및 코드 읽어들이는 시간을 벌어주기
                time.sleep(1)

                ### 임시로 2번만 반복 처리 후 break 처리
                # if more_view_cnt == 2 :
                #   break
                
                ### 더보기 클릭 횟수 확인을 위해 1씩 증
                more_view_cnt += 1
                
            except Exception as e :
                ### 더이상 더보기 버튼이 보이지 않으면 오류 발생
                # - 오류 발생 시점이 더보기 버튼이 끝나는 시점
                break

        ### 더보기 클릭획수 확인하기
        print(f"더보기 클릭 횟수 : [{more_view_cnt}]")

 

→ 여기까지 실행하면 영화 10개의 제목과  더보기를 눌러 모두 펼쳤을 때의 평점, 리뷰, 긍정/부정 데이터가 출력된다

728x90
반응형
728x90
반응형

데이터 전처리 시각화

🐳 데이터 불러오기

### 라이브러리 정의하기
import pandas as pd

### 사용할 데이터 읽어오기
# 데이터프레임 변수명 : df_bus_card_tot
file_path = "./01_data/all/df_bus_card_tot.csv"
df_bus_card_tot = pd.read_csv(file_path)

print("갯수 : ", len(df_bus_card_tot))
df_bus_card_tot.head(1)

 

 

데이터 시각화

시각화의 목적?
직관적인 데이터 확인

 

🐳 시각화에 필요한 라이브러리

### 시각화 라이브러리
import matplotlib # 시각화 라이브러리를 쓰겠다!
import matplotlib.pyplot as plt # 차트나 그림이 들어있다
import seaborn as sns # 파스텔 색감

### 그래프 내에 한글이 포함된 경우 폰트 처리가 필요하다
# - 한글 꺠짐 방지를 위한 라이브러리
### 폰트 환결설정 라이브러리
from matplotlib import font_manager, rc

### 운영체제 확인을 위한 라이브러리
# import platform

plt.rc("font", family = "Malgun Gothic")

### 그래프 내에 마이너스(-) 표시 기호 적용하기
plt.rcParams["axes.unicode_minus"] = False

 

🐳 기준월 및 기준일자별 버스 이용량 시각화 분석

  • 사용할 컬럼 : 기준월, 기준일, 승객연령
  • 사용할 집계함수 : count
  • 이용량 집계를 위한 함수 : pivot_table()
    - 히트맵 시각화시 데이터 생성
  • 사용할 그래프 : 히트맵(hitmap)
    - 히트맵을 그리기 위한 데이터를 만들어야 하는데, 그 데이터를 만들어내는게 피벗테이블
df_pivot = df_bus_card_tot.pivot_table(index = "기준월",
                                       columns = "기준일",
                                       values = "승객연령",
                                       aggfunc = "count")

 

<데이터 count 집계하기>
- y축 : index
- x축 : columns
- 집계 : count(승객연령)

- 결측값 존재 : NaN

 

 

 

🐳 결측치(NaN) 처리하기

  • 결측치를 처리한 이유가 명확해야 한다.
    - 2월 결측치의 경우 2월이 28일 밖에 없어서 나머지 일에는 결측치가 나왔고 타당한 이유이기에 처리가 가능하다.
    - 3월 결측치의 경우 타당한 이유가 없이 결측치를 처리 할 수 없다. 이럴땐 데이터 제공자 측에 왜 데이터가 없는지 확인하고 타당한 이유 생성해야한다. 만약 버스시스템 오류로 인한 확인 불가라는 답변이 온다면 이유가 생성 됐다면 결측치를 0으로 처리하고 타당한 이유 작성하면 된다.
    - 0 으로 처리하지 않고 3월의 전체 평균을 삽입하거나 비어있는 값 전의 값과 후의 값의 평균을 넣거나 데이터를 아예 삭제하는 방법이 있다.
  • 모든 결측치(NaN)는 0으로 대체하기
df_pivot = df_pivot.fillna(0)
df_pivot

 

 

히트맵(heatmap) 시각화

🐳 기준일 및 기준일자별 버스 이용량 시각화 분석

### 그래프 전체 너비, 높이 설정
plt.figure(figsize=(20, 10))

### 그래프 제목 넣기
plt.title("기준월 및 기준일자별 버스 이용량 분석")

### 히트맵 그리기 : 히트맵은 seaborn 라이브러리에 존재한다
# - annot : False는 집계값 숨기기, True는 집계값 보이기
# - fmt : ".0f"는 소숫점 0자리까지 보이기
# - cmap : colormap, 컬러 색상그룹
sns.heatmap(df_pivot, annot=True, fmt=".0f", cmap="rocket_r")

### 그래프 출력
plt.show()

 

  • 그래프 해석
     - 1월 ~ 3월까지의 이용량을 분석한 결과 1월에 가장 많은 이용량을 나타내고 있으며, 2월에서 3월로 가면서 이용량이 점진적으로 줄어들고 있는 것으로 확인된다.
     - 1월 이용량이 가장 많은 이유는 포항시의 특성상 외부에서 관광객의 유입에 따라, 버스를 이용하는 사람들이 많을 것으로 예상된다.
     - 이에 따라, 포항시 관광객에 대한 데이터를 수집하여 해당 년월에 대한 데이터를 비교 분석해볼 필요성이 있다.

🐳 기준일 및 기준시간별 버스 이용량 시각화 분석

df_pivot = df_bus_card_tot.pivot_table(index = "기준일",
                                       columns = "기준시간",
                                       values = "승객연령",
                                       aggfunc = "count")
# 결측치 처리
df_pivot = df_pivot.fillna(0)

# 히트맵 그리기
plt.figure(figsize=(20, 10))

plt.title("기준일 및 기준시간별 버스 이용량 분석")

sns.heatmap(df_pivot, annot=True, fmt=".0f", cmap="YlGnBu")

plt.show()

  • 그래프 해석
    - 버스 이용량에 대한 분석결과, 일반적으로 출/퇴근 시간에 많아야 할 버스 이용량이 포항시의 경우 오후 시간대에 이용량이 밀집되어있다.
    - 특히, 오후1시와 3시에 높은 이용량을 나타내고 있다.
    - 이는 출/퇴근 시간에 자가 차량을 이용하는 사람이 많을 수도 있다는 예상을 할 수 있으며,
    인구 분포가 노령인구가 많기에 오후에 이용자가 많을 수도 있을 수 있다.
    - 따라서, 포항시 인구현황 데이터, 경제활동인구 분석을 통해 비교 분석이 가능할 것으로 예상된다.
    - 또한, 해당 이용량이 높은 시간대의 노선을 확인하여 특성 확인도 필요할 것으로 예상된다.

🐳 기준시간 및 분별 버스 이용량 시각화 분석

df_pivot = df_bus_card_tot.pivot_table(index = "기준시간",
                                       columns = "기준시간(분)",
                                       values = "승객연령",
                                       aggfunc = "count")
# 결측치 처리
df_pivot = df_pivot.fillna(0)

# 히트맵 그리기
plt.figure(figsize=(20, 10))

plt.title("기준시간 및 기준시간(분)별 버스 이용량 분석")

sns.heatmap(df_pivot, annot=True, fmt=".0f", cmap="coolwarm")

plt.show()

  • 그래프 해석
    - 출근 시간대의 버스이용량을  볼 때 오전 7시 55분 ~ 8시 10분 사이에 이용량이 많은 것으로 보인다.
    - 퇴근 시간대의 버스 이용량을 볼 때 오후 6시 ~ 6시 20분까지 이용량이 많은 것으로 보인다.
    - 특히 오후 3시 20분까지 버스 이용량이 매우 크게 나타나고 있다.
    - 오후 시간대 이용자에 대한 추가 확인이 필요할 것으로 보인다. 

🐳 기준일 및 시간별 버스내체류시간(분) 시각화 분석

df_pivot = df_bus_card_tot.pivot_table(index = "기준일",
                                       columns = "기준시간",
                                       values = "버스내체류시간(분)",
                                       aggfunc = "mean")
# 결측치 처리
df_pivot = df_pivot.fillna(0)

# 히트맵 그리기
plt.figure(figsize=(20, 10))

plt.title("기준일 및 시간별 버스내체류시간(분) 시각화 분석")

sns.heatmap(df_pivot, annot=True, fmt=".3f", cmap="BuPu")

plt.show()

  • 그래프 해석
     - 매월 1일에 장거리 이용자가 다소 분포하고 있으며 오전 5시부터 8시를 전후로 장거리 이용자가 증가하고 있다.
     - 오후 5시에 장거리 이용자가 매우 많게 나타난다. 이는 포항시 주변 상권(경제활동인구)의 출/퇴근 시간의 영향을 받을 수도 있을 것으로 예상된다.
     - 오후 7시 이후로는 장거리 이용자가 보편적으로 나타나고 있으며, 위에서 분석한 기준일 및 시간별 이용량 분석에서 확인한 바와 같이 7시 이후의 버스 이용량도 급격하게 줄어드는 것을 보아 저녁시간 버스 이용이 현저히 낮은것으로 보인다.
     - 장거리 이용자가 많은 시간대에 급행버스의 도입에 대한 추가 확인은 필요할 것으로 여겨진다.


막대그래프 시각화

🐳시간대 및 승객구별 버스내체류시간(분) 시각화

  • 필요한 데이터 추출
    - 기준시간, 승객연령, 버스내체류시간(분)
df_temp = pd.DataFrame()
df_temp["기준시간"] = df_bus_card_tot["기준시간"]
df_temp["승객구분"] = df_bus_card_tot["승객연령"]
df_temp["버스내체류시간"] = df_bus_card_tot["버스내체류시간(분)"]
df_temp


  • 승객 빈도 확인하기
df_temp["승객구분"].value_counts()


  • 그룹화 하기
  • 그룹화 후 head()
    - df_temp2.head(1)
    - groupby 이후의 head()의 역할 : 행단위로 조회하는게 아니라 그룹 단위로 조회한다.
    - groupby하고 head(1) 하면 각 그룹의 첫번째 값이 조회 된다.
# sum()
df_temp2 = df_temp.groupby(["기준시간", "승객구분"], as_index=False).sum()

# 내림차순 정렬
df_temp2 = df_temp2.sort_values(by=["버스내체류시간"], ascending=False)
df_temp2


  • 데이터의 행과 열을 교환하기
df_temp2.transpose()


  • 막대그래프 시각화 하기
fig = plt.figure(figsize=(25, 10))

plt.title("시간 및 승객구분별 버스내체류시간(분) 분석")

### hue : x축 및 y축을 기준으로 비교할 대상 컬럼 지정(범주형 데이터를 보통 사용)
sns.barplot(x="기준시간", y="버스내체류시간", hue="승객구분", data=df_temp2)

plt.show()

 

 

밀도그래프 시각화( histplot )

  • 2개의 그래프 조합

🐳시간대 및 승객구별 버스내체류시간(분) 시각화

plt.figure(figsize=(12, 4))
plt.title("시간 및 승객구분별 버스내체류시간(분) 분석")

sns.histplot(data = df_temp2,
            x = "기준시간",
             
            ### 사용할 막대의 최대 갯수
            bins = 30,
             
            ### 막대그래프에 밀도 선그리기            
            kde = True,
             
            ### 범주 데이터
            hue = "승객구분",
             
            ### 여러 범주를 하나의 막대에 표현하기
            multiple = "stack",
            
            ### 비율로 표시
            stat = "density",
             
            ### 막대 너비 : 0.6은 60% 축소한 너비 사이즈
            shrink = 0.6)

plt.show()

 

 

선그래프 시각화

🐳승차하정류장별 버스내체류시간(분) 상위 30건 시각화 분석

  • 구간(승차정류장 ~ 하차정류장) 까지의 버스내 체류시간을 이용하여 체류시간이 많은 구간을 확인하기
df_temp3 = pd.DataFrame()
df_temp3["버스내체류시간"] = df_bus_card_tot["버스내체류시간(분)"]
df_temp3["승하차정류장"] = df_bus_card_tot["승차정류장"] + "-->" + \
                         df_bus_card_tot["하차정류장"]
df_temp3


  • 구간별 그룹화 하기
### 구간(승차정류장 ~ 하차정류장)별 버스내체류시간(분) sum() 그룹화 하기
df_temp_gp = df_temp3.groupby(["승하차정류장"], as_index=False).sum()

### 내림차순 정렬
df_temp_gp = df_temp_gp.sort_values(by=["버스내체류시간"], ascending=False)

### 상위 30건 추출하기
df_temp_gp.head(30)


  • 선 그래프 그리기
plt.figure(figsize=(12, 4))
plt.title("승하차정류장별 버스내 체류시간 분석")

### 선그래프
plt.plot(df_temp3["승하차정류장"], df_temp3["버스내체류시간"])

### x축 및 y축 제목 넣기
plt.xlabel("승하창정류장")
plt.ylabel("버스내체류시간(분)")

### x축의 값의 기울기를 이용하여 조정하기
# - xticks() : x축을 컨트롤하는 함수
plt.xticks(rotation=90)

### 격자선 표시하기
plt.grid(True)

plt.show()

728x90
반응형

+ Recent posts