Skip to contents

First of all, thank you for using healthyR.ai. If you encounter issues or want to make a feature request, please visit https://github.com/spsanderson/healthyR.ai/issues

library(healthyR.ai)
#> 
#> == Welcome to healthyR.ai ===========================================================================
#> If you find this package useful, please leave a star: 
#>    https://github.com/spsanderson/healthyR.ai'
#> 
#> If you encounter a bug or want to request an enhancement please file an issue at:
#>    https://github.com/spsanderson/healthyR.ai/issues
#> 
#> Thank you for using healthyR.ai

In this should example we will showcase the pca_your_recipe() function. This function takes only a few arguments. The arguments are currently .data which is the full data set that gets passed internally to the recipes::bake() function, .recipe_object which is a recipe you have already made and want to pass to the function in order to perform the pca, and finally .threshold which is the fraction of the variance that should be captured by the components.

To start this walk through we will first load in a few libraries.

Data

Now that we have out libraries we can go ahead and get our data set ready.

Data Set

data_tbl <- healthyR_data %>%
    select(visit_end_date_time) %>%
    summarise_by_time(
        .date_var = visit_end_date_time,
        .by       = "month",
        value     = n()
    ) %>%
    set_names("date_col","value") %>%
    filter_by_time(
        .date_var = date_col,
        .start_date = "2013",
        .end_date = "2020"
    ) %>%
    mutate(date_col = as.Date(date_col))

head(data_tbl)
#> # A tibble: 6 × 2
#>   date_col   value
#>   <date>     <int>
#> 1 2013-01-01  2082
#> 2 2013-02-01  1719
#> 3 2013-03-01  1796
#> 4 2013-04-01  1865
#> 5 2013-05-01  2028
#> 6 2013-06-01  1813

The data set is simple and by itself would not be at all useful for a pca analysis since there is only one predictor, being time. In order to facilitate the use of the function and this example, we will create a splits object and a recipe object.

Splits

splits <- initial_split(data = data_tbl, prop = 0.8)

splits
#> <Training/Testing/Total>
#> <76/19/95>

head(training(splits))
#> # A tibble: 6 × 2
#>   date_col   value
#>   <date>     <int>
#> 1 2016-05-01  1587
#> 2 2017-05-01  1647
#> 3 2018-09-01  1343
#> 4 2018-11-01  1550
#> 5 2019-08-01  1416
#> 6 2019-03-01  1560

Initial Recipe

rec_obj <- recipe(value ~ ., training(splits)) %>%
    step_timeseries_signature(date_col) %>%
    step_rm(matches("(iso$)|(xts$)|(hour)|(min)|(sec)|(am.pm)"))

rec_obj
#> 
#> ── Recipe ──────────────────────────────────────────────────────────────────────
#> 
#> ── Inputs
#> Number of variables by role
#> outcome:   1
#> predictor: 1
#> 
#> ── Operations
#>  Timeseries signature features from: date_col
#>  Variables removed: matches("(iso$)|(xts$)|(hour)|(min)|(sec)|(am.pm)")

get_juiced_data(rec_obj) %>% glimpse()
#> Rows: 76
#> Columns: 20
#> $ date_col           <date> 2016-05-01, 2017-05-01, 2018-09-01, 2018-11-01, 20…
#> $ value              <int> 1587, 1647, 1343, 1550, 1416, 1560, 1513, 1635, 147…
#> $ date_col_index.num <dbl> 1462060800, 1493596800, 1535760000, 1541030400, 156…
#> $ date_col_year      <int> 2016, 2017, 2018, 2018, 2019, 2019, 2016, 2017, 201…
#> $ date_col_half      <int> 1, 1, 2, 2, 2, 1, 2, 1, 1, 2, 1, 1, 2, 2, 1, 2, 1, …
#> $ date_col_quarter   <int> 2, 2, 3, 4, 3, 1, 4, 1, 1, 3, 1, 1, 3, 3, 1, 4, 2, …
#> $ date_col_month     <int> 5, 5, 9, 11, 8, 3, 11, 1, 2, 8, 2, 1, 8, 9, 2, 10, …
#> $ date_col_month.lbl <ord> May, May, September, November, August, March, Novem…
#> $ date_col_day       <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ date_col_wday      <int> 1, 2, 7, 5, 5, 6, 3, 1, 6, 6, 7, 5, 3, 1, 6, 3, 4, …
#> $ date_col_wday.lbl  <ord> Sunday, Monday, Saturday, Thursday, Thursday, Frida…
#> $ date_col_mday      <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …
#> $ date_col_qday      <int> 31, 31, 63, 32, 32, 60, 32, 1, 32, 32, 32, 1, 32, 6…
#> $ date_col_yday      <int> 122, 121, 244, 305, 213, 60, 306, 1, 32, 213, 32, 1…
#> $ date_col_mweek     <int> 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, …
#> $ date_col_week      <int> 18, 18, 35, 44, 31, 9, 44, 1, 5, 31, 5, 1, 31, 35, …
#> $ date_col_week2     <int> 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, …
#> $ date_col_week3     <int> 0, 0, 2, 2, 1, 0, 2, 1, 2, 1, 2, 1, 1, 2, 2, 1, 1, …
#> $ date_col_week4     <int> 2, 2, 3, 0, 3, 1, 0, 1, 1, 3, 1, 1, 3, 3, 1, 0, 2, …
#> $ date_col_mday7     <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, …

