In [1]:
import polars as pl
import pandas as pd
pl.Config.set_tbl_rows(15)
pl.Config(float_precision=2)

import gc
import numpy as np
import matplotlib.pyplot as plt

from datetime import datetime, timedelta
from bs4 import BeautifulSoup
import requests
import math
In [2]:
# SHould be 3, 7, or 30
days = '7'
In [26]:
from sklearn.compose import ColumnTransformer
# from sklearn.feature_selection import mutual_info_regression, SelectKBest
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder, MinMaxScaler, RobustScaler, FunctionTransformer
from tensorflow.keras.layers import Concatenate, Dense, Dropout, Embedding, Flatten, Input, IntegerLookup
from tensorflow.keras.models import Model
from tensorflow.keras.regularizers import l2
from tensorflow.keras.callbacks import EarlyStopping
2026-08-21 20:25:15.325711: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.
To enable the following instructions: SSE3 SSE4.1 SSE4.2 AVX AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
In [39]:
# Define the ID input branch
penny_id_input = Input(shape=(1,), name='passthrough__id')

# Map raw sparse IDs (e.g., 12136) to contiguous integers (0, 1, 2...)
penny_lookup = IntegerLookup(vocabulary=penny_unique_ids, output_mode='int')(penny_id_input)

# Pass the contiguous integers into the Embedding layer
# input_dim needs to account for the vocab size + OOV (Out of Vocabulary) token
penny_id_embed = Embedding(input_dim=len(penny_unique_ids) + 1, output_dim=16)(penny_lookup)
penny_id_flat = Flatten()(penny_id_embed)

# Define the remaining continuous/binary feature branch
penny_features_input = Input(shape=(penny_train_features.shape[1],), name='numeric_features')

# Merge branches and pass through Dense layers
penny_merged = Concatenate()([penny_id_flat, penny_features_input])
penny_dense1 = Dense(64, activation='relu', kernel_regularizer=l2(1e-4))(penny_merged)
penny_drop1 = Dropout(0.3)(penny_dense1)
penny_dense2 = Dense(32, activation='relu', kernel_regularizer=l2(1e-4))(penny_drop1)
penny_drop2 = Dropout(0.2)(penny_dense2)
penny_output = Dense(1, activation='sigmoid')(penny_drop2) # Outputting target_3d

penny_model = Model(inputs=[penny_id_input, penny_features_input], outputs=penny_output)
penny_model.compile(optimizer='adam', loss='mae', metrics=['mae'])
penny_model.summary()

# Define the ID input branch
luxury_id_input = Input(shape=(1,), name='passthrough__id')

# Map raw sparse IDs (e.g., 12136) to contiguous integers (0, 1, 2...)
luxury_lookup = IntegerLookup(vocabulary=luxury_unique_ids, output_mode='int')(luxury_id_input)

# Pass the contiguous integers into the Embedding layer
# input_dim needs to account for the vocab size + OOV (Out of Vocabulary) token
luxury_id_embed = Embedding(input_dim=len(luxury_unique_ids) + 1, output_dim=16)(luxury_lookup)
luxury_id_flat = Flatten()(luxury_id_embed)

# Define the remaining continuous/binary feature branch
luxury_features_input = Input(shape=(luxury_train_features.shape[1],), name='numeric_features')

# Merge branches and pass through Dense layers
luxury_merged = Concatenate()([luxury_id_flat, luxury_features_input])
luxury_dense1 = Dense(64, activation='relu', kernel_regularizer=l2(1e-4))(luxury_merged)
luxury_drop1 = Dropout(0.3)(luxury_dense1)
luxury_dense2 = Dense(32, activation='relu', kernel_regularizer=l2(1e-4))(luxury_drop1)
luxury_drop2 = Dropout(0.2)(luxury_dense2)
luxury_output = Dense(1, activation='sigmoid')(luxury_drop2) # Outputting target_3d

