본문 바로가기
추천시스템 앱 개발/데이터

[데이터 분석] Movielens(무비렌즈) 데이터 분석 2 - 장르별 영화 분포 분석

by 직_장인 2025. 3. 15.

1-2. 장르별 영화 분포 분석

1-2-1. 장르별 영화 수

  • movie 데이터프레임
    • movie 데이터프레임에서 각 영화는 위 이미지와 같이 여러 장르를 가지기도 한다.
    • 그리고 '|' 로 구분되기 때문에, 이 구분자를 이용하여 각 장르를 분리할 수 있다
# 장르 분리 및 집계
def extract_genres(movies_df):
    all_genres = []
    for genres in movies_df['genres']:
        all_genres.extend(genres.split('|'))
    return all_genres

all_genres = extract_genres(movies)
genre_counts = Counter(all_genres)

# 장르별 비율 계산
total_genre_mentions = sum(genre_counts.values())
print("전체 장르 언급 중 각 장르의 비율:")
for genre, count in sorted(genre_counts.items(), key=lambda x: x[1], reverse=True):
    print(f"{genre}: {count/total_genre_mentions*100:.2f}%")
  • 장르별 영화 분석
    • movies 데이터셋의 'genres' 컬럼 값을 순서대로 돌면서 '|'로 분리한 후, 각각을 all_genres라는 빈 리스트에 모두 담는다.
    • 이렇게 genres 내의 각 장르 값을 모두 한곳에 모은 뒤, Counter 함수로 각 장르별로 갯수를 센다.
    • Counter 함수는 값을 key로, 갯수를 value로 하는 dictionary 형태를 반환하기 때문에, 계산된 genre_counts는 dict 타입이다.
# 결과
전체 장르 언급 중 각 장르의 비율:
Drama: 19.75%
Comedy: 17.01%
Thriller: 8.58%
Action: 8.28%
Romance: 7.23%
Adventure: 5.72%
Crime: 5.43%
Sci-Fi: 4.44%
Horror: 4.43%
Fantasy: 3.53%
Children: 3.01%
Animation: 2.77%
Mystery: 2.59%
Documentary: 1.99%
War: 1.73%
Musical: 1.51%
Western: 0.76%
IMAX: 0.72%
Film-Noir: 0.39%
(no genres listed): 0.15%
  • 시각화
    • 앞서 구한 장르 별 갯수(genre_counts)를 데이터프레임 형태로 만든다.
    • barplot으로 그래프를 출력한다. 아래와 같이 축을 바꿔서 출력하면, y축 기준으로 순서가 한눈에 들어오게 표시할 수 있다.
# 가장 흔한 장르 시각화
plt.figure(figsize=(12, 8))
genres_df = pd.DataFrame.from_dict(genre_counts, orient='index').reset_index()
genres_df.columns = ['Genre', 'Count']
genres_df = genres_df.sort_values('Count', ascending=False)

sns.barplot(x='Count', y='Genre', data=genres_df, palette='viridis')
plt.title('장르별 영화 수', fontsize=15)
plt.xlabel('영화 수', fontsize=12)
plt.ylabel('장르', fontsize=12)
plt.grid(True, alpha=0.3)
plt.show()

  • 분석 결과
    • 계산 결과를 보면 (중복이 가능하다는 점을 염두하고) Drama, Comedy 장르의 비율이 높고, 3위부터는 점진적으로 낮아진다.
    • 영화의 타입(Thriller, Action 등)과 별개로 기승전결 스토리를 위한 Drama나 영화의 요소인 Comedy는 기본으로 깔고 들어가는 느낌이다.
    • 확인해보자!
# 장르 조합 분석
genre_combinations = movies['genres'].value_counts().head(20)
print("\n가장 흔한 장르 조합 (상위 20개):")
print(genre_combinations)