Now that we have out initial recipe we can use the pca_your_recipe() function.

pca_list <- pca_your_recipe(
  .recipe_object = rec_obj,
  .data          = data_tbl,
  .threshold     = 0.8,
  .top_n         = 5
)
#> Warning: Column(s) have zero variance so scaling cannot be used:
#> `date_col_day`, `date_col_mday` and `date_col_mday7`. Consider using
#> `step_zv()` to remove those columns before normalizing

Inspect PCA Output

The function returns a list object and does so insvisible so you must assign the output to a variable, you can then access the items of the list in the usual manner.

The following items are included in the output of the function:

  1. pca_transform - This is the pca recipe.
  2. variable_loadings
  3. variable_variance
  4. pca_estimates
  5. pca_juiced_estimates
  6. pca_baked_data
  7. pca_variance_df
  8. pca_variance_scree_plt
  9. pca_rotation_df

Lets start going down the list of items.

PCA Transform

This is the portion you will want to output to a variable as this is the recipe object itself that you will use further down the line of your work.

pca_rec_obj <- pca_list$pca_transform

pca_rec_obj
#> 
#> ── Recipe ──────────────────────────────────────────────────────────────────────
#> 
#> ── Inputs
#> Number of variables by role
#> outcome:   1
#> predictor: 1
#> 
#> ── Operations
#>  Timeseries signature features from: date_col
#>  Variables removed: matches("(iso$)|(xts$)|(hour)|(min)|(sec)|(am.pm)")
#>  Centering for: recipes::all_numeric()
#>  Scaling for: recipes::all_numeric()
#>  Sparse, unbalanced variable filter on: recipes::all_numeric()
#>  PCA extraction with: recipes::all_numeric_predictors()

Variable Loadings

pca_list$variable_loadings
#> # A tibble: 169 × 4
#>    terms                 value component id       
#>    <chr>                 <dbl> <chr>     <chr>    
#>  1 date_col_index.num  0.0193  PC1       pca_vaKjE
#>  2 date_col_year      -0.0386  PC1       pca_vaKjE
#>  3 date_col_half       0.388   PC1       pca_vaKjE
#>  4 date_col_quarter    0.431   PC1       pca_vaKjE
#>  5 date_col_month      0.433   PC1       pca_vaKjE
#>  6 date_col_wday      -0.0351  PC1       pca_vaKjE
#>  7 date_col_qday       0.0467  PC1       pca_vaKjE
#>  8 date_col_yday       0.433   PC1       pca_vaKjE
#>  9 date_col_mweek      0.00422 PC1       pca_vaKjE
#> 10 date_col_week       0.433   PC1       pca_vaKjE
#> # ℹ 159 more rows

Variable Variance

pca_list$variable_variance
#> # A tibble: 52 × 4
#>    terms       value component id       
#>    <chr>       <dbl>     <int> <chr>    
#>  1 variance 5.23             1 pca_vaKjE
#>  2 variance 2.00             2 pca_vaKjE
#>  3 variance 1.52             3 pca_vaKjE
#>  4 variance 1.30             4 pca_vaKjE
#>  5 variance 1.14             5 pca_vaKjE
#>  6 variance 0.686            6 pca_vaKjE
#>  7 variance 0.593            7 pca_vaKjE
#>  8 variance 0.465            8 pca_vaKjE
#>  9 variance 0.0521           9 pca_vaKjE
#> 10 variance 0.000211        10 pca_vaKjE
#> # ℹ 42 more rows

PCA Estimates

pca_list$pca_estimates
#> 
#> ── Recipe ──────────────────────────────────────────────────────────────────────
#> 
#> ── Inputs
#> Number of variables by role
#> outcome:   1
#> predictor: 1
#> 
#> ── Training information
#> Training data contained 76 data points and no incomplete rows.
#> 
#> ── Operations
#>  Timeseries signature features from: date_col | Trained
#>  Variables removed: date_col_year.iso, date_col_month.xts, ... | Trained
#>  Centering for: value, date_col_index.num, date_col_year, ... | Trained
#>  Scaling for: value, date_col_index.num, date_col_year, ... | Trained
#>  Sparse, unbalanced variable filter removed: date_col_day, ... | Trained
#>  PCA extraction with: date_col_index.num, date_col_year, ... | Trained

Jucied and Baked Data

