探索的データ分析

データを料理する前に、どのようなデータが与えられているのか確認することが大切です。この段階を踏むことで、データに対する理解が深まり、より良いモデルの構築に繋がる可能性もあります。こうした一連の作業は探索的データ分析 (Exploratory Data Analysis: EDA)と呼ばれます。この作業には、データの集計、要約、可視化が含まれます。

EDAがデータ分析の作業において早期段階で行われるのは、データの異常(思い込みとの比較を含めて)や特徴を把握するためです。これらは分析全体のアプローチや良い出発点を見つけるために有効です。出発点と表現したのは、モデルの構築や特徴量の生成によって改めてデータを見つめ直す作業が発生するためです。そのため必ずしも徹底的である必要はありません。

まずは手元のデータを眺め、簡単な集計をしてみましょう。続いてデータをグラフによって表現してみましょう。データを要約、図示することで、個々の値からは見えなかった情報やデータ間の関係を把握できます。特に欠損値や異常値(外れ値)、データの分布などデータ全体あるいはデータ間の関係性やそのばらつきを見るのに可視化は重要です。なお欠損値の視覚化については後の章で解説します。

データを眺める

地価公示データを利用します。このデータでは、目的変数として設定する地価価格に影響を及ぼす変数を明らかにしたい、またその関係を知りたいという状況を設定します。

データを手に入れたら、分析作業へ取り掛かる前にまずはデータを眺めてみることにしましょう。眺める、と言ってもデータの値を1つずつ見ていくわけではありません。これから扱うデータにはどのような値が含まれているのか、データ型が処理されているか、また全体の大きさはどれくらいなのか欠損はどれだけあるかと言った情報を俯瞰的に整理していきます。それには以下のような項目があります。

  • サイズ(列数、行数)
  • 各列のデータ型
  • 完全データ、欠損データ

データの大きさ

データフレームは行と列からなります。いくつかの関数を使って読み込んだデータの大きさを調べてみましょう。

dim(df_lp_kanto)
## [1] 8476   45

dim()をデータフレームに適用すると、そのサイズを数値ベクトルで返します。最初の要素が行数、2番目の数字が列数を示します。これは次のncol()nrow()により個別に求めることができます。

nrow(df_lp_kanto)
## [1] 8476
ncol(df_lp_kanto)
## [1] 45

データの一部を表示

データフレームの一部を表示して、列名と値の確認をしてみましょう。head()をデータフレームに対して実行すると先頭の数行を表示します。またtail() でデータフレームの最後の行を表示できます。いずれの関数も引数n = に実数を与えることで表示される行数を制御可能です。

