title: column names - xgboost predict on new data
body: <p>I have never productionised an xgboost model and am concerned re how to handle fresh data predictions within an xgboost model. Specifically when column names do not match the trained models sparse matrix column names - either due to new columns being added or certain columns being removed when fresh data is converted to a sparse matrix.</p>
  
  <p>What if I attempt to predict an xgboost model on new data with extra or some missing column names? I see this definitely occurring and would like to create code to account for it so that predictions are correct. I would prefer to avoid hacking together a solution if more elegant ones already exist.</p>
  
  <p>So specifically if the new datas sparse matrix has different column names then what?</p>
  
  <p>My best guess is to factorise (levels based on trained data levels) > create sparse matrix > then remove non-matching columns (between trained dataset and new data).</p>
  
  <p>I have created dummy data (in below code) as an example of prediction errors given different column names.</p>
  
  <p>1st step = build model (just for illustrative purposes I know it's a bad build)</p>
  
  <p>2nd step = resample entire dataset then predict (= no problems. Predictions match)</p>
  
  <p>3rd step = only select from 10% of data then predict - this gets prediction errors due to different column names.</p>
  
  <p>Here's the code:</p>
  
  <p>Step 1 create dummy data and create a lazy xgboost model just for illustrative purposes.</p>
  
  <pre><code>library(xgboost) # for xgboost algo
  library(Matrix) # for sparse matrix
  
  ### Create dummy data
  num_rows &lt;- 100
  
  set.seed(1234)
  
  target &lt;- runif(num_rows)
  
  dummy_data &lt;- data.frame(
  LETTER_SINGLE=sample(LETTERS,num_rows,replace=TRUE),
  DOUBLE_LETTER=paste(sample(LETTERS,num_rows,replace=TRUE),sample(LETTERS,num_rows,replace=TRUE),sep=""),
  TRIPLE_LETTER=paste(sample(LETTERS,num_rows,replace=TRUE),sample(LETTERS,num_rows,replace=TRUE),sample(LETTERS,num_rows,replace=TRUE),sep=""),
  stringsAsFactors=FALSE
  )
  
  
  ## STEP 1 CREATE XGBOOST MODEL AND GET PREDICTED VALUES TO COMPARE WITH FUTURE DATA CUTS.
  model_data_01 &lt;- dummy_data
  target_01 &lt;- target
  # create matrix
  model_01_sparse &lt;- sparse.model.matrix(~ .-1, data = model_data_01) 
  
  # colnames model 1
  colnames_trained_model &lt;- colnames(model_01_sparse)
  
  # train a model
  xgb_fit_01 &lt;- 
  xgboost(data = model_01_sparse,
  label = target_01,
  #param = best_param,
  nrounds=100,
  verbose = T
  )
  
  pred_01 &lt;- predict(xgb_fit_01,newdata=model_01_sparse)
  </code></pre>
  
  <p>Step 2. Test to see if order of observations cause differences in predictions. Spoiler - no prediction errors occur.</p>
  
  <pre><code>## STEP 2 CREATE SHUFFLED DATA (SAME DATA SAMPLES BUT SHUFFLED) THEN PREDICT AND COMPARE.
  sample_order &lt;- sample(1:num_rows)
  
  model_data_shuffled &lt;- dummy_data[sample_order,]
  target_shuffled &lt;- target[sample_order]
  
  # They are different
  head(model_data_01)
  head(model_data_shuffled)
  
  # create matrix
  model_shuffled_sparse &lt;- sparse.model.matrix(~ .-1, data = model_data_shuffled) 
  
  # colnames model 1
  colnames_shuffled &lt;- colnames(model_shuffled_sparse)
  
  pred_shuffled &lt;- predict(xgb_fit_01,newdata=model_shuffled_sparse)
  
  # check if predictions differ
  pred_01[sample_order] - pred_shuffled
  ## This matched. Yay. sparse.model.matrix function must first sort alphabetically then create column names.
  # due to same column names
  mean(colnames_trained_model == colnames_shuffled)
  </code></pre>
  
  <p>Step 3. Only sample a select few rows and predict to see whether missing columns - in sparse matrix - cause prediction errors.</p>
  
  <pre><code>## STEP 2 WORKED FINE SO ONTO...
  ## STEP 3 RANDOMLY SAMPLE ONLY A HANDFUL OF ROWS PREDICT AND COMPARE.
  sample_order_02 &lt;- sample(1:(num_rows*0.1))
  
  model_data_shuffled_02 &lt;- dummy_data[sample_order_02,]
  target_shuffled_02 &lt;- target[sample_order_02]
  # create matrix
  model_shuffled_sparse_02 &lt;- sparse.model.matrix(~ .-1, data = model_data_shuffled_02)   
  
  # colnames model 1
  colnames_shuffled_02 &lt;- colnames(model_shuffled_sparse_02)
  
  pred_shuffled_02 &lt;- predict(xgb_fit_01,newdata=model_shuffled_sparse_02)
  
  # check if predictions differ
  pred_01[sample_order_02] - pred_shuffled_02
  ## This did not matched. Damn.
  
  # Due to different column names
  colnames_trained_model
  colnames_shuffled_02
  
  mean(colnames_trained_model == colnames_shuffled_02)
  </code></pre>
  
  <p>As you can see this last attempt gets variance in the predicted values due solely to missing column names in the spare matrix.
  I don't want to hack an ugly solution together if an elegant one exists for me to learn from.
  So my question is... Is there an elegant way to force sparse model matrix column names to match that of the built model (the one used for predictions on new data)?</p>
  
  <p>I have searched the web and no luck thus far finding any best practices solution.</p>
  
  <p>If anybody could help by answering the Question or pointing me in the right direction that would be much appreciated.</p>