thr conf matrix added
This commit is contained in:
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='ttools',
|
name='ttools',
|
||||||
version='0.7.82',
|
version='0.7.9',
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
install_requires=[
|
install_requires=[
|
||||||
# list your dependencies here
|
# list your dependencies here
|
||||||
|
|||||||
101
ttools/models.py
101
ttools/models.py
@ -778,6 +778,7 @@ class LibraryTradingModel:
|
|||||||
return results, model
|
return results, model
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
raise e
|
||||||
print(f"Error in iteration {iteration_num}: {str(e)} - {format_exc()}")
|
print(f"Error in iteration {iteration_num}: {str(e)} - {format_exc()}")
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
@ -1020,7 +1021,7 @@ class LibraryTradingModel:
|
|||||||
left=[],
|
left=[],
|
||||||
middle1=[(results["predicted"],"predicted"),(results["actual"],"actual"),(prob_df,)],
|
middle1=[(results["predicted"],"predicted"),(results["actual"],"actual"),(prob_df,)],
|
||||||
).chart(size="s", precision=6, title=f"Iteration {iteration_num} classes:{self.config.n_classes} forward_bars:{self.config.forward_bars}")
|
).chart(size="s", precision=6, title=f"Iteration {iteration_num} classes:{self.config.n_classes} forward_bars:{self.config.forward_bars}")
|
||||||
|
|
||||||
num_classes = self.config.n_classes
|
num_classes = self.config.n_classes
|
||||||
|
|
||||||
# Add probability columns to results
|
# Add probability columns to results
|
||||||
@ -1062,6 +1063,104 @@ class LibraryTradingModel:
|
|||||||
print("Overall Accuracy:", (results['predicted'] == results['actual']).mean())
|
print("Overall Accuracy:", (results['predicted'] == results['actual']).mean())
|
||||||
print("Directional Accuracy:", results['direction_correct'].mean())
|
print("Directional Accuracy:", results['direction_correct'].mean())
|
||||||
|
|
||||||
|
print("New confusion matrix")
|
||||||
|
|
||||||
|
def plot_threshold_confusion_matrices(results, predictions_proba, thresholds=[0.3, 0.5, 0.8], num_classes=5):
|
||||||
|
"""
|
||||||
|
Plot confusion matrices for different probability thresholds
|
||||||
|
"""
|
||||||
|
# Calculate subplot dimensions
|
||||||
|
plots_per_row = 3
|
||||||
|
num_rows = (len(thresholds) + plots_per_row - 1) // plots_per_row # Ceiling division
|
||||||
|
num_cols = min(len(thresholds), plots_per_row)
|
||||||
|
|
||||||
|
# Create figure with extra spacing between subplots
|
||||||
|
fig = plt.figure(figsize=(7*num_cols, 6*num_rows))
|
||||||
|
gs = fig.add_gridspec(num_rows, num_cols, hspace=0.4, wspace=0.3)
|
||||||
|
|
||||||
|
for idx, threshold in enumerate(thresholds):
|
||||||
|
# Calculate subplot position
|
||||||
|
row = idx // plots_per_row
|
||||||
|
col = idx % plots_per_row
|
||||||
|
ax = fig.add_subplot(gs[row, col])
|
||||||
|
|
||||||
|
# Create masked predictions where low confidence predictions are marked as -1
|
||||||
|
predicted_classes = np.full(len(predictions_proba), -1)
|
||||||
|
max_probs = np.max(predictions_proba, axis=1)
|
||||||
|
confident_mask = max_probs >= threshold
|
||||||
|
|
||||||
|
# Only assign predictions where confidence meets threshold
|
||||||
|
predicted_classes[confident_mask] = np.argmax(predictions_proba[confident_mask], axis=1)
|
||||||
|
|
||||||
|
# Filter results to only include confident predictions
|
||||||
|
valid_indices = predicted_classes != -1
|
||||||
|
filtered_actual = results['actual'][valid_indices]
|
||||||
|
filtered_predicted = predicted_classes[valid_indices]
|
||||||
|
|
||||||
|
if len(filtered_actual) > 0:
|
||||||
|
# Calculate confusion matrix for confident predictions
|
||||||
|
conf_matrix = confusion_matrix(filtered_actual, filtered_predicted)
|
||||||
|
conf_matrix_pct = conf_matrix / conf_matrix.sum(axis=1)[:, np.newaxis]
|
||||||
|
|
||||||
|
# Plot heatmap
|
||||||
|
sns.heatmap(conf_matrix_pct, annot=conf_matrix, fmt='d', cmap='YlOrRd',
|
||||||
|
xticklabels=range(num_classes), yticklabels=range(num_classes), ax=ax)
|
||||||
|
|
||||||
|
# Add dynamic directional indicators based on number of classes
|
||||||
|
negative_end = num_classes // 3
|
||||||
|
positive_start = num_classes - (num_classes // 3)
|
||||||
|
|
||||||
|
# Add lines at positions that divide the classes into thirds
|
||||||
|
ax.axhline(y=negative_end, color='blue', linestyle='--', alpha=0.3)
|
||||||
|
ax.axhline(y=positive_start, color='blue', linestyle='--', alpha=0.3)
|
||||||
|
ax.axvline(x=negative_end, color='blue', linestyle='--', alpha=0.3)
|
||||||
|
ax.axvline(x=positive_start, color='blue', linestyle='--', alpha=0.3)
|
||||||
|
|
||||||
|
# Add dynamically positioned direction labels
|
||||||
|
ax.text(-0.2, negative_end/2, 'Negative', rotation=90, verticalalignment='center')
|
||||||
|
ax.text(-0.2, (positive_start + negative_end)/2, 'Neutral', rotation=90, verticalalignment='center')
|
||||||
|
ax.text(-0.2, (positive_start + num_classes)/2, 'Positive', rotation=90, verticalalignment='center')
|
||||||
|
|
||||||
|
# Calculate accuracy metrics
|
||||||
|
accuracy = (filtered_predicted == filtered_actual).mean()
|
||||||
|
|
||||||
|
# Calculate directional metrics
|
||||||
|
def get_direction(x):
|
||||||
|
negative_end = num_classes // 3
|
||||||
|
positive_start = num_classes - (num_classes // 3)
|
||||||
|
if x < negative_end: return 'negative'
|
||||||
|
elif x >= positive_start: return 'positive'
|
||||||
|
return 'neutral'
|
||||||
|
|
||||||
|
pred_direction = np.vectorize(get_direction)(filtered_predicted)
|
||||||
|
actual_direction = np.vectorize(get_direction)(filtered_actual)
|
||||||
|
directional_accuracy = (pred_direction == actual_direction).mean()
|
||||||
|
|
||||||
|
coverage = np.mean(confident_mask)
|
||||||
|
title = f'Threshold: {threshold}\n'
|
||||||
|
title += f'Coverage: {coverage:.2%}\n'
|
||||||
|
title += 'Color: % of True Class\nValues: Absolute Count'
|
||||||
|
ax.set_title(title)
|
||||||
|
ax.set_xlabel('Predicted Class')
|
||||||
|
ax.set_ylabel('True Class')
|
||||||
|
|
||||||
|
ax.text(0, -0.2, f'Acc: {accuracy:.2f}\nDir Acc: {directional_accuracy:.2f}',
|
||||||
|
transform=ax.transAxes)
|
||||||
|
else:
|
||||||
|
ax.text(0.5, 0.5, f'No predictions meet\nthreshold {threshold}',
|
||||||
|
ha='center', va='center')
|
||||||
|
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.show()
|
||||||
|
|
||||||
|
# Replace the original confusion matrix plotting with:
|
||||||
|
plot_threshold_confusion_matrices(
|
||||||
|
results,
|
||||||
|
predictions_proba,
|
||||||
|
thresholds=[0.3, 0.5, 0.6, 0.7, 0.8, 0.9], # Configurable thresholds
|
||||||
|
num_classes=len(model.classes_)
|
||||||
|
)
|
||||||
|
|
||||||
# Create visual confusion matrix
|
# Create visual confusion matrix
|
||||||
conf_matrix = confusion_matrix(results['actual'], results['predicted'])
|
conf_matrix = confusion_matrix(results['actual'], results['predicted'])
|
||||||
plt.figure(figsize=(10, 8))
|
plt.figure(figsize=(10, 8))
|
||||||
|
|||||||
Reference in New Issue
Block a user