안녕하세요 :D 서칭하던 중 재미있어보이는 데이터를 발견했습니다.
미네소타 대학의 컴퓨터 과학 연구 그룹인 GroupLens에서 공개한 MovieLens 데이터셋으로, GroupLens의 연구 분야 중 하나인 인공지능 추천 시스템을 위해 만들어진 데이터셋입니다.
86,537편의 영화와 그와 관련된 33,832,162개의 평점 및 2,328,315개의 태그로 구성되어있는데, 볼륨이 꽤 커서 직접 활용해보지 못했던 기술들을 실전에 유사한 환경에서 만들어 볼 수 있을것 같다는 생각이 들었습니다.
프로젝트는 처음 RDBMS
부터 시작하여, 일부 데이터들을 다른 기술들로 전환하여 점진적으로 개선하는 방식으로 진행해보려고 합니다.
오늘은 첫 걸음으로 데이터가 어떤 형식으로 구성되어있는지 간략하게 살펴보고, 어떤 형태로 설계할지 고민해보겠습니다.
Python3
와 Pandas
를 활용하여 간단히 확인를 했는데, 환경 구성과 같은 내용들은 Movielens 데이터셋 구조 확인 레포지토리를 참고해주시면 되겠습니다.
데이터셋에 대한 정보는 README.html에 상세히 나와있습니다.
데이터셋 구성
데이터셋은 userId
, movieId
를 공통으로 활용하고 있고, 앞서 설명드렸던 영화, 평점, 태그 포함 총 6개의 .csv
파일로 구성되어 있습니다.
userId
- MovieLens의 사용자로 무작위 선택
movieId
- MovieLens에 등록된 영화로, 등급이나 태그가 하나 이상 등록된 영화
포함된 데이터 중 영화에 대한 태그 관련성 점수를 포함하는 데이터 셋인 태그 게놈(genome-scores.csv
, genome-tags.csv
)와 영화 데이터의 다른 소스에 연결하기 위한 식별자 정보가 담겨있는 links.csv
데이터는 활용하지 않겠습니다.
movies
영화 데이터는 movieId
, title
, genres
로 구성되어 있습니다.
영화의 제목들은 직접 입력되었거나, https://www.themoviedb.org/에서 가져온 데이터로, 괄호 안에 개봉년이 포함되어 있으나 정확하지 않을 수 있다고 합니다.
영화 장르들을 모두 포함하고있는 genres
컬럼은 아래의 19개 장르중 일부를 |
문자로 합친 형태로 구성된다고 합니다.
- Action
- Adventure
- Animation
- Children’s
- Comedy
- Crime
- Documentary
- Drama
- Fantasy
- Film-Noir
- Horror
- Musical
- Mystery
- Romance
- Sci-Fi
- Thriller
- War
- Western
- (no genres listed)
장르가 없는 경우는 (no genres listed)가 입력되는 것으로 보아 NULL
을 허용하지는 않는 것으로 보이네요.
|
|
파일을 pandas DataFrame
으로 열고 건수를 확인해보니, 처음 언급한대로 86,537건이었습니다.
|
|
최상단 5건을 확인해보니, README.html에 언급된 형식으로 데이터들이 저장되어 있는 것으로 보입니다.
movieId | title | genres |
---|---|---|
1 | Toy Stroy (1995) | Adventure|Animation|Children|Comedy|Fantasy |
2 | Jumanji (1995) | Adventure|Children|Fantasy |
3 | Grumpier Old Men (1995) | Comedy|Romance |
4 | Waiting to Exhale (1995) | Comedy|Drama|Romance |
5 | Father of the Bride Part II (1995) | Comedy |
genres
컬럼 같은 경우 공식 설명과는 달리 총 20개로 IMAX
가 추가되있습니다. 누락되었나보네요.
|
|
|
|
IMAX
가 포함된 장르를 가지는 레코드들은 총 195건으로 많지는 않지만 데이터 분포 같은 것들이 중요한 요소는 아니기때문에 그냥 활용해도 괜찮을 것 같습니다.
눈에 띄는점은 genres
컬럼인데, 각 장르가 |
문자로 구분되어 여러개 항목이 들어있습니다. 장르들이 영어 오름차순으로 정렬되어 저장되어있는 것으로 보이네요.
이러한 경우 일반적인 RDBMS에서 genres
를 조건으로 이용하여 SELECT
하게 될 경우 %{keyword}%
로 처리해야하므로 인덱스를 활용할 수 없고, 이로 인해 성능에서 문제가 발생할 수 있습니다.
genres
컬럼들의 각 장르들을 카테고리 테이블로 분리하고 movieId
와 장르 간 1:N 테이블을 추가하는 방식으로 바꾼다면 장르를 이용한 검색 조건으로 인덱스를 사용할 수 없는 문제는 해결할 수 있습니다만…
genres
가 여러개의 장르를 포함할 수 있다는 특성으로 인해 쿼리 작성할 때 조인을 사용하면 movies
의 컬럼들이 중복됩니다.
이로 인해 서브 쿼리나 CONCAT
과 같은 처리를 필요로 하거나, movieId
로 장르를 조회하는 방식으로 처리해야 하므로 조회 성능이 떨어질 수 있음은 물론, 테이블 구조가 불필요하게 복잡해집니다.
genres
의 데이터 형태와 한번 등록되면 변하지 않는 장르의 특성으로 볼 때, 단순 조회를 위한 컬럼이지 않을까 추측되고, 검색 기능은 검색 엔진을 별도로 구성하는 방식으로 처리되고 있을 것 같다는 예상을 해봅니다.
일단 RDBMS를 이용한 genres
컬럼 조건 검색은 배제하고 이후 더 좋은 방법을 고려하는 것이 좋겠습니다.
tags
태그 데이터는 userId
, movieId
, tag
, timestamp
로 구성되어 있습니다.
각 행은 한명의 사용자가 한 영화에 적용한 하나의 태그를 의미합니다.
tag
는 단일 단어나 짧은 문구로 구성되며, 의미, 가치, 목적은 각 사용자의 목적에 의해 결정됩니다.
데이터는 총 2,328,315건으로 확인됩니다.
|
|
userId | movieId | tag | timestamp |
---|---|---|---|
10 | 260 | good vs evil | 1430666558 |
10 | 260 | Harrison Ford | 1430666505 |
10 | 260 | sci-fi | 1430666538 |
14 | 1221 | Al Pacino | 1311600756 |
14 | 1221 | mafia | 1311600746 |
tags.csv
파일을 읽어 최상단 5건을 확인해보면 1명의 사용자가 여러개의 영화에 여러개의 태그를 남길 수 있다는 것을 예상해볼 수 있습니다.
|
|
유니크한 tag
값은 153,950건 입니다.
tags.csv
는 사용자가 한 영화에 적용한 태그로 1명의 유저가 여러 영화에 여러 종류의 태그를 적용할 수 있습니다.
전체 항목은 2,328,315건 이지만, tag
컬럼의 유니크한 값의 개수는 153,950개 인 것을 확인할 수 있습니다.
이러한 특성을 지닌 tag.csv
의 데이터를 RDBMS에 저장하는 것이 좋은 방법인가 의구심이 들긴 하지만, 일반적인 서비스 정책으로 예상해 볼 때(특정 영화에 적용된 태그들 조회, 사용자가 활용한 태그들 조회, 사용자가 특정 영화에 남긴 태그 조회 등) 인덱스 설정만 잘 해준다면 화면에 노출 될 데이터 조회 성능에는 큰 이슈는 없어 보입니다.
처음엔 RDBMS로 처리하더라도 이후 새로운 요구가 있다면, 다른 방법으로 변경을 고려할 수 있겠습니다.
ratings
|
|
userId | movieId | rating | timestamp |
---|---|---|---|
1 | 1 | 4.0 | 1225734739 |
1 | 110 | 4.0 | 1225865086 |
1 | 158 | 4.0 | 1225733503 |
1 | 260 | 4.5 | 1225735204 |
1 | 356 | 5.0 | 1225735119 |
평가 데이터는 userId
, movieId
, rating
, timestamp
로 구성되어 있습니다.
각 행은 한 사용자가 한 영화에 남긴 점수를 의미합니다.
|
|
총 데이터 수는 33,832,162건, 최대, 최소값은 각각 0.5, 5.0 입니다.
ratings.csv
는 영화에 대한 사용자의 평점으로 영화 하나에 하나만 만들 수 있습니다.
영화 목록을 검색할 때 일반적으로 평균 평점이 포함되는데, 현재 상태로 테이블을 생성할 시 조회 처리에서 GROUP BY
나 서브 쿼리를 통해 평균을 계산한다던가, 활용된 값들을 조회하는 처리가 필요하게 되고, 이 때문에 조회 성능에 문제가 발생할 수 있습니다.
이를 방지 위해 movies
테이블에 통계 정보에 활용될 컬럼을 만들어 두는 방식으로 설계하는 것도 고려해볼 수 있겠습니다.
rating
컬럼도 꼭 소수로 넣을 필요는 없어보이네요.
끝으로
간단하게 MovieLens 데이터셋의 주요 데이터들을 확인해봤습니다.
영화들에 대한 메타데이터가 없어 다채로운 기능들은 구현할 수 없을 것 같다는 점이 조금 아쉬운 마음에 찾아보니 MovieLens 데이터를 기반으로 TBMS API이용하여 만든 The Movies Dataset 데이터가 Kaggle에 공개되어 있었습니다.
하지만 데이터가 최신화가 안되어 사용할 수 없는 데이터가 많아 사용은 보류했습니다.
일단 생각하고 있는 기능들은 MovieLens 데이터으로 충분해서 필요는 없지만, 여유가 된다면 제가 최신화를 해봐도 괜찮을 것 같네요.
다음은 각 데이터의 특성을 고려하여 테이블을 설계하고, DB에 적재해볼예정입니다.
부족한 글 끝까지 읽어주셔서 감사합니다 :D