head(df_lp_kanto)
## # A tibble: 6 x 45
##   .row_id .prefecture administrative_… posted_land_pri… name_of_nearest…
##     <int> <chr>       <chr>                       <int> <chr>           
## 1   13534 群馬県      10425                        4150 万座・鹿沢口    
## 2   13604 群馬県      10426                       39000 長野原草津口    
## 3   13605 群馬県      10426                       56800 長野原草津口    
## 4   13613 群馬県      10424                        2700 羽根尾          
## 5   13620 群馬県      10424                       12100 羽根尾          
## 6   13621 群馬県      10426                       29800 長野原草津口    
## # … with 40 more variables: distance_from_station <int>, acreage <int>,
## #   current_use <chr>, usage_description <chr>, building_structure <chr>,
## #   attribute_change_supplied_facility <lgl>, water_facility <lgl>,
## #   gas_facility <lgl>, sewage_facility <lgl>,
## #   proximity_with_transportation_facility <chr>, depth_ratio <dbl>,
## #   number_of_floors <int>, number_of_basement_floors <int>,
## #   use_district <chr>, building_coverage <dbl>, configuration <chr>,
## #   surrounding_present_usage <chr>, fire_area <chr>,
## #   urban_planning_area <chr>, forest_law <chr>, parks_law <chr>,
## #   attribute_change_floor_area_ratio <lgl>, frontage_ratio <dbl>,
## #   floor_area_ratio <dbl>, attribute_change_selected_land_status <dbl>,
## #   attribute_change_address <lgl>, attribute_change_acreage <lgl>,
## #   attribute_change_current_use <lgl>,
## #   attribute_change_building_structure <lgl>,
## #   attribute_change_distance_from_station <lgl>,
## #   attribute_change_use_district <lgl>, attribute_change_fire_area <lgl>,
## #   attribute_change_urban_planning_area <lgl>,
## #   attribute_change_forest_law <lgl>, attribute_change_parks_law <lgl>,
## #   attribute_change_building_coverage <lgl>,
## #   common_surveyed_position <lgl>, .longitude <dbl>, .latitude <dbl>,
## #   night_population <dbl>
tail(df_lp_kanto, n = 3)
## # A tibble: 3 x 45
##   .row_id .prefecture administrative_… posted_land_pri… name_of_nearest…
##     <int> <chr>       <chr>                       <int> <chr>           
## 1   23818 茨城県      08232                       15600 銚子            
## 2   23839 千葉県      12202                       41200 銚子            
## 3   23851 千葉県      12202                       31500 銚子            
## # … with 40 more variables: distance_from_station <int>, acreage <int>,
## #   current_use <chr>, usage_description <chr>, building_structure <chr>,
## #   attribute_change_supplied_facility <lgl>, water_facility <lgl>,
## #   gas_facility <lgl>, sewage_facility <lgl>,
## #   proximity_with_transportation_facility <chr>, depth_ratio <dbl>,
## #   number_of_floors <int>, number_of_basement_floors <int>,
## #   use_district <chr>, building_coverage <dbl>, configuration <chr>,
## #   surrounding_present_usage <chr>, fire_area <chr>,
## #   urban_planning_area <chr>, forest_law <chr>, parks_law <chr>,
## #   attribute_change_floor_area_ratio <lgl>, frontage_ratio <dbl>,
## #   floor_area_ratio <dbl>, attribute_change_selected_land_status <dbl>,
## #   attribute_change_address <lgl>, attribute_change_acreage <lgl>,
## #   attribute_change_current_use <lgl>,
## #   attribute_change_building_structure <lgl>,
## #   attribute_change_distance_from_station <lgl>,
## #   attribute_change_use_district <lgl>, attribute_change_fire_area <lgl>,
## #   attribute_change_urban_planning_area <lgl>,
## #   attribute_change_forest_law <lgl>, attribute_change_parks_law <lgl>,
## #   attribute_change_building_coverage <lgl>,
## #   common_surveyed_position <lgl>, .longitude <dbl>, .latitude <dbl>,
## #   night_population <dbl>

各列の情報

データ型や件数、欠損の状況を調べます。

