아카이브/추천시스템(2019)

추천시스템 9 - 비개인적 추천 코드예제

Johnny Yoon 2019. 6. 29. 21:57
728x90
반응형

추천시스템

본 포스팅은 Minnesota대학교의 Intro to Recommender Systems코세라 강좌를 정리한 내용입니다.

https://www.coursera.org/learn/recommender-systems-introduction?specialization=recommender-systems

원본 코드 예제에서는 Excel로 코딩하게 되어있지만, 파이썬으로 코딩한 예제입니다.

 

 

 

1. 영화 평점

문제: 평균 평점을 계산하고, 최상위 3개의 영화와 점수를 구하시오

먼저 Pandas 패키지를 import 하겠습니다.

In [94]:
import pandas as pd

movies_df = pd.read_csv('./HW1-data.csv')
movies_df.head()
Out[94]:
  User Gender (1 =F, 0=M) 260: Star Wars: Episode IV - A New Hope (1977) 1210: Star Wars: Episode VI - Return of the Jedi (1983) 356: Forrest Gump (1994) 318: Shawshank Redemption, The (1994) 593: Silence of the Lambs, The (1991) 3578: Gladiator (2000) 1: Toy Story (1995) 2028: Saving Private Ryan (1998) ... 2396: Shakespeare in Love (1998) 2916: Total Recall (1990) 780: Independence Day (ID4) (1996) 541: Blade Runner (1982) 1265: Groundhog Day (1993) 2571: Matrix, The (1999) 527: Schindler's List (1993) 2762: Sixth Sense, The (1999) 1198: Raiders of the Lost Ark (1981) 34: Babe (1995)
0 755 0 1.0 5.0 2.0 NaN 4.0 4.0 2.0 2.0 ... 2.0 NaN 5.0 2.0 NaN 4.0 2.0 5.0 NaN NaN
1 5277 0 5.0 3.0 NaN 2.0 4.0 2.0 1.0 NaN ... 3.0 2.0 2.0 NaN 2.0 NaN 5.0 1.0 3.0 NaN
2 1577 1 NaN NaN NaN 5.0 2.0 NaN 4.0 NaN ... NaN 1.0 4.0 4.0 1.0 1.0 2.0 3.0 1.0 3.0
3 4388 0 NaN 3.0 NaN NaN NaN 1.0 2.0 3.0 ... NaN 4.0 1.0 3.0 5.0 NaN 5.0 1.0 1.0 2.0
4 1202 1 4.0 3.0 4.0 1.0 4.0 1.0 NaN 4.0 ... 5.0 1.0 NaN 4.0 NaN 3.0 5.0 5.0 NaN NaN

5 rows × 22 columns

 

가장 왼쪽으 두 컬럼은 사용자 ID와 성별 값이니 Drop하고,
평균값을 구한 뒤 상위 3개만 보여주겠습니다.

In [32]:
movies_df_scores = movies_df.drop(movies_df.columns[:2], axis=1)
movies_df_scores.mean().sort_values(ascending=False)[:3]
Out[32]:
318: Shawshank Redemption, The (1994)             3.600000
260: Star Wars: Episode IV - A New Hope (1977)    3.266667
541: Blade Runner (1982)                          3.222222
dtype: float64
 

결과를 보면, 평점이 가장 좋은 영화들은:

  1. 쇼생크탈출 (평균평점 3.60)
  2. 스타워즈 4 (평균평점 3.27)
  3. 블레이드러너 (평균평점 3.22)

라는 것을 알 수 있습니다.

 

2. 평점 카운트 (인기도)

문제: 영화 중 평점이 매겨진것을 카운트 하고, 가장 많이 매겨진 영화 3개를 찾으시오.

위에서 만들어놓은 movies_df_scores를 이용하면 간단합니다. count 메소드를 사용해 NaN이 아닌 모든 셀을 카운트 합니다.

In [99]:
movies_df_scores.count().sort_values(ascending=False)[:3]
Out[99]:
1: Toy Story (1995)                               17
593: Silence of the Lambs, The (1991)             16
260: Star Wars: Episode IV - A New Hope (1977)    15
dtype: int64
 