luxury_model = Model(inputs=[luxury_id_input, luxury_features_input], outputs=luxury_output)
luxury_model.compile(optimizer='adam', loss='mae', metrics=['mae'])
luxury_model.summary()
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1787343919.411882   19492 gpu_device.cc:2020] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 14978 MB memory:  -> device: 0, name: AMD Radeon Graphics, pci bus id: 0000:03:00.0
Model: "functional"
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ Layer (type)        ┃ Output Shape      ┃    Param # ┃ Connected to      ┃
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩
│ passthrough__id     │ (None, 1)         │          0 │ -                 │
│ (InputLayer)        │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ integer_lookup      │ (None, 1)         │          0 │ passthrough__id[… │
│ (IntegerLookup)     │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ embedding           │ (None, 1, 16)     │     23,456 │ integer_lookup[0… │
│ (Embedding)         │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ flatten (Flatten)   │ (None, 16)        │          0 │ embedding[0][0]   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ numeric_features    │ (None, 49)        │          0 │ -                 │
│ (InputLayer)        │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ concatenate         │ (None, 65)        │          0 │ flatten[0][0],    │
│ (Concatenate)       │                   │            │ numeric_features… │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense (Dense)       │ (None, 64)        │      4,224 │ concatenate[0][0] │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dropout (Dropout)   │ (None, 64)        │          0 │ dense[0][0]       │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense_1 (Dense)     │ (None, 32)        │      2,080 │ dropout[0][0]     │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dropout_1 (Dropout) │ (None, 32)        │          0 │ dense_1[0][0]     │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense_2 (Dense)     │ (None, 1)         │         33 │ dropout_1[0][0]   │
└─────────────────────┴───────────────────┴────────────┴───────────────────┘
 Total params: 29,793 (116.38 KB)
 Trainable params: 29,793 (116.38 KB)
 Non-trainable params: 0 (0.00 B)
Model: "functional_1"
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
┃ Layer (type)        ┃ Output Shape      ┃    Param # ┃ Connected to      ┃
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩
│ passthrough__id     │ (None, 1)         │          0 │ -                 │
│ (InputLayer)        │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ integer_lookup_1    │ (None, 1)         │          0 │ passthrough__id[… │
│ (IntegerLookup)     │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ embedding_1         │ (None, 1, 16)     │      5,520 │ integer_lookup_1… │
│ (Embedding)         │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ flatten_1 (Flatten) │ (None, 16)        │          0 │ embedding_1[0][0] │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ numeric_features    │ (None, 49)        │          0 │ -                 │
│ (InputLayer)        │                   │            │                   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ concatenate_1       │ (None, 65)        │          0 │ flatten_1[0][0],  │
│ (Concatenate)       │                   │            │ numeric_features… │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense_3 (Dense)     │ (None, 64)        │      4,224 │ concatenate_1[0]… │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dropout_2 (Dropout) │ (None, 64)        │          0 │ dense_3[0][0]     │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense_4 (Dense)     │ (None, 32)        │      2,080 │ dropout_2[0][0]   │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dropout_3 (Dropout) │ (None, 32)        │          0 │ dense_4[0][0]     │
├─────────────────────┼───────────────────┼────────────┼───────────────────┤
│ dense_5 (Dense)     │ (None, 1)         │         33 │ dropout_3[0][0]   │
└─────────────────────┴───────────────────┴────────────┴───────────────────┘
 Total params: 11,857 (46.32 KB)
 Trainable params: 11,857 (46.32 KB)
 Non-trainable params: 0 (0.00 B)
In [40]:
# hist = model.fit(x_train, y_train, validation_data=(x_test, y_test), epochs=20, batch_size=256)
early_stopping = EarlyStopping(
    monitor='val_mae',         # Metric to watch
    patience=5,                 # Number of epochs to wait for improvement
    restore_best_weights=True,  # Roll back to the best weights at the end
    verbose=1                   # Print log message when stopping
)
In [41]:
penny_hist = penny_model.fit(
    x=[penny_train_id, penny_train_features],
    y=penny_y_train,
    validation_data=([penny_val_id, penny_val_features], penny_y_val),
    epochs=20,
    batch_size=256,
    callbacks=early_stopping
)
Epoch 1/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 34s 9ms/step - loss: 0.0369 - mae: 0.0326 - val_loss: 0.0203 - val_mae: 0.0182
Epoch 2/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 32s 9ms/step - loss: 0.0241 - mae: 0.0224 - val_loss: 0.0192 - val_mae: 0.0178
Epoch 3/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 11s 3ms/step - loss: 0.0228 - mae: 0.0215 - val_loss: 0.0199 - val_mae: 0.0187
Epoch 4/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 12s 3ms/step - loss: 0.0224 - mae: 0.0213 - val_loss: 0.0189 - val_mae: 0.0178
Epoch 5/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 11s 3ms/step - loss: 0.0222 - mae: 0.0211 - val_loss: 0.0180 - val_mae: 0.0169
Epoch 6/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 12s 3ms/step - loss: 0.0221 - mae: 0.0210 - val_loss: 0.0214 - val_mae: 0.0203
Epoch 7/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 11s 3ms/step - loss: 0.0220 - mae: 0.0209 - val_loss: 0.0186 - val_mae: 0.0175
Epoch 8/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 12s 3ms/step - loss: 0.0218 - mae: 0.0208 - val_loss: 0.0193 - val_mae: 0.0183
Epoch 9/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 11s 3ms/step - loss: 0.0218 - mae: 0.0207 - val_loss: 0.0202 - val_mae: 0.0192
Epoch 10/20
3404/3404 ━━━━━━━━━━━━━━━━━━━━ 11s 3ms/step - loss: 0.0217 - mae: 0.0207 - val_loss: 0.0184 - val_mae: 0.0173
Epoch 10: early stopping
Restoring model weights from the end of the best epoch: 5.
In [42]:
luxury_hist = luxury_model.fit(
    x=[luxury_train_id, luxury_train_features],
    y=luxury_y_train,
    validation_data=([luxury_val_id, luxury_val_features], luxury_y_val),
    epochs=20,
    batch_size=256,
    callbacks=early_stopping
)
Epoch 1/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 7s 9ms/step - loss: 0.0500 - mae: 0.0432 - val_loss: 0.0241 - val_mae: 0.0191
Epoch 2/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - loss: 0.0176 - mae: 0.0136 - val_loss: 0.0166 - val_mae: 0.0135
Epoch 3/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 7s 10ms/step - loss: 0.0143 - mae: 0.0116 - val_loss: 0.0169 - val_mae: 0.0147
Epoch 4/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - loss: 0.0126 - mae: 0.0107 - val_loss: 0.0165 - val_mae: 0.0149
Epoch 5/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - loss: 0.0116 - mae: 0.0102 - val_loss: 0.0138 - val_mae: 0.0126
Epoch 6/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - loss: 0.0109 - mae: 0.0099 - val_loss: 0.0124 - val_mae: 0.0114
Epoch 7/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - loss: 0.0106 - mae: 0.0096 - val_loss: 0.0119 - val_mae: 0.0111
Epoch 8/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - loss: 0.0104 - mae: 0.0096 - val_loss: 0.0126 - val_mae: 0.0118
Epoch 9/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - loss: 0.0101 - mae: 0.0094 - val_loss: 0.0132 - val_mae: 0.0125
Epoch 10/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 10ms/step - loss: 0.0100 - mae: 0.0093 - val_loss: 0.0139 - val_mae: 0.0132
Epoch 11/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - loss: 0.0100 - mae: 0.0093 - val_loss: 0.0139 - val_mae: 0.0132
Epoch 12/20
640/640 ━━━━━━━━━━━━━━━━━━━━ 6s 9ms/step - loss: 0.0099 - mae: 0.0092 - val_loss: 0.0122 - val_mae: 0.0115
Epoch 12: early stopping
Restoring model weights from the end of the best epoch: 7.
In [43]:
# 1. Generate predictions on the test set
penny_y_pred_scaled = penny_model.predict([penny_test_id, penny_test_features])
luxury_y_pred_scaled = luxury_model.predict([luxury_test_id, luxury_test_features])
16422/16422 ━━━━━━━━━━━━━━━━━━━━ 26s 2ms/step
3254/3254 ━━━━━━━━━━━━━━━━━━━━ 5s 2ms/step
In [44]:
penny_y_pred_full = penny_y_preprocess.inverse_transform(penny_y_pred_scaled)
penny_y_test_full = penny_y_preprocess.inverse_transform(penny_y_test)
luxury_y_pred_full = luxury_y_preprocess.inverse_transform(luxury_y_pred_scaled)
luxury_y_test_full = luxury_y_preprocess.inverse_transform(luxury_y_test)
print('Targets inverse transformed')
Targets inverse transformed
In [45]:
from sklearn.metrics import mean_absolute_error, mean_squared_error, median_absolute_error

mae = mean_absolute_error(penny_y_test_full, penny_y_pred_full)
medae = median_absolute_error(penny_y_test_full, penny_y_pred_full)
rmse = np.sqrt(mean_squared_error(penny_y_test_full, penny_y_pred_full))

print(f"Mean Absolute Error: {mae/10000:.4f} gold")
print(f"Median Absolute Error: {medae/10000:.4f} gold")
print(f"Root Mean Squared Error: {rmse/10000:.4f} gold")

# Calculate the naive baseline error for your chosen horizon
# (Assuming today's buy_high is the baseline prediction for the target horizon)
naive_mae = mean_absolute_error(penny_y_test_full, penny_raw_test_buy_high)

print()
print(f"--- Benchmark Comparison for Penny {days}d ---")
print(f"Neural Network MAE: {mae/10000:.4f} gold")
print(f"Naive Baseline MAE:   {naive_mae/10000:.4f} gold")

if mae < naive_mae:
    print("Success: Your Penny neural network is beating the naive baseline!")
else:
    print("Warning: Your Penny model is performing worse than or equal to a flat line prediction.")
Mean Absolute Error: 0.0214 gold
Median Absolute Error: 0.0015 gold
Root Mean Squared Error: 0.0659 gold

--- Benchmark Comparison for Penny 7d ---
Neural Network MAE: 0.0214 gold
Naive Baseline MAE:   0.0059 gold
Warning: Your Penny model is performing worse than or equal to a flat line prediction.
In [46]:
mae = mean_absolute_error(luxury_y_test_full, luxury_y_pred_full)
medae = median_absolute_error(luxury_y_test_full, luxury_y_pred_full)
rmse = np.sqrt(mean_squared_error(luxury_y_test_full, luxury_y_pred_full))

print(f"Mean Absolute Error: {mae/10000:.4f} gold")
print(f"Median Absolute Error: {medae/10000:.4f} gold")
print(f"Root Mean Squared Error: {rmse/10000:.4f} gold")

# Calculate the naive baseline error for your chosen horizon
# (Assuming today's buy_high is the baseline prediction for the target horizon)
naive_mae = mean_absolute_error(luxury_y_test_full, luxury_raw_test_buy_high)

print()
print(f"--- Benchmark Comparison for Luxury {days}d ---")
print(f"Neural Network MAE: {mae/10000:.4f} gold")
print(f"Naive Baseline MAE:   {naive_mae/10000:.4f} gold")

if mae < naive_mae:
    print("Success: Your Luxury neural network is beating the naive baseline!")
else:
    print("Warning: Your Luxury model is performing worse than or equal to a flat line prediction.")
Mean Absolute Error: 9.7668 gold
Median Absolute Error: 0.2722 gold
Root Mean Squared Error: 73.7009 gold

--- Benchmark Comparison for Luxury 7d ---
Neural Network MAE: 9.7668 gold
Naive Baseline MAE:   2.2862 gold
Warning: Your Luxury model is performing worse than or equal to a flat line prediction.
In [47]:
plt.figure(figsize=(12, 5))

# Plot 1: Actual vs Predicted
plt.subplot(1, 2, 1)
plt.scatter(penny_y_test_full, penny_y_pred_full, alpha=0.1, s=2)
plt.plot([penny_y_test_full.min(), penny_y_test_full.max()], [penny_y_test_full.min(), penny_y_test_full.max()], 'r--', lw=2)
plt.xscale('log')
plt.yscale('log')
plt.xlabel("Actual Price (Log Scale)")
plt.ylabel("Predicted Price (Log Scale)")
plt.title("Actual vs. Predicted Prices")

# Plot 2: Residuals (Error Distribution)
plt.subplot(1, 2, 2)
residuals = penny_y_pred_full - penny_y_test_full
plt.hist(residuals, bins=100, range=(-5000, 5000), edgecolor='k')
plt.xlabel("Prediction Error (Copper)")
plt.ylabel("Frequency")
plt.title("Residual Distribution (-50s to +50s)")

plt.tight_layout()
plt.show()
No description has been provided for this image
In [48]:
plt.figure(figsize=(12, 5))

# Plot 1: Actual vs Predicted
plt.subplot(1, 2, 1)
plt.scatter(luxury_y_test_full, luxury_y_pred_full, alpha=0.1, s=2)
plt.plot([luxury_y_test_full.min(), luxury_y_test_full.max()], [luxury_y_test_full.min(), luxury_y_test_full.max()], 'r--', lw=2)
plt.xscale('log')
plt.yscale('log')
plt.xlabel("Actual Price (Log Scale)")
plt.ylabel("Predicted Price (Log Scale)")
plt.title("Actual vs. Predicted Prices")

# Plot 2: Residuals (Error Distribution)
plt.subplot(1, 2, 2)
residuals = luxury_y_pred_full - luxury_y_test_full
plt.hist(residuals, bins=100, range=(-5000, 5000), edgecolor='k')
plt.xlabel("Prediction Error (Copper)")
plt.ylabel("Frequency")
plt.title("Residual Distribution (-50s to +50s)")

plt.tight_layout()
plt.show()
No description has been provided for this image
In [49]:
penny_x_train.columns
Out[49]:
Index(['num_scaler__supply_demand_ratio', 'num_scaler__level',
       'num_scaler__vendor_value', 'num_scaler__current_sell_price',
       'num_scaler__current_buy_price', 'cat_encode__type_CraftingMaterial',
       'cat_encode__type_Trophy', 'cat_encode__rarity_Ascended',
       'cat_encode__rarity_Basic', 'cat_encode__rarity_Exotic',
       'cat_encode__rarity_Fine', 'cat_encode__rarity_Legendary',
       'cat_encode__rarity_Masterwork', 'cat_encode__rarity_Rare',
       'passthrough__id', 'passthrough__lunar_new_year',
       'passthrough__lunar_new_year_next_week',
       'passthrough__lunar_new_year_last_week',
       'passthrough__super_adventure_festival',
       'passthrough__super_adventure_festival_next_week',
       'passthrough__super_adventure_festival_last_week',
       'passthrough__dragon_bash', 'passthrough__dragon_bash_next_week',
       'passthrough__dragon_bash_last_week',
       'passthrough__festival_of_the_four_winds',
       'passthrough__festival_of_the_four_winds_next_week',
       'passthrough__festival_of_the_four_winds_last_week',
       'passthrough__halloween', 'passthrough__halloween_next_week',
       'passthrough__halloween_last_week', 'passthrough__wintersday',
       'passthrough__wintersday_next_week',
       'passthrough__wintersday_last_week', 'passthrough__PvpLobby',
       'passthrough__Activity', 'passthrough__Wvw', 'passthrough__Dungeon',
       'passthrough__Pve', 'passthrough__NoSell', 'passthrough__NoSalvage',
       'passthrough__Unique', 'passthrough__NoMysticForge',
       'passthrough__DeleteWarning', 'passthrough__NotUpgradeable',
       'passthrough__sin_day_of_year', 'passthrough__cos_day_of_year',
       'passthrough__sin_day_of_week', 'passthrough__cos_day_of_week',
       'passthrough__sin_day_of_month', 'passthrough__cos_day_of_month'],
      dtype='str')
In [50]:
luxury_x_train.columns
Out[50]:
Index(['num_scaler__supply_demand_ratio', 'num_scaler__level',
       'num_scaler__vendor_value', 'num_scaler__current_sell_price',
       'num_scaler__current_buy_price', 'cat_encode__type_CraftingMaterial',
       'cat_encode__type_Trophy', 'cat_encode__rarity_Ascended',
       'cat_encode__rarity_Basic', 'cat_encode__rarity_Exotic',
       'cat_encode__rarity_Fine', 'cat_encode__rarity_Legendary',
       'cat_encode__rarity_Masterwork', 'cat_encode__rarity_Rare',
       'passthrough__id', 'passthrough__lunar_new_year',
       'passthrough__lunar_new_year_next_week',
       'passthrough__lunar_new_year_last_week',
       'passthrough__super_adventure_festival',
       'passthrough__super_adventure_festival_next_week',
       'passthrough__super_adventure_festival_last_week',
       'passthrough__dragon_bash', 'passthrough__dragon_bash_next_week',
       'passthrough__dragon_bash_last_week',
       'passthrough__festival_of_the_four_winds',
       'passthrough__festival_of_the_four_winds_next_week',
       'passthrough__festival_of_the_four_winds_last_week',
       'passthrough__halloween', 'passthrough__halloween_next_week',
       'passthrough__halloween_last_week', 'passthrough__wintersday',
       'passthrough__wintersday_next_week',
       'passthrough__wintersday_last_week', 'passthrough__PvpLobby',
       'passthrough__Activity', 'passthrough__Wvw', 'passthrough__Dungeon',
       'passthrough__Pve', 'passthrough__NoSell', 'passthrough__NoSalvage',
       'passthrough__Unique', 'passthrough__NoMysticForge',
       'passthrough__DeleteWarning', 'passthrough__NotUpgradeable',
       'passthrough__sin_day_of_year', 'passthrough__cos_day_of_year',
       'passthrough__sin_day_of_week', 'passthrough__cos_day_of_week',
       'passthrough__sin_day_of_month', 'passthrough__cos_day_of_month'],
      dtype='str')
In [51]:
import joblib
penny_model.save(f'Models/PennyLuxury/penny_model_{days}d.keras')
joblib.dump(penny_preprocess, f'Models/PennyLuxury/penny_preprocess_{days}d.joblib')
joblib.dump(penny_y_preprocess, f'Models/PennyLuxury/penny_y_preprocess_{days}d.joblib')

luxury_model.save(f'Models/PennyLuxury/luxury_model_{days}d.keras')
joblib.dump(luxury_preprocess, f'Models/PennyLuxury/luxury_preprocess_{days}d.joblib')
joblib.dump(luxury_y_preprocess, f'Models/PennyLuxury/luxury_y_preprocess_{days}d.joblib')
Out[51]:
['Models/PennyLuxury/luxury_y_preprocess_7d.joblib']
In [ ]: