스릴러 장르의 평균 평점이 높지 않았던 걸 생각하면, 스릴러 영화는 명작 아니면 졸작 느낌..?
가장 많이 평가된 영화 대부분이 1990년대 영화이다. 이 그래프는 실제 이 시기에 영화가 얼마나 많이 만들어졌는지와 함께 봐야 의미가 있을 것 같다. 시간에 따른 트렌드는 아래에서 살펴보기로 한다.
1-3-2. 평균 평점이 높은 영화
의미있는 평균값
우리가 장르별 영화 분포 분석에서 평균값을 계산할 때, 갯수를 중요하게 생각하지는 않았다.
하지만, 그건 영화를 크게 장르별로 구분했을 때 평균을 계산하기 위한 데이터 수가 충분하다는 가정이 있었기 때문이다.
만약 영화별로 평균 평점을 구하려면 똑같이 해도 될까?
아니다. 한번 점수를 5점으로 받아서 평균이 5점인 영화와, 100번 점수를 5점으로 받아 평균이 5점인 영화를 비교한다면 평균 점수는 같을 것이다. 하지만 명백히 다른 의미를 갖는다.
따라서, 평균값이 의미있는 영화를 기준(최소 100개 이상의 평점이 있는 영화)으로 평균 평점이 높은 영화를 확인한다,
# 평균 평점이 높은 영화 (최소 100개 이상의 평점이 있는 영화 중)
movie_avg_ratings = ratings.groupby('movieId')['rating'].agg(['mean', 'count']).reset_index()
min_ratings = 100 # 최소 평점 수 기준
qualified_movies = movie_avg_ratings[movie_avg_ratings['count'] >= min_ratings]
qualified_movies = qualified_movies.merge(movies, on='movieId')
top_avg_rated = qualified_movies.sort_values('mean', ascending=False).head(20)
print(f"\n평균 평점이 높은 영화 (최소 {min_ratings}개 이상의 평점, 상위 20개):")
display(top_avg_rated[['title', 'mean', 'count', 'genres']])
평균 평점이 높은 영화
ratings 데이터프레임을 groupby() 함수를 이용하여, movieId를 기준으로 묶고 점수(rating)값을 표시한다.
이때 agg() 함수를 이용하여 점수 평균(mean), 점수 갯수(count)에 대해 값을 구하고 이를 movie_avg_ratings로 만든다.
movie_avg_ratings 데이터프레임에서 갯수가 min_ratings(=100)보다 큰 영화만 필터링 한다.
영화명(title)을 확인하기 위해 movies 데이터프레임을 결합한다.
평점을 기준으로 정렬한다.
시각화
genre_ratings_df의 Avg_Rating(평균 평점) 값을 시각화한다.
# 시각화
plt.figure(figsize=(14, 10))
sns.barplot(x='mean', y='title', data=top_avg_rated.head(15), palette='viridis')
plt.title(f'평균 평점이 높은 영화 (최소 {min_ratings}개 이상의 평점, 상위 15개)', fontsize=15)
plt.xlabel('평균 평점', fontsize=12)
plt.ylabel('영화 제목', fontsize=12)
plt.grid(True, alpha=0.3)
plt.xlim(4.0, 5.0) # 차이를 더 명확하게 보기 위해 축 범위 조정
plt.show()
분석 결과
평점 갯수를 기준으로 높은 위치를 차지했던 스릴러(Thriller) 영화가 평균 평점을 기준으로도 상위권에 위치해있다. 명작 아니면 졸작이라는 가정이 신빙성이 있어보인다.
또한 평점 갯수와 평균 평점 사이에 약한 상관관계가 있는 것 같기도 하다.
1-3-3. 상관 관계 분석
평점 수와 평균 평점 사이의 관계 분석
상관관계(correlation) 값을 계산하는 corr() 함수를 이용하여 손쉽게 계산 가능하다.
# 상관계수 계산
correlation = movie_avg_ratings['count'].corr(movie_avg_ratings['mean'])
print(f"평점 수와 평균 평점의 피어슨 상관계수: {correlation:.4f}")
평점 수와 평균 평점의 피어슨 상관계수: 0.1273
상관계수는 0 ~ 1의 값을 가지며, 1에 가까울수록 강한 상관관계를 갖는다.
일반적으로 0.1~0.3이면 매우 약한 상관관계라고 해석한다.
(상관계수를 볼 때 p-value도 같이 확인해야 하는데, 이번 분석에선 생략한다.)
시각화
상관관계가 약하더라도 특정 패턴이 있을 수 있으므로, seaborn의 scatterplot()을 활용해 산점도를 그려본다.
# 평점 수와 평균 평점 사이의 관계 분석
plt.figure(figsize=(10, 6))
sns.scatterplot(x='count', y='mean', data=movie_avg_ratings, alpha=0.5)
plt.title('평점 수와 평균 평점의 관계', fontsize=15)
plt.xlabel('평점 수', fontsize=12)
plt.ylabel('평균 평점', fontsize=12)
plt.xscale('log') # 로그 스케일로 표시하여 분포를 더 잘 볼 수 있게 함
plt.grid(True, alpha=0.3)
plt.show()
분석 결과
산점도로 표현하니 추세가 잘 보인다. 평점 갯수가 많아질 수록 평균 평점이 높아지는걸 볼 수 있다.
재미있는 영화일 수록 많이 보고 평점도 높게 주지만, 재미없는 영화는 많이 안보고 점수를 주지도 않은 것으로 해석할 수도 있다.
1-3-4. 트렌드 분석
연도별 영화 수 분석
가장 많이 평가된 영화를 확인할 때, 동일 시점에 얼마나 많은 영화가 만들어졌는지 같이 확인해봐야 한다는걸 알았다.
연도별로 얼마나 많은 영화가 만들어졌는지 확인해보자.
movies 데이터프레임의 title에 각 영화의 개봉 연도가 함께 표시되어 있다.
movies 데이터프레임의 title에서 str(string:문자열)의 extract() 함수를 이용하여 괄호 안에 4자리 값(연도)을 추출한다.
데이터 타입을 float으로 바꾼다.(int로 하는게 직관적으로 좋지만, Nan(빈 값)이 있는 경우엔 int로 변환이 안되기 때문에 float으로 한다.)
movies 데이터프레임의 year 값의 갯수를 계산하여, 연도 별 영화 수를 year_counts로 만든다.
year_counts는 pandas의 series 타입이 된다. index(연도)와 value(갯수)만 있기 때문에 뒤에 plot을 붙여서 바로 시각화 할 수 있다.
# 연도별 영화 수 분석
year_counts = movies['year'].value_counts().sort_index()
plt.figure(figsize=(15, 6))
year_counts.plot(kind='line', marker='o', markersize=4)
plt.title('연도별 영화 수', fontsize=15)
plt.xlabel('개봉 연도', fontsize=12)
plt.ylabel('영화 수', fontsize=12)
plt.grid(True, alpha=0.3)
plt.show()
분석 결과
1980년대부터 2000년대까지 영화 산업이 급격하게 성장했고, 2000년 이후로는 250~300개 수준으로 유지된다.
1990년대에 이후로 좋은 평가를 받은 작품은 다른 많은 경쟁작들보다 좋은 평가를 받은 것이기 때문에 명작이라고 이야기할 수 있을 것이다.
최근 장르 트렌드 분석
2000년 이후부터 장르 별 영화 수를 파악해보자.
for문을 이용해서 장르를 하나씩 가져오고, recent_years(2000~2021)의 연도를 하나씩 가져온다.
이 두가지 조건을 만족하는 영화를 movies 데이터프레임에서 색인한 후 len() 함수로 갯수를 계산하여 count 값으로 만든다.
이렇게 하나의 장르의 연도별 영화 갯수를 yearly_counts 리스트로 묶은 후 genre_trends인 dictonary에 장르(genre)를 key로, yearly_counts 리스트를 value로 값을 입력한다.
모든 장르에 대해 계산한 뒤 데이터프레임 형태로 만든다.
# 최근 20년간 장르 트렌드 분석
recent_years = range(2000, 2021)
genre_trends = {}
for genre in sorted(set(all_genres)):
yearly_counts = []
for year in recent_years:
# 해당 연도, 해당 장르의 영화 수
count = len(movies[(movies['year'] == year) & (movies['genres'].str.contains(genre))])
yearly_counts.append(count)
genre_trends[genre] = yearly_counts
genre_trends = pd.DataFrame(genre_trends)
genre_trends
genre_trends
시각화
상위 8개 장르에 대해서 시각화한다.
genre_trends 데이터프레임에서 sum() 함수를 이용하여 열 방향(axis=0)으로 장르 별 총 갯수를 구한 뒤 정렬하여 상위 8개 장르를 top_tenre_names로 만든다.
각 장르별로 연도에 따른 영화 갯수값을 계산해두었기 때문에, for문을 이용하여 장르별 plot을 반복해서 그리면 된다.
# 상위 8개 장르만 시각화
top_genres = genre_trends.sum(axis=0).sort_values(ascending=False).head(8)
top_genre_names = top_genres.index
plt.figure(figsize=(15, 8))
for genre in top_genre_names:
if genre in genre_trends:
plt.plot(list(recent_years), genre_trends[genre], marker='o', markersize=4, label=genre)
plt.title('최근 20년간 주요 장르 트렌드', fontsize=15)
plt.xlabel('연도', fontsize=12)
plt.ylabel('영화 수', fontsize=12)
plt.legend(fontsize=10)
plt.grid(True, alpha=0.3)
plt.show()
분석 결과
드라마, 코미디는 다른 장르와 묶인 경우가 많기 때문에 대체적으로 높지만, 2010년 이후로 그 격차가 줄어 거의 동일한 비율이 된다.
스릴러, 액션, SF의 경우 시기에 따라 변동이 있다. 아무래도 연도별로 영화 제작자가 선호하는 장르가 바뀌는 것 같다.
댓글