glimpse(df_lp_kanto)
## Observations: 8,476
## Variables: 45
## $ .row_id                                <int> 13534, 13604, 13605, 136…
## $ .prefecture                            <chr> "群馬県", "群馬県", "群馬県", "群馬…
## $ administrative_area_code               <chr> "10425", "10426", "10426…
## $ posted_land_price                      <int> 4150, 39000, 56800, 2700…
## $ name_of_nearest_station                <chr> "万座・鹿沢口", "長野原草津口", "長野原…
## $ distance_from_station                  <int> 8700, 13000, 13000, 5500…
## $ acreage                                <int> 317, 166, 226, 274, 357,…
## $ current_use                            <chr> "住宅,その他", "住宅", "店舗", "住…
## $ usage_description                      <chr> "別荘", NA, NA, "別荘", NA, …
## $ building_structure                     <chr> "W1", "W2", "W1", "W2", …
## $ attribute_change_supplied_facility     <lgl> FALSE, FALSE, FALSE, FAL…
## $ water_facility                         <lgl> TRUE, TRUE, TRUE, TRUE, …
## $ gas_facility                           <lgl> FALSE, FALSE, FALSE, FAL…
## $ sewage_facility                        <lgl> FALSE, TRUE, TRUE, TRUE,…
## $ proximity_with_transportation_facility <chr> NA, NA, NA, NA, NA, NA, …
## $ depth_ratio                            <dbl> 1.0, 1.0, 2.0, 2.0, 1.5,…
## $ number_of_floors                       <int> 1, 2, 1, 2, 2, 2, 2, 1, …
## $ number_of_basement_floors              <int> 0, 0, 0, 0, 0, 0, 0, 0, …
## $ use_district                           <chr> NA, "2住居", "近商", NA, NA,…
## $ building_coverage                      <dbl> 0, 60, 80, 70, 70, 60, 7…
## $ configuration                          <chr> NA, NA, "台形", NA, NA, NA…
## $ surrounding_present_usage              <chr> "低層別荘が建ち並ぶ環境の良い別荘地域", "一…
## $ fire_area                              <chr> NA, NA, NA, NA, NA, NA, …
## $ urban_planning_area                    <chr> "都計外", "非線引", "非線引", "非線…
## $ forest_law                             <chr> NA, NA, NA, NA, NA, NA, …
## $ parks_law                              <chr> NA, NA, NA, NA, NA, NA, …
## $ attribute_change_floor_area_ratio      <lgl> FALSE, FALSE, FALSE, FAL…
## $ frontage_ratio                         <dbl> 1.2, 1.2, 1.0, 1.0, 1.0,…
## $ floor_area_ratio                       <dbl> 0, 200, 300, 400, 400, 2…
## $ attribute_change_selected_land_status  <dbl> 1, 1, 1, 1, 1, 1, 1, 1, …
## $ attribute_change_address               <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_acreage               <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_current_use           <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_building_structure    <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_distance_from_station <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_use_district          <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_fire_area             <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_urban_planning_area   <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_forest_law            <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_parks_law             <lgl> FALSE, FALSE, FALSE, FAL…
## $ attribute_change_building_coverage     <lgl> FALSE, FALSE, FALSE, FAL…
## $ common_surveyed_position               <lgl> FALSE, FALSE, FALSE, FAL…
## $ .longitude                             <dbl> 138.5383, 138.5921, 138.…
## $ .latitude                              <dbl> 36.46920, 36.61913, 36.6…
## $ night_population                       <dbl> 9780, 6518, 6518, 5536, …

この地価公示データには45の列(変数)があります。

  • データの型 (character, numeric, logical, factor)

  • 欠損数、ユニーク数

  • 文字データの長さの幅

  • カテゴリデータの偏り、水準、順序

  • 数値データの要約統計量、分布(ヒストグラム)

  • configurationfire_areaは欠損を多く含んでいることがわかります。building_structureにもわずかですが欠損データがあります

# 同一のデータで重複があるもの
df_lp_kanto %>% 
  tidyr::separate_rows("current_use", sep = ",") %>% 
  count(.row_id) %>% 
  filter(n > 1) %>% 
  distinct(.row_id) %>% 
  nrow() %>% 
  ensure(. == 1986L)
## [1] 1986

明確な答えがあるわけではありませんが、以下の情報はデータ全体、各変数について把握しておくと良いでしょう。またデータの偏りや出現傾向、分布のパターンは可視化を行い確認するのが効率的です。

要約統計量の算出