결과를 보면, 인기가 가장 좋은 영화들은:

  1. 토이스토리 (평가 17개)
  2. 양들의침묵 (평가 16개)
  3. 스타워즈4 (평가 15개)

라는 것을 알 수 있습니다.

 

3. 4+평점의 퍼센테지

문제: 평점이 4+가 가장 많은 영화를 3개 구하시오.

강의를 보시면, 4+평점을 좋은 평점으로 사용한 적이 있다는 것을 아실 수 있습니다.
먼저 평점이 4+인 셀들은 Boolean Indexing으로 쉽게 구할 수 있습니다.

In [42]:
movies_df_scores[movies_df_scores >= 4.0].head()
Out[42]:
  260: Star Wars: Episode IV - A New Hope (1977) 1210: Star Wars: Episode VI - Return of the Jedi (1983) 356: Forrest Gump (1994) 318: Shawshank Redemption, The (1994) 593: Silence of the Lambs, The (1991) 3578: Gladiator (2000) 1: Toy Story (1995) 2028: Saving Private Ryan (1998) 296: Pulp Fiction (1994) 1259: Stand by Me (1986) 2396: Shakespeare in Love (1998) 2916: Total Recall (1990) 780: Independence Day (ID4) (1996) 541: Blade Runner (1982) 1265: Groundhog Day (1993) 2571: Matrix, The (1999) 527: Schindler's List (1993) 2762: Sixth Sense, The (1999) 1198: Raiders of the Lost Ark (1981) 34: Babe (1995)
0 NaN 5.0 NaN NaN 4.0 4.0 NaN NaN NaN NaN NaN NaN 5.0 NaN NaN 4.0 NaN 5.0 NaN NaN
1 5.0 NaN NaN NaN 4.0 NaN NaN NaN NaN 4.0 NaN NaN NaN NaN NaN NaN 5.0 NaN NaN NaN
2 NaN NaN NaN 5.0 NaN NaN 4.0 NaN NaN NaN NaN NaN 4.0 4.0 NaN NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN NaN NaN NaN 4.0 NaN NaN 4.0 NaN NaN 5.0 NaN 5.0 NaN NaN NaN
4 4.0 NaN 4.0 NaN 4.0 NaN NaN 4.0 NaN NaN 5.0 NaN NaN 4.0 NaN NaN 5.0 5.0 NaN NaN
 

이것을 이용해 위의 문제들과 같이 정답을구해보겠습니다.

In [46]:
movies_df_scores[movies_df_scores >= 4.0].count().sort_values(ascending=False)[:3]
Out[46]:
260: Star Wars: Episode IV - A New Hope (1977)    8
318: Shawshank Redemption, The (1994)             7
593: Silence of the Lambs, The (1991)             7
dtype: int64
 

결과를 보면, 4+평점이 가장 많은 영화들은:

  1. 스타워즈4 (8개)
  2. 쇼생크탈출 (7개)
  3. 양들의침묵 (7개)

라는 것을 알 수 있습니다.
(sort_values 뒤 코드를 제외하고 실행시키시면, 8은 한개 7은 두개가 나옵니다.)

 

4. 토이스토리와 다른 영화와의 관계

문제: 토이스토리를 본 사람들이 어떤 영화를 봤는지 알기 위해,
(x+y)/x 수식을 이용해 토이스토리와 다른 영화들의 공존관계를 구하시오.

이전 문제들보다는 조금 복잡한 문제입니다.
위의 수식은 "(선택된 영화 & 다른영화) / 선택된영화" 수식으로 다시 표현할 수 있습니다.
먼저 영화별 확률을 구하기 위해 새로운 Series에 카운트값을 저장하도록 하겠습니다.
그리고 토이스토리를 drop해주겠습니다.

In [78]:
rating_counts = movies_df_scores.count().drop('1: Toy Story (1995)')
rating_counts.head()
Out[78]:
260: Star Wars: Episode IV - A New Hope (1977)             15
1210: Star Wars: Episode VI - Return of the Jedi (1983)    14
356: Forrest Gump (1994)                                   10
318: Shawshank Redemption, The (1994)                      10
593: Silence of the Lambs, The (1991)                      16
dtype: int64
 

