ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Data Science 기초] IMDB 영화 정보 데이터 시각화 및 분석
    Data Science/Data Science in R 2018. 10. 24. 01:28

    목표 : Kaggle의 포켓몬스터 데이터를 다운받아 분석해보자.

    데이터 다운 링크 : https://www.kaggle.com/carolzhangdc/imdb-5000-movie-dataset


    * 시각화 및 분석은 R Language를 활용하였음


    분석할 내용은 다음과 같다.


    a. 이 데이터는 어떤 변수로 이루어져 있는가?

    b. 시각화를 통해 다음 질문에 답해보자

      i. 연도별 영화의 편수는?

      ii. 연도별 리뷰평점의 변화는?

      iii. 영상물 등급(content_rating)에 따라서 리뷰평점의 분포에 차이가 있는가?

      iv. 페이스북 좋아요 개수와 리뷰평점의 사이의 관계는?


    1. Steps to Read Data

    1) Kaggle에서 IMDB 영화 정보 데이터를 다운받아 read한다. 사용할 데이터는 해당 프로젝트 폴더에 삽입되어 있어야 Read가 가능하다. read_csv()는 데이터 저장 방식 중 하나인 csv 파일을 읽는 함수이다.

    > #install.packages("tidyverse")

    > library(tidyverse)

    > library(dplyr)

    > df = read_csv("movie_metadata.zip")

    Parsed with column specification:

    cols(

      .default = col_integer(),

      color = col_character(),

      director_name = col_character(),

      actor_2_name = col_character(),

      genres = col_character(),

      actor_1_name = col_character(),

      movie_title = col_character(),

      actor_3_name = col_character(),

      plot_keywords = col_character(),

      movie_imdb_link = col_character(),

      language = col_character(),

      country = col_character(),

      content_rating = col_character(),

      imdb_score = col_double(),

      aspect_ratio = col_double()

    )

    See spec(...) for full column specifications.


    데이터 read를 완료했다면 a의 답은 다음과 같다.

    > glimpse(df)

    Observations: 5,043

    Variables: 28

    $ color                     <chr> "Color", "Color", "Color", "Color", NA, "Color", "Color", "Color"...

    $ director_name             <chr> "James Cameron", "Gore Verbinski", "Sam Mendes", "Christopher Nol...

    $ num_critic_for_reviews    <int> 723, 302, 602, 813, NA, 462, 392, 324, 635, 375, 673, 434, 403, 3...

    $ duration                  <int> 178, 169, 148, 164, NA, 132, 156, 100, 141, 153, 183, 169, 106, 1...

    $ director_facebook_likes   <int> 0, 563, 0, 22000, 131, 475, 0, 15, 0, 282, 0, 0, 395, 563, 563, 0...

    $ actor_3_facebook_likes    <int> 855, 1000, 161, 23000, NA, 530, 4000, 284, 19000, 10000, 2000, 90...

    $ actor_2_name              <chr> "Joel David Moore", "Orlando Bloom", "Rory Kinnear", "Christian B...

    $ actor_1_facebook_likes    <int> 1000, 40000, 11000, 27000, 131, 640, 24000, 799, 26000, 25000, 15...

    $ gross                     <int> 760505847, 309404152, 200074175, 448130642, NA, 73058679, 3365303...

    $ genres                    <chr> "Action|Adventure|Fantasy|Sci-Fi", "Action|Adventure|Fantasy", "A...

    $ actor_1_name              <chr> "CCH Pounder", "Johnny Depp", "Christoph Waltz", "Tom Hardy", "Do...

    $ movie_title               <chr> "Avatar ", "Pirates of the Caribbean: At World's End ", "Spectre ...

    $ num_voted_users           <int> 886204, 471220, 275868, 1144337, 8, 212204, 383056, 294810, 46266...

    $ cast_total_facebook_likes <int> 4834, 48350, 11700, 106759, 143, 1873, 46055, 2036, 92000, 58753,...

    $ actor_3_name              <chr> "Wes Studi", "Jack Davenport", "Stephanie Sigman", "Joseph Gordon...

    $ facenumber_in_poster      <int> 0, 0, 1, 0, 0, 1, 0, 1, 4, 3, 0, 0, 1, 2, 1, 0, 4, 3, 4, 1, 0, 0,...

    $ plot_keywords             <chr> "avatar|future|marine|native|paraplegic", "goddess|marriage cerem...

    $ movie_imdb_link           <chr> "http://www.imdb.com/title/tt0499549/?ref_=fn_tt_tt_1", "http://w...

    $ num_user_for_reviews      <int> 3054, 1238, 994, 2701, NA, 738, 1902, 387, 1117, 973, 3018, 2367,...

    $ language                  <chr> "English", "English", "English", "English", NA, "English", "Engli...

    $ country                   <chr> "USA", "USA", "UK", "USA", NA, "USA", "USA", "USA", "USA", "UK", ...

    $ content_rating            <chr> "PG-13", "PG-13", "PG-13", "PG-13", NA, "PG-13", "PG-13", "PG", "...

    $ budget                    <int> 237000000, 300000000, 245000000, 250000000, NA, 263700000, 258000...

    $ title_year                <int> 2009, 2007, 2015, 2012, NA, 2012, 2007, 2010, 2015, 2009, 2016, 2...

    $ actor_2_facebook_likes    <int> 936, 5000, 393, 23000, 12, 632, 11000, 553, 21000, 11000, 4000, 1...

    $ imdb_score                <dbl> 7.9, 7.1, 6.8, 8.5, 7.1, 6.6, 6.2, 7.8, 7.5, 7.5, 6.9, 6.1, 6.7, ...

    $ aspect_ratio              <dbl> 1.78, 2.35, 2.35, 2.35, NA, 2.35, 2.35, 1.85, 2.35, 2.35, 2.35, 2...

    $ movie_facebook_likes      <int> 33000, 0, 85000, 164000, 0, 24000, 0, 29000, 118000, 10000, 19700...


    2) Steps to Visualize Data


    b - (i)의 답을 시각화 하기 위해 필요한 변수는 title_year이다.


    단계는 다음과 같다.


    1. title_year을 그룹화

    2. 그룹화 시킨 것들 중에서 그에 해당하는 개수를 count

    3. 1~2를 토대로 시각화 진행


    * 여기서 n()의 역활은 각 그룹에서 row의 개수를 세어주는 함수로써, summarize (), mutate () 및 filter () 내에서만 사용할 수 있음

    > df %>%

      group_by(title_year) %>%

      summarize(n_movies=n()) %>% 

      ggplot(aes(title_year, n_movies)) + geom_point() + geom_line()


    b - (ii)의 답을 시각화 하기 위해 필요한 변수는 title_year과 imdb_score이다.


    단계는 다음과 같다.


    1. title_year을 그룹화

    2. imdb_score의 평균값을 계산

    3. 1~2를 토대로 시각화 진행


    > df2 %>%

      group_by(title_year) %>%

      summarise(avg_imdb_score = mean(imdb_score)) %>%

      ggplot(aes(title_year, avg_imdb_score)) + geom_point() + geom_line()



    b - (iii)의 답을 시각화 하기 위해 필요한 변수는 imdb_score과 content_rating이다.


    먼저, content_rating의 분포를 살펴보자


    > df %>% ggplot(aes(content_rating)) + geom_bar() 

    위에 결과에 보듯이 영상물 등급은 크게 G, PG, PG-13, R 4개의 등급으로 나뉘는 것을 볼 수 있다.

    따라서 4개의 등급에 따른 리뷰평점 분포의 병렬상자그림을 그려보면 다음과 같다.


    df %>%

      mutate(content_rating = factor(content_rating, levels = c("G", "PG", "PG-13", "R"))) %>%

      ggplot(aes(content_rating, imdb_score)) + geom_boxplot() 

    위에 결과에 보듯이, 영상물 등급에 따른 리뷰 평점의 순위는 G > R > PG > PG-13 순인 것을 알 수 있다.


    조금 더 전통적인 통계학적 가설검정을 적용하자면 분산분석을 해 보면 된다



    summary(lm(imdb_score ~ content_rating, data=df %>% 

    mutate(content_rating = factor(content_rating, levels = c("G", "PG", "PG-13", "R")))))


    Call:

    lm(formula = imdb_score ~ content_rating, data = df %>% filter(content_rating %in% 

        c("G", "PG", "PG-13", "R")))


    Residuals:

        Min      1Q  Median      3Q     Max 

    -4.9295 -0.6271  0.0729  0.7425  2.7729 


    Coefficients:

                         Estimate Std. Error t value Pr(>|t|)    

    (Intercept)          6.529464   0.103061  63.356   <2e-16 ***

    content_ratingPG    -0.235028   0.110989  -2.118   0.0343 *  

    content_ratingPG-13 -0.271969   0.106938  -2.543   0.0110 *  

    content_ratingR     -0.002363   0.105750  -0.022   0.9822    

    ---

    Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


    Residual standard error: 1.091 on 4388 degrees of freedom

    Multiple R-squared:  0.0139, Adjusted R-squared:  0.01322 

    F-statistic: 20.62 on 3 and 4388 DF,  p-value: 2.92e-13


    자료의 개수가 워낙 많아서이기도 하지만 등급 집단간에 평점 평균이 통계적으로 유의한 차이가 있음을 알 수 있다.

    b - (iv)의 답을 시각화 하기 위해 필요한 변수는 imdb_score과 movie_facebook_likes이다.

    먼저, movie_facebook_likes의 개수 분포를 살펴보자

    > df %>% ggplot(aes(movie_facebook_likes)) + geom_histogram()

    꼬리가 너무 길어, log 변환을 한 후 사용해야 할 것으로 판단된다.

    log로 변환한 movie_facebook_likes 변수와 스코어 간의 산점도를 그려보면 다음과 같다.


    > df %>%

      ggplot(aes(movie_facebook_likes, imdb_score)) + 

      geom_point() +

      scale_x_sqrt() +

      geom_smooth()

    위의 결과에서 알 수 있듯, 평점이 높을수록 페이스북 좋아요의 개수도 많은 것을 알 수 있다.


    하지만, 정확한 결과일까 라는 의문이 든다. 페이스북은 만들어진지 얼마 되지 않았지만 영화 개봉은 수십년째 이어지고 있기 때문이다.

    따라서 년간 페이스북 좋아요의 개수를 알아보자.


    > df %>% ggplot(aes(as.factor(title_year), movie_facebook_likes)) + geom_boxplot() + scale_y_log10()

    위 결과에서도 알 수 있듯이, 예상대로 2010년 이전과 이후로 좋아요의 개수는 확연히 차이난다.

    따라서, 2010년과 미국 영화를 기준으로 다시 확인해보면 다음과 같다.


    > df %>% filter(title_year > 2010 & country == "USA") %>% 

      ggplot(aes(movie_facebook_likes, imdb_score))+ 

      geom_point() + 

      scale_x_log10() + 

      geom_smooth()

    결과에서도 알 수 있듯이, 좋아요 개수가 100개가 넘는 데이터에 관해 두 변수간의 상관관계는 높은 편이다.


    > df2 = df %>%

      filter(title_year > 2010 & country == "USA") %>%

      filter(movie_facebook_likes > 100)


    > cor(log10(df3$movie_facebook_likes), df2$imdb_score) 

    [1] 0.4682827


    선형회귀분석을 적용하면 모수추정과 가설검정 결과도 얻을 수 있다.

    > summary(lm(imdb_score ~ log10(movie_facebook_likes), data=df2))

    Call:

    lm(formula = imdb_score ~ log10(movie_facebook_likes), data = df2)


    Residuals:

        Min      1Q  Median      3Q     Max 

    -5.2173 -0.5197  0.0826  0.6478  2.9942 


    Coefficients:

                                Estimate Std. Error t value Pr(>|t|)    

    (Intercept)                  3.63497    0.20335   17.88   <2e-16 ***

    log10(movie_facebook_likes)  0.66405    0.04859   13.67   <2e-16 ***

    ---

    Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


    Residual standard error: 1 on 665 degrees of freedom

    Multiple R-squared:  0.2193, Adjusted R-squared:  0.2181 

    F-statistic: 186.8 on 1 and 665 DF,  p-value: < 2.2e-16

    댓글

by KUKLIFE