summary(df_lp_kanto)
##     .row_id      .prefecture        administrative_area_code
##  Min.   :13534   Length:8476        Length:8476             
##  1st Qu.:16404   Class :character   Class :character        
##  Median :18532   Mode  :character   Mode  :character        
##  Mean   :18584                                              
##  3rd Qu.:20708                                              
##  Max.   :23851                                              
##  posted_land_price  name_of_nearest_station distance_from_station
##  Min.   :     613   Length:8476             Min.   :    0        
##  1st Qu.:   59900   Class :character        1st Qu.:  500        
##  Median :  155000   Mode  :character        Median : 1000        
##  Mean   :  415432                           Mean   : 1566        
##  3rd Qu.:  308000                           3rd Qu.: 1800        
##  Max.   :55500000                           Max.   :24000        
##     acreage       current_use        usage_description  building_structure
##  Min.   :    46   Length:8476        Length:8476        Length:8476       
##  1st Qu.:   140   Class :character   Class :character   Class :character  
##  Median :   181   Mode  :character   Mode  :character   Mode  :character  
##  Mean   :   751                                                           
##  3rd Qu.:   272                                                           
##  Max.   :413215                                                           
##  attribute_change_supplied_facility water_facility  gas_facility   
##  Mode :logical                      Mode :logical   Mode :logical  
##  FALSE:8429                         FALSE:49        FALSE:1860     
##  TRUE :47                           TRUE :8427      TRUE :6616     
##                                                                    
##                                                                    
##                                                                    
##  sewage_facility proximity_with_transportation_facility  depth_ratio   
##  Mode :logical   Length:8476                            Min.   :0.000  
##  FALSE:701       Class :character                       1st Qu.:1.000  
##  TRUE :7775      Mode  :character                       Median :1.200  
##                                                         Mean   :1.459  
##                                                         3rd Qu.:1.500  
##                                                         Max.   :6.500  
##  number_of_floors number_of_basement_floors use_district      
##  Min.   : 0.000   Min.   :0.00000           Length:8476       
##  1st Qu.: 2.000   1st Qu.:0.00000           Class :character  
##  Median : 2.000   Median :0.00000           Mode  :character  
##  Mean   : 2.718   Mean   :0.07574                             
##  3rd Qu.: 2.000   3rd Qu.:0.00000                             
##  Max.   :52.000   Max.   :6.00000                             
##  building_coverage configuration      surrounding_present_usage
##  Min.   : 0.00     Length:8476        Length:8476              
##  1st Qu.:50.00     Class :character   Class :character         
##  Median :60.00     Mode  :character   Mode  :character         
##  Mean   :60.17                                                 
##  3rd Qu.:60.00                                                 
##  Max.   :80.00                                                 
##   fire_area         urban_planning_area  forest_law       
##  Length:8476        Length:8476         Length:8476       
##  Class :character   Class :character    Class :character  
##  Mode  :character   Mode  :character    Mode  :character  
##                                                           
##                                                           
##                                                           
##   parks_law         attribute_change_floor_area_ratio frontage_ratio 
##  Length:8476        Mode :logical                     Min.   :0.000  
##  Class :character   FALSE:8474                        1st Qu.:1.000  
##  Mode  :character   TRUE :2                           Median :1.000  
##                                                       Mean   :1.066  
##                                                       3rd Qu.:1.000  
##                                                       Max.   :5.500  
##  floor_area_ratio attribute_change_selected_land_status
##  Min.   :   0.0   Min.   :1.000                        
##  1st Qu.: 100.0   1st Qu.:1.000                        
##  Median : 200.0   Median :1.000                        
##  Mean   : 216.6   Mean   :1.027                        
##  3rd Qu.: 200.0   3rd Qu.:1.000                        
##  Max.   :1300.0   Max.   :4.000                        
##  attribute_change_address attribute_change_acreage
##  Mode :logical            Mode :logical           
##  FALSE:8411               FALSE:8450              
##  TRUE :65                 TRUE :26                
##                                                   
##                                                   
##                                                   
##  attribute_change_current_use attribute_change_building_structure
##  Mode :logical                Mode :logical                      
##  FALSE:8402                   FALSE:8406                         
##  TRUE :74                     TRUE :70                           
##                                                                  
##                                                                  
##                                                                  
##  attribute_change_distance_from_station attribute_change_use_district
##  Mode :logical                          Mode :logical                
##  FALSE:8431                             FALSE:8475                   
##  TRUE :45                               TRUE :1                      
##                                                                      
##                                                                      
##                                                                      
##  attribute_change_fire_area attribute_change_urban_planning_area
##  Mode :logical              Mode :logical                       
##  FALSE:8417                 FALSE:8475                          
##  TRUE :59                   TRUE :1                             
##                                                                 
##                                                                 
##                                                                 
##  attribute_change_forest_law attribute_change_parks_law
##  Mode :logical               Mode :logical             
##  FALSE:8476                  FALSE:8476                
##                                                        
##                                                        
##                                                        
##                                                        
##  attribute_change_building_coverage common_surveyed_position
##  Mode :logical                      Mode :logical           
##  FALSE:8474                         FALSE:7870              
##  TRUE :2                            TRUE :606               
##                                                             
##                                                             
##                                                             
##    .longitude      .latitude     night_population
##  Min.   :138.5   Min.   :34.98   Min.   :  3214  
##  1st Qu.:139.5   1st Qu.:35.59   1st Qu.:118919  
##  Median :139.7   Median :35.72   Median :200012  
##  Mean   :139.7   Mean   :35.79   Mean   :259450  
##  3rd Qu.:139.9   3rd Qu.:35.92   3rd Qu.:341076  
##  Max.   :140.8   Max.   :37.02   Max.   :903346