pca_list$pca_juiced_estimates %>% glimpse()
#> Rows: 76
#> Columns: 9
#> $ date_col           <date> 2016-05-01, 2017-05-01, 2018-09-01, 2018-11-01, 20…
#> $ value              <dbl> 0.1329352773, 0.3982240583, -0.9459057653, -0.03065…
#> $ date_col_month.lbl <ord> May, May, September, November, August, March, Novem…
#> $ date_col_wday.lbl  <ord> Sunday, Monday, Saturday, Thursday, Thursday, Frida…
#> $ PC1                <dbl> -1.0267706, -1.0469010, 0.9807093, 2.9354197, 0.524…
#> $ PC2                <dbl> -0.36928356, 0.48921097, 1.07346258, 1.00952193, 1.…
#> $ PC3                <dbl> -0.49077479, 0.54757044, 0.04788856, -0.69761176, 0…
#> $ PC4                <dbl> -0.41037035, -0.56381837, 2.75026214, -0.52731285, …
#> $ PC5                <dbl> -1.8430269, -2.1771819, 1.5951432, 1.0780155, 0.802…

pca_list$pca_baked_data %>% glimpse()
#> Rows: 95
#> Columns: 9
#> $ date_col           <date> 2013-01-01, 2013-02-01, 2013-03-01, 2013-04-01, 20…
#> $ value              <dbl> 2.3215677, 0.7165706, 1.0570245, 1.3621066, 2.08280…
#> $ date_col_month.lbl <ord> January, February, March, April, May, June, July, A…
#> $ date_col_wday.lbl  <ord> Tuesday, Friday, Friday, Monday, Wednesday, Saturda…
#> $ PC1                <dbl> -3.3206464, -2.8989505, -2.6214743, -1.8620358, -1.…
#> $ PC2                <dbl> -2.118685, -2.443313, -2.494372, -1.984653, -2.3584…
#> $ PC3                <dbl> 1.68932549, 0.02008400, -1.33699696, 1.87290199, -0…
#> $ PC4                <dbl> -1.37846842, 0.06197514, 0.89992496, -1.29970361, -…
#> $ PC5                <dbl> -0.44764626, 1.29598389, -0.62715237, -0.76917566, …

Roatation Data

pca_list$pca_rotation_df %>% glimpse()
#> Rows: 13
#> Columns: 13
#> $ PC1  <dbl> 0.019315047, -0.038563997, 0.387552478, 0.431449781, 0.433168437,…
#> $ PC2  <dbl> 0.699276384, 0.697213171, 0.038818102, 0.011923053, 0.005377266, …
#> $ PC3  <dbl> -0.10534865, -0.10336850, 0.18724238, 0.03805013, -0.01435840, -0…
#> $ PC4  <dbl> 0.0005850596, -0.0119762590, 0.1106993688, -0.0530122832, 0.09423…
#> $ PC5  <dbl> 0.02213747, 0.02654742, 0.20622901, 0.05239999, -0.03537168, 0.59…
#> $ PC6  <dbl> 0.022912405, 0.022989574, -0.146573929, -0.122281043, -0.00514882…
#> $ PC7  <dbl> 0.009393494, 0.014285815, 0.164388048, 0.018529703, -0.034957737,…
#> $ PC8  <dbl> 0.00891792, 0.01608612, -0.24670371, -0.06456866, -0.05127006, 0.…
#> $ PC9  <dbl> -0.019204403, 0.009966989, 0.805646910, -0.272060527, -0.21538705…
#> $ PC10 <dbl> -0.0148882682, 0.0130633078, 0.0008932996, -0.2927032461, -0.3799…
#> $ PC11 <dbl> -2.639123e-02, 2.695316e-02, -1.289940e-03, -2.866897e-02, 6.5501…
#> $ PC12 <dbl> -3.380893e-03, 3.184078e-03, -3.504556e-03, -7.909521e-01, 4.2229…
#> $ PC13 <dbl> -7.050245e-01, 7.063111e-01, 1.148276e-04, 3.347581e-02, 4.377297…

Variance and Scree Plot

pca_list$pca_variance_df %>% glimpse()
#> Rows: 13
#> Columns: 6
#> $ PC              <chr> "PC1", "PC2", "PC3", "PC4", "PC5", "PC6", "PC7", "PC8"…
#> $ var_explained   <dbl> 4.026731e-01, 1.541863e-01, 1.170039e-01, 1.001223e-01…
#> $ var_pct_txt     <chr> "40.27%", "15.42%", "11.70%", "10.01%", "8.78%", "5.28…
#> $ cum_var_pct     <dbl> 0.4026731, 0.5568594, 0.6738634, 0.7739857, 0.8618163,…
#> $ cum_var_pct_txt <chr> "40.27%", "55.69%", "67.39%", "77.40%", "86.18%", "91.…
#> $ ou_threshold    <fct> Under, Under, Under, Under, Over, Over, Over, Over, Ov…
pca_list$pca_variance_scree_plt

Variable Loading Plots

pca_list$pca_loadings_plt


pca_list$pca_top_n_loadings_plt