이제 여기에 위 수식을 적용해보도록 하겠습니다.
토이스토리의 카운트를 x값으로 놓고 rating값들에 적용한 결과입니다.

In [79]:
x = movies_df_scores['1: Toy Story (1995)'].count()
rating_counts = rating_counts.apply(lambda y: (x + y) / y)
rating_counts.head()
Out[79]:
260: Star Wars: Episode IV - A New Hope (1977)             2.133333
1210: Star Wars: Episode VI - Return of the Jedi (1983)    2.214286
356: Forrest Gump (1994)                                   2.700000
318: Shawshank Redemption, The (1994)                      2.700000
593: Silence of the Lambs, The (1991)                      2.062500
dtype: float64
 

마지막으로 이를 정렬한 결과중 상위 3개를 가져오면 됩니다.

In [57]:
rating_counts.sort_values(ascending=False)[:3]
Out[57]:
593: Silence of the Lambs, The (1991)                      9.242424
260: Star Wars: Episode IV - A New Hope (1977)             8.968750
1210: Star Wars: Episode VI - Return of the Jedi (1983)    8.677419
dtype: float64
 

결과를 보면, 토이스토리를 봤던 사람들이 본 다른 영화들 중 가장 많이 본것은:

  1. 양들의침묵
  2. 스타워즈 4
  3. 스타워즈 6

인것을 알 수 있습니다.

 

5 토이스토리와의 연관성

문제: 토이스토리와 연관성이 있는 영화들을 찾아보시오.

이번에는 연관성 문제입니다.
먼저 토이스토리와 다른 영화들의 피어슨 연관도를 구해보겠습니다.
Pandas에서 피어슨 연관도는 corr 메소드를 이용해 쉽게 구할 수 있습니다.
연관도에서 토이스토리 줄만 뽑은 결과입니다.

In [80]:
corr = movies_df_scores.corr('pearson')['1: Toy Story (1995)']
corr.head()
Out[80]:
260: Star Wars: Episode IV - A New Hope (1977)            -0.119005
1210: Star Wars: Episode VI - Return of the Jedi (1983)   -0.314504
356: Forrest Gump (1994)                                   0.522913
318: Shawshank Redemption, The (1994)                      0.888523
593: Silence of the Lambs, The (1991)                     -0.568258
Name: 1: Toy Story (1995), dtype: float64
 

상위 3개의 영화를 뽑기 위해, 토이스토리를 drop하고,
나머지 값들중에 최상위 3개를 뽑아내겠습니다.

In [81]:
corr.drop('1: Toy Story (1995)').sort_values(ascending=False)[:3]
Out[81]:
318: Shawshank Redemption, The (1994)    0.888523
34: Babe (1995)                          0.811107
296: Pulp Fiction (1994)                 0.709842
Name: 1: Toy Story (1995), dtype: float64
 

결과를 보면, 토이스토리와 평점에서 연관성이 있는 영화들은:

  1. 쇼생크달출
  2. 꼬마돼지 베이브
  3. 펄프 픽션

인것을 알 수 있습니다.

 

6 성별 평균 평점

문제: 모든 영화에 대한 성별간의 평점을 구하시오.
문제: 각 성별간 상위 3개의 영화를 구하시오.
문제: 성별간 평점 차이가 큰 영화를 각각 구하시오.
문제: 성별의 모든 평점을 더한값의 차이를 구하시오 (여성평점 - 남성평점).

이번 문제는 성별간의 평점을 구하고, 비교하는 문제입니다.
Pandas에서 제공하는 groupby를 이용해 풀어보겠습니다.

In [100]:
grouped_gender = movies_df.drop('User', axis=1).groupby('Gender (1 =F, 0=M)')
grouped_means = grouped_gender.mean()
grouped_means
Out[100]:
  260: Star Wars: Episode IV - A New Hope (1977) 1210: Star Wars: Episode VI - Return of the Jedi (1983) 356: Forrest Gump (1994) 318: Shawshank Redemption, The (1994) 593: Silence of the Lambs, The (1991) 3578: Gladiator (2000) 1: Toy Story (1995) 2028: Saving Private Ryan (1998) 296: Pulp Fiction (1994) 1259: Stand by Me (1986) 2396: Shakespeare in Love (1998) 2916: Total Recall (1990) 780: Independence Day (ID4) (1996) 541: Blade Runner (1982) 1265: Groundhog Day (1993) 2571: Matrix, The (1999) 527: Schindler's List (1993) 2762: Sixth Sense, The (1999) 1198: Raiders of the Lost Ark (1981) 34: Babe (1995)