Rの組み込み関数として用意されている summary() を利用して、データフレームに含まれる列の要約統計量を得ることができます。

# 論理値型で標準偏差0の列を特定 constant cols
df_lp_kanto %>% 
  select(-starts_with(".")) %>% 
  select_if(is.logical) %>% 
  mutate_all(as.numeric) %>% 
  summarise_all(sd) %>% 
  tidyr::gather()
## # A tibble: 17 x 2
##    key                                     value
##    <chr>                                   <dbl>
##  1 attribute_change_supplied_facility     0.0743
##  2 water_facility                         0.0758
##  3 gas_facility                           0.414 
##  4 sewage_facility                        0.275 
##  5 attribute_change_floor_area_ratio      0.0154
##  6 attribute_change_address               0.0872
##  7 attribute_change_acreage               0.0553
##  8 attribute_change_current_use           0.0930
##  9 attribute_change_building_structure    0.0905
## 10 attribute_change_distance_from_station 0.0727
## 11 attribute_change_use_district          0.0109
## 12 attribute_change_fire_area             0.0831
## 13 attribute_change_urban_planning_area   0.0109
## 14 attribute_change_forest_law            0     
## 15 attribute_change_parks_law             0     
## 16 attribute_change_building_coverage     0.0154
## 17 common_surveyed_position               0.258

ここでは skimr で行う例を示します。

# skimr::skim(df_lp) # Rコンソールでの実行は skim() で構いません
df_lp_kanto %>% 
  select(-starts_with(".")) %>% 
  skimr::skim_to_list()