# 결과
가장 흔한 장르 조합 (상위 20개):
genres
Drama                      1053
Comedy                      946
Comedy|Drama                435
Comedy|Romance              363
Drama|Romance               349
Documentary                 339
Comedy|Drama|Romance        276
Drama|Thriller              168
Horror                      167
Horror|Thriller             135
Crime|Drama                 134
Crime|Drama|Thriller        125
Drama|War                   114
Comedy|Crime                101
Action|Comedy                92
Thriller                     84
Children|Comedy              74
Comedy|Horror                69
Action|Adventure|Sci-Fi      66
Action|Crime|Thriller        66
Name: count, dtype: int64
  • 구분하지 않은 장르 갯수(추가 분석)
    • genres 컬럼을 가공하지 않고, 그대로 갯수를 출력해보면 위와 같이 계산된다.
    • 예상했던 것처럼, Drama와 Comedy는 다른 장르와도 결합한 경우가 많다.

1-2-2. 장르별 평균 평점

  • 장르별 평균 평점 계산
    • 앞서 구한 all_genres를 set() 함수를 이용하여 중복된걸 빼고 unique한 값만 남긴다. 갯수는 20개이다.
    • 이 값을 순차적으로 대입하면서, movies 데이터프레임의 genres 컬럼에 포함되었는지를 기준으로 genre_movies를 만든다.
    • 그리고 해당 genres의 점수를 추출하여 genre_movie_ratings로 만들고, mean() 함수를 이용하여 평균값을 계산한다.
    • 맨 처음 만든 genre_ratings라는 dict에 genre를 key로, 평균값을 value로 입력한다.
    • 마지막으로 이 dictionary 형태의 genre와 평균값을 데이터프레임 형태로 만들어 genre_ratings_df 변수로 만든다.
# 장르별 평균 평점 계산
genre_ratings = {}

for genre in set(all_genres):
    # 해당 장르가 포함된 영화 ID 목록
    genre_movies = movies[movies['genres'].str.contains(genre)]['movieId'].tolist()
    # 해당 영화들의 평점
    genre_movie_ratings = ratings[ratings['movieId'].isin(genre_movies)]['rating']
    # 평균 평점 계산
    genre_ratings[genre] = genre_movie_ratings.mean()

# 장르별 평균 평점 시각화
genre_ratings_df = pd.DataFrame.from_dict(genre_ratings, orient='index', columns=['Avg_Rating'])
genre_ratings_df = genre_ratings_df.sort_values('Avg_Rating', ascending=False)

genre_ratings_df

  • 시각화
    • genre_ratings_df의 Avg_Rating(평균 평점) 값을 시각화한다.
plt.figure(figsize=(12, 8))
sns.barplot(x='Avg_Rating', y=genre_ratings_df.index, data=genre_ratings_df, palette='coolwarm')
plt.title('장르별 평균 평점', fontsize=15)
plt.xlabel('평균 평점', fontsize=12)
plt.ylabel('장르', fontsize=12)
plt.grid(True, alpha=0.3)
plt.xlim(3.0, 4.0)  # 차이를 더 명확하게 보기 위해 축 범위 조정
plt.show()

  • 분석 결과
    • 필름 느와르(Film-Noir), 전쟁(War), 다큐멘터리(Documentary) 영화는 평균적으로 높은 평점을 받는다.
    • 반면, 호러(Horror), 코미디(Comedy), SF(Sci-Fi) 영화는 상대적으로 낮은 평점을 받는다.
    • 드라마(Drama), 코미디 장르는 다른 장르와 묶여있는 경우가 많음을 앞서 확인했다.
    • 근런데, 드라마는 평균 평점이 높은 반면에 코미디는 평균 평점이 낮다.
    • 같이 묶여있는 영화들이 어떤 특징을 갖는지 추가적으로 분석해서 구분되는 특징을 찾아볼 수도 있을 것이다.
    • (하지만 아직 갈길이 멀기 때문에, 평균 평점에 관한 분석은 여기까지만 진행한다.)

댓글