Gender (1 =F, 0=M)                                        
0 3.125000 3.0 2.25 3.4 3.333333 2.833333 2.300000 3.142857 2.625 3.000000 2.142857 2.200000 2.857143 3.0 3.500000 3.142857 3.5 2.666667 3.666667 2.000000
1 3.428571 3.0 3.00 3.8 2.714286 3.000000 3.571429 2.750000 4.000 2.428571 4.250000 1.714286 2.666667 3.5 2.833333 2.400000 2.5 3.000000 2.000000 3.428571
 

이제 각 성별의 평점 중 상위 3개의 영화를 뽑아보겠습니다.

In [128]:
male_means = grouped_means.loc[0].sort_values(ascending=False)
female_means = grouped_means.loc[1].sort_values(ascending=False)

print('Male Top 3: \n', male_means[:3])
print()
print('Female Top 3: \n', female_means[:3])
 
Male Top 3: 
 1198: Raiders of the Lost Ark (1981)    3.666667
527: Schindler's List (1993)            3.500000
1265: Groundhog Day (1993)              3.500000
Name: 0, dtype: float64

Female Top 3: 
 2396: Shakespeare in Love (1998)         4.25
296: Pulp Fiction (1994)                 4.00
318: Shawshank Redemption, The (1994)    3.80
Name: 1, dtype: float64
 

결과를 보면, 남성들이 가장 선호하는 영화들은:

  1. 레이더스
  2. 쉰들러 리스트
  3. 사랑의 블랙홀

여성들이 가장 선호하는 영화들은:

  1. 셰익스피어 인 러브
  2. 펄프 픽션
  3. 쇼생크 탈출

인것을 알 수 있습니다.

 

이번에는 차이가 가장 큰 영화들을 뽑아보겠습니다.
차이가 크다는 이야기는 한 영화를 특별히 남성/여성이 더 좋아했다는 의미입니다.

In [130]:
top_males = (male_means -  female_means).sort_values(ascending=False)[:1]
top_females = (female_means -  male_means).sort_values(ascending=False)[:1]
print('top by males:\n{},\n\ntop by females:\n{}'.format(top_males, top_females))
 
top by males:
1198: Raiders of the Lost Ark (1981)    1.666667
dtype: float64,

top by females:
2396: Shakespeare in Love (1998)    2.107143
dtype: float64
 

남성들이 더 선호하는 영화는 "레이더스"이고,
여성들이 더 선호하는 영화는 "셰익스피어 인 러브" 인 것 같습니다.

 

마지막으로 평점들의 합의 차이를 구해보겠습니다.
이것을 구하는 이유는, 어떤 성별이 대체적으로 평점을 더 후하게 주는지 알아보기 위함인 것 같습니다.

In [134]:
female_means.sum() - male_means.sum()
Out[134]:
2.299999999999997
 

결과는 여성이 더 평점을 후하게 주는 경향이 있는 것 같습니다.

 

7 성별 4+평점

문제: 각 성별간 4+평점의 차이를 구하시오.

마지막은 위에서 사용했던 grouping을 이용해 간단하게 구할 수 있습니다.
Boolean Indexing을 사용해 4+평점을 구하고 모두 더한 뒤 그 값을 빼주겠습니다.

In [133]:
female_means[female_means >= 4.0].sum() - male_means[male_means >= 4.0].sum()
Out[133]:
8.25
 

결과적으로 우리가 사용한 데이터셋에서는 여성들이 4+평점을 더 많이 준것으로 보입니다.

 

 

원본 소스를 확인하시려면 다음 링크로 가시면 됩니다:
https://github.com/ydy1128/coursera-recommender-systems/tree/master/ex1

728x90
반응형