## $character
## # A tibble: 13 x 8
##    variable               missing complete n     min   max   empty n_unique
##  * <chr>                  <chr>   <chr>    <chr> <chr> <chr> <chr> <chr>   
##  1 administrative_area_c… 0       8476     8476  5     5     0     329     
##  2 building_structure     220     8256     8476  2     8     0     130     
##  3 configuration          7454    1022     8476  2     3     0     2       
##  4 current_use            0       8476     8476  2     14    0     70      
##  5 fire_area              4859    3617     8476  2     2     0     2       
##  6 forest_law             8450    26       8476  3     3     0     1       
##  7 name_of_nearest_stati… 0       8476     8476  1     14    0     1481    
##  8 parks_law              8465    11       8476  7     7     0     2       
##  9 proximity_with_transp… 8308    168      8476  2     6     0     3       
## 10 surrounding_present_u… 0       8476     8476  15    22    0     4397    
## 11 urban_planning_area    0       8476     8476  2     3     0     4       
## 12 usage_description      7552    924      8476  1     8     0     40      
## 13 use_district           515     7961     8476  2     3     0     12      
## 
## $integer
## # A tibble: 5 x 12
##   variable missing complete n     mean  sd    p0    p25   p50   p75   p100 
## * <chr>    <chr>   <chr>    <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 acreage  0       8476     8476  "   … "   … 46    140   181   272   "413…
## 2 distanc… 0       8476     8476  "  1… "   … 0     500   1000  1800  " 24…
## 3 number_… 0       8476     8476  "   … "   … 0     0     0     0     "   …
## 4 number_… 0       8476     8476  "   … "   … 0     2     2     2     "   …
## 5 posted_… 0       8476     8476  "415… 1766… 613   59900 1550… 3080… "   …
## # … with 1 more variable: hist <chr>
## 
## $logical
## # A tibble: 17 x 6
##    variable                 missing complete n     mean    count           
##  * <chr>                    <chr>   <chr>    <chr> <chr>   <chr>           
##  1 attribute_change_acreage 0       8476     8476  "0.003… FAL: 8450, TRU:…
##  2 attribute_change_address 0       8476     8476  "0.007… FAL: 8411, TRU:…
##  3 attribute_change_buildi… 0       8476     8476  0.00024 FAL: 8474, TRU:…
##  4 attribute_change_buildi… 0       8476     8476  "0.008… FAL: 8406, TRU:…
##  5 attribute_change_curren… 0       8476     8476  "0.008… FAL: 8402, TRU:…
##  6 attribute_change_distan… 0       8476     8476  "0.005… FAL: 8431, TRU:…
##  7 attribute_change_fire_a… 0       8476     8476  "0.007… FAL: 8417, TRU:…
##  8 attribute_change_floor_… 0       8476     8476  0.00024 FAL: 8474, TRU:…
##  9 attribute_change_forest… 0       8476     8476  "0    … FAL: 8476, NA: 0
## 10 attribute_change_parks_… 0       8476     8476  "0    … FAL: 8476, NA: 0
## 11 attribute_change_suppli… 0       8476     8476  "0.005… FAL: 8429, TRU:…
## 12 attribute_change_urban_… 0       8476     8476  0.00012 FAL: 8475, TRU:…
## 13 attribute_change_use_di… 0       8476     8476  0.00012 FAL: 8475, TRU:…
## 14 common_surveyed_position 0       8476     8476  "0.071… FAL: 7870, TRU:…
## 15 gas_facility             0       8476     8476  "0.78 … TRU: 6616, FAL:…
## 16 sewage_facility          0       8476     8476  "0.92 … TRU: 7775, FAL:…
## 17 water_facility           0       8476     8476  "0.99 … TRU: 8427, FAL:…
## 
## $numeric
## # A tibble: 6 x 12
##   variable missing complete n     mean  sd    p0    p25   p50   p75   p100 
## * <chr>    <chr>   <chr>    <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 attribu… 0       8476     8476  "   … "   … 1     1     "   … "   … "   …
## 2 buildin… 0       8476     8476  "   … "   … 0     50    "   … "   … "   …
## 3 depth_r… 0       8476     8476  "   … "   … 0     1     "   … "   … "   …
## 4 floor_a… 0       8476     8476  "   … "  1… 0     100   "  2… "   … " 13…
## 5 frontag… 0       8476     8476  "   … "   … 0     1     "   … "   … "   …
## 6 night_p… 0       8476     8476  2594… "2e+… 3214  1189… "2e+… "341… "9e+…
## # … with 1 more variable: hist <chr>

論理型データのうち、attribute_change_forest_lawattribute_change_parks_law は FALSE のみが出現していることがわかります。

探索的データ分析

モデリングでは、目的変数の挙動(予測、分類)を明らかにすることがゴールとして設定されます。変数が多いデータであるほど確認する図の数が多くなり、効率的ではなくなります。そのため、まずはモデリングの目的変数となるデータを詳しく見ることを勧めます。また、この段階で作る図は初期モデルを構築する前段階で示唆を提供するものであると望ましいです。そこで目的変数に影響する説明変数、説明変数間の関係を明らかにすることで、次のモデリングプロセスに活かせる知識を得られることが期待できます。

探索的データ分析の結果が最終的な成果物になることは稀です。ここで作られる図は論文や書籍、プレゼンテーションのための図ではありません。つまり複雑な図を作ることは求められていません。ここでは主にggplot2による作図を行いますが、扱いに慣れた最低限の機能を提供しれくれるライブラリを利用すると良いでしょう。

以下では引き続き、地価公示データを使います。このデータには位置情報も含まれているため、地図上へのデータのマッピングも試みます。

また時系列データの例としてビールへの支出データも利用します。

数値データ

df_is_num <- 
  df_lp_kanto %>% 
  select(-starts_with(".")) %>% 
  select_if(is_numeric)

カテゴリデータ

df_is_cat <- 
  df_lp_kanto %>% 
  select(-starts_with(".")) %>% 
  select_if(is.character) %>% 
  verify(ncol(.) == 13)
df_is_cat %>% 
  count(name_of_nearest_station, sort = TRUE)
## # A tibble: 1,481 x 2
##    name_of_nearest_station     n
##    <chr>                   <int>
##  1 本厚木                     59
##  2 水戸                       56
##  3 宇都宮                     55
##  4 平塚                       51
##  5 八王子                     48
##  6 柏                         41
##  7 川崎                       40
##  8 木更津                     36
##  9 千葉                       35
## 10 前橋                       34
## # … with 1,471 more rows

論理値

df_is_log <-
  df_lp_kanto %>% 
  select(-starts_with(".")) %>% 
  select_if(is.logical) %>% 
  verify(ncol(.) == 17)
gg_count_var <- function(data, var) {
  var <- rlang::enquo(var)
  var_label <- rlang::quo_name(var)
    data %>% 
    count(!!var) %>% 
    ggplot(aes(forcats::fct_reorder(!!var, n), n)) +
    geom_bar(stat = "identity") +
    labs(x = var_label) +
    coord_flip()
}
df_is_cat %>% 
  filter(stringr::str_detect(administrative_area_code, "^08")) %>% 
  gg_count_var(name_of_nearest_station)

purrr::map(
  rlang::syms(str_subset(names(df_is_cat), "name_of_nearest_station", negate = TRUE)),
  ~ gg_count_var(df_is_cat %>% 
                   filter(stringr::str_detect(administrative_area_code, "^08")), 
                 !!.x)) %>% 
    plot_grid(plotlist = ., ncol = 2)

何枚かの図は文字が潰れてしまいましたが、いくつかのカテゴリデータについて掴めたことがあります。

全体

vis_dat(df_lp_kanto)

1変数の可視化

データのばらつきを見るのにはヒストグラム、箱ひげ図を利用します。一変量を対象とした単純な可視化は、変数の変動、特性を理解するのに役立ちます。

ヒストグラム

スパイク(峰)を検出するのに効果的です。ヒストグラムは単峰、二峰など多様な形状を取り得ます。

df_lp_kanto %>% 
  ggplot(aes(distance_from_station)) +
  geom_histogram(bins = 30)

df_lp_kanto %>% 
  ggplot(aes(distance_from_station)) +
  geom_histogram(bins = 30) +
  facet_wrap(~ .prefecture, ncol = 1)
library(ggridges)

ggplot(df_lp_kanto, 
       aes(x = distance_from_station, y  = .prefecture,
           fill = .prefecture)) +
  #scale_x_log10() +
  ggridges::geom_density_ridges(scale = 4) +
  scale_fill_ds()

箱ひげ図・バイオリンプロット

2変数の可視化

df_lp_kanto %>% 
  ggplot(aes(use_district, posted_land_price)) +
  geom_boxplot()

散布図

df_lp_kanto %>% 
  ggplot(aes(distance_from_station, posted_land_price)) +
  geom_point()

df_lp_kanto %>% 
  ggplot(aes(distance_from_station, acreage)) +
  geom_point() +
  scale_x_log10() +
  scale_y_log10()

特殊なデータの視覚化

時系列データ

時系列データを扱うときは、時間のならびの通りに表示させることが肝心です。周期があるものは分割したり重ねてみると良いでしょう。

df_beer2018q2 %>% 
  ggplot(aes(expense)) +
  geom_histogram(bins = 30)

空間データ

sf_lp_kanto <- 
  df_lp_kanto %>% 
  select(posted_land_price, .longitude, .latitude) %>% 
  st_as_sf(coords = c(".longitude", ".latitude"), crs = 4326)

ggplot(sf_lp_kanto) +
  geom_sf(aes(color = posted_land_price),
          fill = "transparent", 
          alpha = 0.1, size = 0.5) +
  scale_color_viridis_c()

高次元の可視化

3次元の世界に生きる我々は、高次元のデータを直接扱うことに慣れていません。

次元圧縮を行ってからの可視化が効果的です。

ヒートマップ

変数間の関係、特に相関や欠損関係がある場合に役立ちます。

散布図行列

df_is_num %>% 
  GGally::ggpairs()

相関行列

df_is_num %>% 
  corrr::correlate()
## 
## Correlation method: 'pearson'
## Missing treated using: 'pairwise.complete.obs'

## # A tibble: 11 x 12
##    rowname posted_land_pri… distance_from_s…  acreage depth_ratio
##    <chr>              <dbl>            <dbl>    <dbl>       <dbl>
##  1 posted…         NA                -0.126   0.00819     0.0375 
##  2 distan…         -0.126            NA       0.0468     -0.0646 
##  3 acreage          0.00819           0.0468 NA           0.00383
##  4 depth_…          0.0375           -0.0646  0.00383    NA      
##  5 number…          0.438            -0.228  -0.0135      0.102  
##  6 number…          0.543            -0.138   0.0164      0.0428 
##  7 buildi…          0.212            -0.206  -0.00184     0.294  
##  8 fronta…          0.0486           -0.0185  0.0330     -0.220  
##  9 floor_…          0.473            -0.228   0.00763     0.223  
## 10 attrib…          0.00416          -0.0201 -0.00616     0.0244 
## 11 night_…          0.0103           -0.172  -0.0202      0.0211 
## # … with 7 more variables: number_of_floors <dbl>,
## #   number_of_basement_floors <dbl>, building_coverage <dbl>,
## #   frontage_ratio <dbl>, floor_area_ratio <dbl>,
## #   attribute_change_selected_land_status <dbl>, night_population <dbl>

df_is_log %>% 
  mutate_all(as.numeric) %>% 
  vis_cor()

all.equal(
  df_lp_kanto$attribute_change_building_coverage,
  df_lp_kanto$attribute_change_floor_area_ratio)

t-SNE

高次元データの2次元散布図を用いた可視化に利用される

モデルの利用

効果的な変数の仮説がない場合や、変数の量が多い場合には、EDAの前に木ベースのモデルを適用してみるのも戦略の1つです。これらのモデルでは目的変数に対する説明変数の貢献度として、変数重要度を示すことが可能です。これによりEDAのとっかかりを得ることが可能になるはずです。変数重要度については後の章で解説します。

まとめ

  • モデリング、統計分析を行う前にデータを精査することが大事
    • データの特徴を理解することで次のステップにかける時間を減らす、異常を見逃さない、(意図しない)間違いを見逃さない
  • 特に可視化の手法を用いることでデータの集約や関係、パターンを見やすくする

関連項目

参考文献

-