Compare commits
18 Commits
8dc55a1201
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 93d8bf4a5b | |||
| 4887c03420 | |||
| 5d4ec549c0 | |||
| b12bfa4287 | |||
| d06c904f4b | |||
| 31874b3159 | |||
| 2f5ba2c829 | |||
| e4aae5bb86 | |||
| 6b8a100ad0 | |||
| 9996d673f4 | |||
| e512774f97 | |||
| 32ae8d1d46 | |||
| 0346d939ab | |||
| 67970cea36 | |||
| 7e73535e32 | |||
| 4777fbbdc8 | |||
| a34b004ee0 | |||
| dc3722ca08 |
594
Classification Lab/inclass_lab.ipynb
Normal file
594
Classification Lab/inclass_lab.ipynb
Normal file
@@ -0,0 +1,594 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dffa60e8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%matplotlib inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3340eabf",
|
||||
"metadata": {
|
||||
"cell_marker": "\"\"\""
|
||||
},
|
||||
"source": [
|
||||
"Inclass-Lab\n",
|
||||
"\n",
|
||||
"Automatically generated by Colab.\n",
|
||||
"\n",
|
||||
"Original file is located at\n",
|
||||
" https://colab.research.google.com/drive/13N7lQHvv4_LxKgcerumJ-18e5GfdBggm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "34271feb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9491847c",
|
||||
"metadata": {
|
||||
"cell_marker": "\"\"\""
|
||||
},
|
||||
"source": [
|
||||
"In-Class Lab: Comparing Classification Models (Breast Cancer Dataset)\n",
|
||||
"\n",
|
||||
"Learning Objectives\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"By the end of this lab, you should be able to:\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"* Train multiple models (KNN, Logistic Regression, Decision Tree)\n",
|
||||
"* Compare performance across various scenarios\n",
|
||||
"* Understand the effect of scaling and evaluation methods\n",
|
||||
"* Interpret confusion matrix & classification report\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cceb43dc",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 1:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "818bfdad",
|
||||
"metadata": {
|
||||
"cell_marker": "'''",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"Load dataset\n",
|
||||
"Explain features/target\n",
|
||||
"Do train_test_split"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6de94b5d",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a8899ca0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.datasets import load_breast_cancer\n",
|
||||
"data = load_breast_cancer()\n",
|
||||
"X = data.data\n",
|
||||
"y = data.target\n",
|
||||
"\n",
|
||||
"print(data.target_names)\n",
|
||||
"print(X.shape)\n",
|
||||
"#0 - malignant\n",
|
||||
"#1 - benigh"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ae1b0d61",
|
||||
"metadata": {
|
||||
"cell_marker": "###############################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 2: IMPORT LIBRARIES FOR CLASSIFIERS\n",
|
||||
"##############################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8db6dfd6",
|
||||
"metadata": {
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.neighbors import KNeighborsClassifier\n",
|
||||
"from sklearn.linear_model import LogisticRegression\n",
|
||||
"from sklearn.tree import DecisionTreeClassifier\n",
|
||||
"import numpy as np"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a2301b40",
|
||||
"metadata": {
|
||||
"cell_marker": "#########################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 3: IMPORT MODUL FOR DATA SPLIT\n",
|
||||
"########################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "75fe2532",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.model_selection import train_test_split"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fb69921d",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 4: SPLIT THE DATASET\n",
|
||||
"###################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6eb66fc0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b182e930",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 5\n",
|
||||
"TASK 1: Train 3 models (no scaling)\n",
|
||||
"###################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f31f0262",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"knn = KNeighborsClassifier(n_neighbors=5)\n",
|
||||
"logreg = LogisticRegression(max_iter=5000)\n",
|
||||
"tree = DecisionTreeClassifier()\n",
|
||||
"\n",
|
||||
"knn.fit(X_train, y_train)\n",
|
||||
"logreg.fit(X_train, y_train)\n",
|
||||
"tree.fit(X_train, y_train)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d3e0088e",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 6\n",
|
||||
"Task 2: Evaluate accuracy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3a8845a1",
|
||||
"metadata": {
|
||||
"cell_marker": "'''",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"* Which model performs best?\n",
|
||||
"* Are the results very different?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d49b62b3",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "395d887c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"KNN:\", knn.score(X_test, y_test))\n",
|
||||
"print(\"LogReg:\", logreg.score(X_test, y_test))\n",
|
||||
"print(\"Tree:\", tree.score(X_test, y_test))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9de74c34",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################"
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 7\n",
|
||||
"Part 2: Evaluation Metrics\n",
|
||||
"Task 3: Confusion Matrix"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "deec64c6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import confusion_matrix\n",
|
||||
"print(confusion_matrix(y_test, knn.predict(X_test)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "18bc0c0e",
|
||||
"metadata": {
|
||||
"cell_marker": "#####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 8: CLASSIFICATION FREPORT"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a2e8747f",
|
||||
"metadata": {
|
||||
"cell_marker": "'''",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"* Which model has better recall?\n",
|
||||
"* Which is better for detecting cancer?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "88303af7",
|
||||
"metadata": {
|
||||
"cell_marker": "#####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e9ef7bea",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.metrics import classification_report\n",
|
||||
"print(classification_report(y_test, knn.predict(X_test)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c1d8978a",
|
||||
"metadata": {
|
||||
"cell_marker": "########################################"
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 9:\n",
|
||||
"Part 3: Scaling Effect\n",
|
||||
"Task 5: Apply scaling using pipeline\n",
|
||||
"#######################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "84e1f5d4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.pipeline import Pipeline\n",
|
||||
"from sklearn.preprocessing import StandardScaler\n",
|
||||
"from sklearn.metrics import accuracy_score, confusion_matrix, classification_report\n",
|
||||
"\n",
|
||||
"knn_scaled = Pipeline([\n",
|
||||
" ('scaler', StandardScaler()),\n",
|
||||
" ('knn', KNeighborsClassifier(n_neighbors=5))\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"logreg_scaled = Pipeline([\n",
|
||||
" ('scaler', StandardScaler()),\n",
|
||||
" ('logreg', LogisticRegression(max_iter=5000))\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"tree_scaled = Pipeline([\n",
|
||||
" ('scaler', StandardScaler()),\n",
|
||||
" ('tree', DecisionTreeClassifier(random_state=42))\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"knn_scaled.fit(X_train, y_train)\n",
|
||||
"logreg_scaled.fit(X_train, y_train)\n",
|
||||
"tree_scaled.fit(X_train, y_train)\n",
|
||||
"\n",
|
||||
"knn_pred_scaled = knn_scaled.predict(X_test)\n",
|
||||
"logreg_pred_scaled = logreg_scaled.predict(X_test)\n",
|
||||
"tree_pred_scaled = tree_scaled.predict(X_test)\n",
|
||||
"\n",
|
||||
"print(\"\\n=== RESULTS WITH SCALING ===\")\n",
|
||||
"print(\"KNN Accuracy:\", accuracy_score(y_test, knn_pred_scaled))\n",
|
||||
"print(\"Logistic Regression Accuracy:\", accuracy_score(y_test, logreg_pred_scaled))\n",
|
||||
"print(\"Decision Tree Accuracy:\", accuracy_score(y_test, tree_pred_scaled))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d5caa8ec",
|
||||
"metadata": {
|
||||
"cell_marker": "#####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 10: CLASSIFICATION REPORT\n",
|
||||
"####################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6643f0af",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"\\n=== CLASSIFICATION REPORTS (WITH SCALING) ===\")\n",
|
||||
"\n",
|
||||
"print(\"\\nKNN Report:\")\n",
|
||||
"print(classification_report(y_test, knn_pred_scaled))\n",
|
||||
"\n",
|
||||
"print(\"\\nLogistic Regression Report:\")\n",
|
||||
"print(classification_report(y_test, logreg_pred_scaled))\n",
|
||||
"\n",
|
||||
"print(\"\\nDecision Tree Report:\")\n",
|
||||
"print(classification_report(y_test, tree_pred_scaled))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c38c51d0",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 11: CONFUSION MATRIX\n",
|
||||
"###################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "444fbb13",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"\\n=== CONFUSION MATRICES (WITH SCALING) ===\")\n",
|
||||
"\n",
|
||||
"print(\"\\nKNN Confusion Matrix:\")\n",
|
||||
"print(confusion_matrix(y_test, knn_pred_scaled))\n",
|
||||
"\n",
|
||||
"print(\"\\nLogistic Regression Confusion Matrix:\")\n",
|
||||
"print(confusion_matrix(y_test, logreg_pred_scaled))\n",
|
||||
"\n",
|
||||
"print(\"\\nDecision Tree Confusion Matrix:\")\n",
|
||||
"print(confusion_matrix(y_test, tree_pred_scaled))\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c5d82a08",
|
||||
"metadata": {
|
||||
"cell_marker": "###############################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 12: MODWLS WITH CROSS-VALIDATION\n",
|
||||
"##############################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "17493cc3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.model_selection import cross_val_score\n",
|
||||
"from sklearn.preprocessing import StandardScaler\n",
|
||||
"\n",
|
||||
"knn_pipeline = Pipeline([\n",
|
||||
" ('scaler', StandardScaler()),\n",
|
||||
" ('knn', KNeighborsClassifier(n_neighbors=5))\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"logreg_pipeline = Pipeline([\n",
|
||||
" ('scaler', StandardScaler()),\n",
|
||||
" ('logreg', LogisticRegression(max_iter=5000))\n",
|
||||
"])\n",
|
||||
"\n",
|
||||
"tree_model = DecisionTreeClassifier(random_state=42)\n",
|
||||
"\n",
|
||||
"knn_cv_scores = cross_val_score(knn_pipeline, X, y, cv=5, scoring='accuracy')\n",
|
||||
"logreg_cv_scores = cross_val_score(logreg_pipeline, X, y, cv=5, scoring='accuracy')\n",
|
||||
"tree_cv_scores = cross_val_score(tree_model, X, y, cv=5, scoring='accuracy')\n",
|
||||
"\n",
|
||||
"print(\"=== Cross-Validation Results ===\")\n",
|
||||
"\n",
|
||||
"print(\"\\nKNN\")\n",
|
||||
"print(\"CV Scores:\", knn_cv_scores)\n",
|
||||
"print(\"Mean Accuracy:\", np.mean(knn_cv_scores))\n",
|
||||
"print(\"Standard Deviation:\", np.std(knn_cv_scores))\n",
|
||||
"\n",
|
||||
"print(\"\\nLogistic Regression\")\n",
|
||||
"print(\"CV Scores:\", logreg_cv_scores)\n",
|
||||
"print(\"Mean Accuracy:\", np.mean(logreg_cv_scores))\n",
|
||||
"print(\"Standard Deviation:\", np.std(logreg_cv_scores))\n",
|
||||
"\n",
|
||||
"print(\"\\nDecision Tree\")\n",
|
||||
"print(\"CV Scores:\", tree_cv_scores)\n",
|
||||
"print(\"Mean Accuracy:\", np.mean(tree_cv_scores))\n",
|
||||
"print(\"Standard Deviation:\", np.std(tree_cv_scores))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "94d94dd2",
|
||||
"metadata": {
|
||||
"cell_marker": "####################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 13: CONFUSION MATRIX\n",
|
||||
"###################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c706abc3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.model_selection import cross_val_predict\n",
|
||||
"from sklearn.metrics import confusion_matrix, classification_report\n",
|
||||
"\n",
|
||||
"knn_pred = cross_val_predict(knn_pipeline, X, y, cv=5)\n",
|
||||
"logreg_pred = cross_val_predict(logreg_pipeline, X, y, cv=5)\n",
|
||||
"tree_pred = cross_val_predict(tree_model, X, y, cv=5)\n",
|
||||
"\n",
|
||||
"print(\"\\n=== Confusion Matrices ===\")\n",
|
||||
"print(\"\\nKNN\")\n",
|
||||
"print(confusion_matrix(y, knn_pred))\n",
|
||||
"\n",
|
||||
"print(\"\\nLogistic Regression\")\n",
|
||||
"print(confusion_matrix(y, logreg_pred))\n",
|
||||
"\n",
|
||||
"print(\"\\nDecision Tree\")\n",
|
||||
"print(confusion_matrix(y, tree_pred))\n",
|
||||
"\n",
|
||||
"print(\"\\n=== Classification Reports ===\")\n",
|
||||
"print(\"\\nKNN\")\n",
|
||||
"print(classification_report(y, knn_pred))\n",
|
||||
"\n",
|
||||
"print(\"\\nLogistic Regression\")\n",
|
||||
"print(classification_report(y, logreg_pred))\n",
|
||||
"\n",
|
||||
"print(\"\\nDecision Tree\")\n",
|
||||
"print(classification_report(y, tree_pred))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "34354ec9",
|
||||
"metadata": {
|
||||
"cell_marker": "###########################################",
|
||||
"lines_to_next_cell": 0
|
||||
},
|
||||
"source": [
|
||||
"BLOCK 14: LETS GET THE BEST VALUE FOR K\n",
|
||||
"task: use the k value to recompute the previous KNN model and evaluate the performance\n",
|
||||
"#########################################"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "93fa45e5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.model_selection import cross_val_score\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"k_values = range(1, 21)\n",
|
||||
"scores = []\n",
|
||||
"\n",
|
||||
"for k in k_values:\n",
|
||||
" knn = KNeighborsClassifier(n_neighbors=k)\n",
|
||||
" cv_scores = cross_val_score(knn, X, y, cv=5)\n",
|
||||
" scores.append(np.mean(cv_scores))\n",
|
||||
"\n",
|
||||
"best_k = k_values[np.argmax(scores)]\n",
|
||||
"\n",
|
||||
"print(\"Best k:\", best_k)\n",
|
||||
"print(\"Best CV Accuracy:\", max(scores))\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"jupytext": {
|
||||
"cell_metadata_filter": "-all",
|
||||
"encoding": "# -*- coding: utf-8 -*-",
|
||||
"main_language": "python",
|
||||
"notebook_metadata_filter": "-all"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
284
Classification Lab/inclass_lab.py
Normal file
284
Classification Lab/inclass_lab.py
Normal file
@@ -0,0 +1,284 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Inclass-Lab
|
||||
|
||||
Automatically generated by Colab.
|
||||
|
||||
Original file is located at
|
||||
https://colab.research.google.com/drive/13N7lQHvv4_LxKgcerumJ-18e5GfdBggm
|
||||
"""
|
||||
|
||||
|
||||
|
||||
"""In-Class Lab: Comparing Classification Models (Breast Cancer Dataset)
|
||||
|
||||
Learning Objectives
|
||||
|
||||
---
|
||||
|
||||
|
||||
By the end of this lab, you should be able to:
|
||||
|
||||
|
||||
|
||||
* Train multiple models (KNN, Logistic Regression, Decision Tree)
|
||||
* Compare performance across various scenarios
|
||||
* Understand the effect of scaling and evaluation methods
|
||||
* Interpret confusion matrix & classification report
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
####################################
|
||||
# BLOCK 1:
|
||||
'''
|
||||
Load dataset
|
||||
Explain features/target
|
||||
Do train_test_split
|
||||
'''
|
||||
####################################
|
||||
from sklearn.datasets import load_breast_cancer
|
||||
data = load_breast_cancer()
|
||||
X = data.data
|
||||
y = data.target
|
||||
|
||||
print(data.target_names)
|
||||
print(X.shape)
|
||||
#0 - malignant
|
||||
#1 - benigh
|
||||
|
||||
'''
|
||||
Answer: The dataset contains 569 samples with 30 features each. The target variable has two classes: 0 (malignant) and 1 (benign). The goal is to classify tumors as either malignant or benign based on the features provided.
|
||||
'''
|
||||
###############################
|
||||
# BLOCK 2: IMPORT LIBRARIES FOR CLASSIFIERS
|
||||
###############################
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.tree import DecisionTreeClassifier
|
||||
import numpy as np
|
||||
#########################################
|
||||
# BLOCK 3: IMPORT MODUL FOR DATA SPLIT
|
||||
#########################################
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
####################################
|
||||
# BLOCK 4: SPLIT THE DATASET
|
||||
####################################
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
|
||||
|
||||
####################################
|
||||
# BLOCK 5
|
||||
#TASK 1: Train 3 models (no scaling)
|
||||
####################################
|
||||
knn = KNeighborsClassifier(n_neighbors=5)
|
||||
logreg = LogisticRegression(max_iter=5000)
|
||||
tree = DecisionTreeClassifier()
|
||||
|
||||
knn.fit(X_train, y_train)
|
||||
logreg.fit(X_train, y_train)
|
||||
tree.fit(X_train, y_train)
|
||||
|
||||
####################################
|
||||
# BLOCK 6
|
||||
# Task 2: Evaluate accuracy
|
||||
'''
|
||||
* Which model performs best?
|
||||
* Are the results very different?
|
||||
'''
|
||||
####################################
|
||||
print("KNN:", knn.score(X_test, y_test))
|
||||
print("LogReg:", logreg.score(X_test, y_test))
|
||||
print("Tree:", tree.score(X_test, y_test))
|
||||
|
||||
'''
|
||||
Answer: The results are as follows:
|
||||
KNN: 0.956140350877193
|
||||
LogReg: 0.956140350877193
|
||||
Tree: 0.9298245614035088
|
||||
|
||||
They are all very similar, however LogReg and KNN perform slightly better than the Decision Tree in terms of accuracy on the test set. The difference is not very large, but it suggests that KNN and Logistic Regression may be more effective for this particular dataset.
|
||||
'''
|
||||
|
||||
####################################
|
||||
#BLOCK 7
|
||||
# Part 2: Evaluation Metrics
|
||||
# Task 3: Confusion Matrix
|
||||
|
||||
from sklearn.metrics import confusion_matrix
|
||||
print(confusion_matrix(y_test, knn.predict(X_test)))
|
||||
|
||||
#####################################
|
||||
# BLOCK 8: CLASSIFICATION FREPORT
|
||||
'''
|
||||
* Which model has better recall?
|
||||
* Which is better for detecting cancer?
|
||||
'''
|
||||
|
||||
'''
|
||||
Answer: The recall for the model in Block 8 is 0.88 for malignant, so it correctly identifies 88% of cancer cases.
|
||||
'''
|
||||
#####################################
|
||||
from sklearn.metrics import classification_report
|
||||
print(classification_report(y_test, knn.predict(X_test)))
|
||||
|
||||
########################################
|
||||
# BLOCK 9:
|
||||
# Part 3: Scaling Effect
|
||||
# Task 5: Apply scaling using pipeline
|
||||
########################################
|
||||
|
||||
from sklearn.pipeline import Pipeline
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report
|
||||
|
||||
knn_scaled = Pipeline([
|
||||
('scaler', StandardScaler()),
|
||||
('knn', KNeighborsClassifier(n_neighbors=5))
|
||||
])
|
||||
|
||||
logreg_scaled = Pipeline([
|
||||
('scaler', StandardScaler()),
|
||||
('logreg', LogisticRegression(max_iter=5000))
|
||||
])
|
||||
|
||||
tree_scaled = Pipeline([
|
||||
('scaler', StandardScaler()),
|
||||
('tree', DecisionTreeClassifier(random_state=42))
|
||||
])
|
||||
|
||||
knn_scaled.fit(X_train, y_train)
|
||||
logreg_scaled.fit(X_train, y_train)
|
||||
tree_scaled.fit(X_train, y_train)
|
||||
|
||||
knn_pred_scaled = knn_scaled.predict(X_test)
|
||||
logreg_pred_scaled = logreg_scaled.predict(X_test)
|
||||
tree_pred_scaled = tree_scaled.predict(X_test)
|
||||
|
||||
print("\n=== RESULTS WITH SCALING ===")
|
||||
print("KNN Accuracy:", accuracy_score(y_test, knn_pred_scaled))
|
||||
print("Logistic Regression Accuracy:", accuracy_score(y_test, logreg_pred_scaled))
|
||||
print("Decision Tree Accuracy:", accuracy_score(y_test, tree_pred_scaled))
|
||||
|
||||
#####################################
|
||||
# BLOCK 10: CLASSIFICATION REPORT
|
||||
#####################################
|
||||
print("\n=== CLASSIFICATION REPORTS (WITH SCALING) ===")
|
||||
|
||||
print("\nKNN Report:")
|
||||
print(classification_report(y_test, knn_pred_scaled))
|
||||
|
||||
print("\nLogistic Regression Report:")
|
||||
print(classification_report(y_test, logreg_pred_scaled))
|
||||
|
||||
print("\nDecision Tree Report:")
|
||||
print(classification_report(y_test, tree_pred_scaled))
|
||||
|
||||
####################################
|
||||
# BLOCK 11: CONFUSION MATRIX
|
||||
####################################
|
||||
print("\n=== CONFUSION MATRICES (WITH SCALING) ===")
|
||||
|
||||
print("\nKNN Confusion Matrix:")
|
||||
print(confusion_matrix(y_test, knn_pred_scaled))
|
||||
|
||||
print("\nLogistic Regression Confusion Matrix:")
|
||||
print(confusion_matrix(y_test, logreg_pred_scaled))
|
||||
|
||||
print("\nDecision Tree Confusion Matrix:")
|
||||
print(confusion_matrix(y_test, tree_pred_scaled))
|
||||
|
||||
|
||||
|
||||
###############################################
|
||||
# BLOCK 12: MODWLS WITH CROSS-VALIDATION
|
||||
###############################################
|
||||
from sklearn.model_selection import cross_val_score
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
|
||||
knn_pipeline = Pipeline([
|
||||
('scaler', StandardScaler()),
|
||||
('knn', KNeighborsClassifier(n_neighbors=5))
|
||||
])
|
||||
|
||||
logreg_pipeline = Pipeline([
|
||||
('scaler', StandardScaler()),
|
||||
('logreg', LogisticRegression(max_iter=5000))
|
||||
])
|
||||
|
||||
tree_model = DecisionTreeClassifier(random_state=42)
|
||||
|
||||
knn_cv_scores = cross_val_score(knn_pipeline, X, y, cv=5, scoring='accuracy')
|
||||
logreg_cv_scores = cross_val_score(logreg_pipeline, X, y, cv=5, scoring='accuracy')
|
||||
tree_cv_scores = cross_val_score(tree_model, X, y, cv=5, scoring='accuracy')
|
||||
|
||||
print("=== Cross-Validation Results ===")
|
||||
|
||||
print("\nKNN")
|
||||
print("CV Scores:", knn_cv_scores)
|
||||
print("Mean Accuracy:", np.mean(knn_cv_scores))
|
||||
print("Standard Deviation:", np.std(knn_cv_scores))
|
||||
|
||||
print("\nLogistic Regression")
|
||||
print("CV Scores:", logreg_cv_scores)
|
||||
print("Mean Accuracy:", np.mean(logreg_cv_scores))
|
||||
print("Standard Deviation:", np.std(logreg_cv_scores))
|
||||
|
||||
print("\nDecision Tree")
|
||||
print("CV Scores:", tree_cv_scores)
|
||||
print("Mean Accuracy:", np.mean(tree_cv_scores))
|
||||
print("Standard Deviation:", np.std(tree_cv_scores))
|
||||
|
||||
####################################
|
||||
# BLOCK 13: CONFUSION MATRIX
|
||||
####################################
|
||||
from sklearn.model_selection import cross_val_predict
|
||||
from sklearn.metrics import confusion_matrix, classification_report
|
||||
|
||||
knn_pred = cross_val_predict(knn_pipeline, X, y, cv=5)
|
||||
logreg_pred = cross_val_predict(logreg_pipeline, X, y, cv=5)
|
||||
tree_pred = cross_val_predict(tree_model, X, y, cv=5)
|
||||
|
||||
print("\n=== Confusion Matrices ===")
|
||||
print("\nKNN")
|
||||
print(confusion_matrix(y, knn_pred))
|
||||
|
||||
print("\nLogistic Regression")
|
||||
print(confusion_matrix(y, logreg_pred))
|
||||
|
||||
print("\nDecision Tree")
|
||||
print(confusion_matrix(y, tree_pred))
|
||||
|
||||
print("\n=== Classification Reports ===")
|
||||
print("\nKNN")
|
||||
print(classification_report(y, knn_pred))
|
||||
|
||||
print("\nLogistic Regression")
|
||||
print(classification_report(y, logreg_pred))
|
||||
|
||||
print("\nDecision Tree")
|
||||
print(classification_report(y, tree_pred))
|
||||
|
||||
###########################################
|
||||
# BLOCK 14: LETS GET THE BEST VALUE FOR K
|
||||
# task: use the k value to recompute the previous KNN model and evaluate the performance
|
||||
##########################################
|
||||
from sklearn.model_selection import cross_val_score
|
||||
import numpy as np
|
||||
|
||||
k_values = range(1, 21)
|
||||
scores = []
|
||||
|
||||
for k in k_values:
|
||||
knn = KNeighborsClassifier(n_neighbors=k)
|
||||
cv_scores = cross_val_score(knn, X, y, cv=5)
|
||||
scores.append(np.mean(cv_scores))
|
||||
|
||||
best_k = k_values[np.argmax(scores)]
|
||||
|
||||
print("Best k:", best_k)
|
||||
print("Best CV Accuracy:", max(scores))
|
||||
|
||||
4
Classwork Assignment/phrase.txt
Normal file
4
Classwork Assignment/phrase.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
When IN the course
|
||||
of human events IN
|
||||
the space of one
|
||||
place IN time IN memory
|
||||
4
Classwork Assignment/phrase.txt.bak
Normal file
4
Classwork Assignment/phrase.txt.bak
Normal file
@@ -0,0 +1,4 @@
|
||||
When in the course
|
||||
of human events in
|
||||
the space of one
|
||||
place in time in memory
|
||||
56
HW 4B/HW4.py
Normal file
56
HW 4B/HW4.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import requests
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
|
||||
|
||||
def printQuake(properties):
|
||||
magnitude = properties["mag"]
|
||||
location = properties["place"]
|
||||
timestamp = properties["time"] / 1000
|
||||
|
||||
time_str = time.strftime("%H:%M:%S", time.gmtime(timestamp))
|
||||
date_str = time.strftime("%a, %d %b %Y", time.gmtime(timestamp))
|
||||
|
||||
print(f"At {time_str} on {date_str}: earthquake of magnitude {magnitude} at {location}")
|
||||
|
||||
|
||||
def fetchAndPrintQuakes(start_date, end_date, min_magnitude):
|
||||
url = "https://earthquake.usgs.gov/fdsnws/event/1/query"
|
||||
|
||||
params = {
|
||||
"method": "query",
|
||||
"format": "geojson",
|
||||
"starttime": start_date,
|
||||
"endtime": end_date,
|
||||
"minmagnitude": min_magnitude
|
||||
}
|
||||
|
||||
response = requests.get(url, params=params)
|
||||
data = response.json()
|
||||
|
||||
for quake in data["features"]:
|
||||
printQuake(quake["properties"])
|
||||
|
||||
|
||||
def readAndPrintQuakes(filename):
|
||||
script_dir = os.path.dirname(__file__)
|
||||
filepath = os.path.join(script_dir, filename)
|
||||
|
||||
with open(filepath, "r") as f:
|
||||
data = json.load(f)
|
||||
|
||||
for quake in data["features"]:
|
||||
printQuake(quake["properties"])
|
||||
|
||||
|
||||
def main():
|
||||
print("Earthquakes from API:")
|
||||
fetchAndPrintQuakes("2023-10-01", "2023-10-03", 5.0)
|
||||
|
||||
print("\nEarthquakes from saved JSON:")
|
||||
readAndPrintQuakes("load.json")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
7
HW 4B/load.json
Normal file
7
HW 4B/load.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{"type":"FeatureCollection","metadata":{"generated":1774984347000,"url":"https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&minmagnitude=5.4&starttime=2025-09-25&endtime=2025-09-30","title":"USGS Earthquakes","status":200,"api":"2.4.0","count":7},"features":[{"type":"Feature","properties":{"mag":5.5,"place":"89 km E of Petropavlovsk-Kamchatsky, Russia","time":1759183643711,"updated":1765489240040,"tz":null,"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000rdnq","detail":"https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us6000rdnq&format=geojson","felt":1,"cdi":3.8,"mmi":4.454,"alert":"green","status":"reviewed","tsunami":0,"sig":466,"net":"us","code":"6000rdnq","ids":",us6000rdnq,usauto6000rdnq,pt25272000,","sources":",us,usauto,pt,","types":",dyfi,internal-moment-tensor,internal-origin,losspager,moment-tensor,origin,phase-data,shakemap,","nst":101,"dmin":0.785,"rms":0.84,"gap":60,"magType":"mww","type":"earthquake","title":"M 5.5 - 89 km E of Petropavlovsk-Kamchatsky, Russia"},"geometry":{"type":"Point","coordinates":[159.9446,52.9637,42]},"id":"us6000rdnq"},
|
||||
{"type":"Feature","properties":{"mag":5.5,"place":"south of the Fiji Islands","time":1759049581242,"updated":1765489239040,"tz":null,"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000rdex","detail":"https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us6000rdex&format=geojson","felt":null,"cdi":null,"mmi":1,"alert":"green","status":"reviewed","tsunami":0,"sig":465,"net":"us","code":"6000rdex","ids":",usauto6000rdex,us6000rdex,","sources":",usauto,us,","types":",internal-moment-tensor,losspager,moment-tensor,origin,phase-data,shakemap,","nst":58,"dmin":6.142,"rms":0.94,"gap":71,"magType":"mww","type":"earthquake","title":"M 5.5 - south of the Fiji Islands"},"geometry":{"type":"Point","coordinates":[178.8114,-23.8765,573.583]},"id":"us6000rdex"},
|
||||
{"type":"Feature","properties":{"mag":5.5,"place":"90 km WNW of Sola, Vanuatu","time":1758960648598,"updated":1765489241040,"tz":null,"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000rdan","detail":"https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us6000rdan&format=geojson","felt":null,"cdi":null,"mmi":4.159,"alert":"green","status":"reviewed","tsunami":0,"sig":465,"net":"us","code":"6000rdan","ids":",usauto6000rdan,us6000rdan,","sources":",usauto,us,","types":",internal-moment-tensor,losspager,moment-tensor,origin,phase-data,shakemap,","nst":142,"dmin":7.205,"rms":0.81,"gap":50,"magType":"mww","type":"earthquake","title":"M 5.5 - 90 km WNW of Sola, Vanuatu"},"geometry":{"type":"Point","coordinates":[166.7322,-13.6974,33]},"id":"us6000rdan"},
|
||||
{"type":"Feature","properties":{"mag":5.9,"place":"239 km W of Bandon, Oregon","time":1758869128067,"updated":1774594539969,"tz":null,"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000rd1w","detail":"https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us6000rd1w&format=geojson","felt":29,"cdi":2.5,"mmi":0,"alert":"green","status":"reviewed","tsunami":1,"sig":543,"net":"us","code":"6000rd1w","ids":",at00t36o3y,us6000rd1w,usauto6000rd1w,pt25269000,","sources":",at,us,usauto,pt,","types":",dyfi,event-sequence,impact-link,internal-moment-tensor,internal-origin,losspager,moment-tensor,oaf,origin,phase-data,shakemap,","nst":85,"dmin":2.395,"rms":0.81,"gap":167,"magType":"mww","type":"earthquake","title":"M 5.9 - 239 km W of Bandon, Oregon"},"geometry":{"type":"Point","coordinates":[-127.3203,43.4524,10]},"id":"us6000rd1w"},
|
||||
{"type":"Feature","properties":{"mag":5.4,"place":"72 km SSW of Isangel, Vanuatu","time":1758842212037,"updated":1765489243040,"tz":null,"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000rcyv","detail":"https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us6000rcyv&format=geojson","felt":null,"cdi":null,"mmi":3.885,"alert":"green","status":"reviewed","tsunami":0,"sig":449,"net":"us","code":"6000rcyv","ids":",usauto6000rcyv,us6000rcyv,","sources":",usauto,us,","types":",internal-moment-tensor,losspager,moment-tensor,origin,phase-data,shakemap,","nst":48,"dmin":2.873,"rms":0.75,"gap":67,"magType":"mww","type":"earthquake","title":"M 5.4 - 72 km SSW of Isangel, Vanuatu"},"geometry":{"type":"Point","coordinates":[169.0959,-20.1733,49.94]},"id":"us6000rcyv"},
|
||||
{"type":"Feature","properties":{"mag":5.7,"place":"183 km SSW of Emiliano Zapata, Mexico","time":1758795384902,"updated":1765489238040,"tz":null,"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000rcsb","detail":"https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us6000rcsb&format=geojson","felt":0,"cdi":1,"mmi":3.513,"alert":"green","status":"reviewed","tsunami":0,"sig":500,"net":"us","code":"6000rcsb","ids":",us6000rcsb,usauto6000rcsb,pt25268001,","sources":",us,usauto,pt,","types":",dyfi,internal-moment-tensor,internal-origin,losspager,moment-tensor,origin,phase-data,shakemap,","nst":82,"dmin":2.375,"rms":1,"gap":118,"magType":"mww","type":"earthquake","title":"M 5.7 - 183 km SSW of Emiliano Zapata, Mexico"},"geometry":{"type":"Point","coordinates":[-105.8786,17.9793,10]},"id":"us6000rcsb"},
|
||||
{"type":"Feature","properties":{"mag":6.3,"place":"25 km ENE of Mene Grande, Venezuela","time":1758772299565,"updated":1765489239040,"tz":null,"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000rcqw","detail":"https://earthquake.usgs.gov/fdsnws/event/1/query?eventid=us6000rcqw&format=geojson","felt":224,"cdi":5.2,"mmi":7.744,"alert":"yellow","status":"reviewed","tsunami":1,"sig":766,"net":"us","code":"6000rcqw","ids":",pt25268000,us6000rcqw,at00t34le6,usauto6000rcqw,","sources":",pt,us,at,usauto,","types":",dyfi,ground-failure,impact-link,impact-text,internal-moment-tensor,internal-origin,losspager,moment-tensor,origin,phase-data,shakemap,","nst":113,"dmin":1.048,"rms":0.94,"gap":27,"magType":"mww","type":"earthquake","title":"M 6.3 - 25 km ENE of Mene Grande, Venezuela"},"geometry":{"type":"Point","coordinates":[-70.7081,9.9355,14]},"id":"us6000rcqw"}],"bbox":[-127.3203,-23.8765,10,178.8114,52.9637,573.583]}
|
||||
BIN
HW 5/Ben Adovasio HW 5.pdf
Normal file
BIN
HW 5/Ben Adovasio HW 5.pdf
Normal file
Binary file not shown.
764
HW 5/Final_HW5.py
Normal file
764
HW 5/Final_HW5.py
Normal file
@@ -0,0 +1,764 @@
|
||||
# %%
|
||||
############################
|
||||
# BLOCK 1: IMPORTS
|
||||
############################
|
||||
|
||||
# libraries!
|
||||
import numpy as np # numpy is Python's "array" library
|
||||
import pandas as pd # Pandas is Python's "data" library ("dataframe" == spreadsheet)
|
||||
|
||||
# %%
|
||||
|
||||
|
||||
# %%
|
||||
#############################
|
||||
# BLOCK 2: VARIABLES LISTING
|
||||
#############################
|
||||
|
||||
# for reference, as you work throughout, come back and list all the variable names
|
||||
# here along with what that variable holds
|
||||
|
||||
# Variable: Contents
|
||||
# -------------------
|
||||
# [FILL IN VARS BELOW]
|
||||
#
|
||||
|
||||
# %%
|
||||
####################################
|
||||
#from sklearn.datasets import load_iris
|
||||
#data = load_iris()
|
||||
#df = pd.DataFrame(data.data, columns=data.feature_names)
|
||||
#df
|
||||
|
||||
# %%
|
||||
#############################
|
||||
# BLOCK 3: READING DATA
|
||||
#############################
|
||||
|
||||
# let's read in our flower data...
|
||||
#
|
||||
filename = 'iris.csv'
|
||||
df = pd.read_csv(filename, header=0) # encoding="latin1" et al.
|
||||
print(f"{filename}: file read into a pandas DataFrame.")
|
||||
df.head()
|
||||
|
||||
# %%
|
||||
#############################
|
||||
# BLOCK 4: SETTING OPTIONS
|
||||
#############################
|
||||
|
||||
#
|
||||
# a dataframe is a "spreadsheet in Python"
|
||||
# (this one seems to have an extra column!)
|
||||
#
|
||||
pd.set_option('display.max_rows', 8) # None for no limit; default: 10
|
||||
pd.set_option('display.min_rows', 8) # None for no limit; default: 10
|
||||
# let's view it!
|
||||
df
|
||||
|
||||
# %%
|
||||
##############################
|
||||
# BLOCK 5: USING DF'S .info()
|
||||
##############################
|
||||
|
||||
#
|
||||
# let's look at our pandas DataFrame's info (Aargh: that extra column!)
|
||||
#
|
||||
df.info()
|
||||
|
||||
# %%
|
||||
#############################
|
||||
# BLOCK 6: CLEANING DATA
|
||||
#############################
|
||||
|
||||
#
|
||||
# let's drop that last column (dropping is usually by _name_):
|
||||
#
|
||||
# if you want a list of the column names use df.columns
|
||||
#col5name = df.columns[5] # get column name at index 5
|
||||
|
||||
df_clean = df.drop(columns=['junk']) # drop by name is typical, but what else is possible?
|
||||
df_clean.info() # Is the bad last column gone?
|
||||
|
||||
# %%
|
||||
##############################
|
||||
# BLOCK 7: FEATURE NAMES DICT
|
||||
##############################
|
||||
|
||||
#
|
||||
# let's keep our column names in variables, for reference;
|
||||
# in machine learning contexts, these are referred to as "features"
|
||||
#
|
||||
features = df_clean.columns # "list" of columns
|
||||
print(f"FEATURES: {features}\n")
|
||||
# It's a "pandas" list, called an Index
|
||||
# use it just as a Python list of strings:
|
||||
print(f"First feature: {features[0]}\n")
|
||||
|
||||
# let's create a dictionary to look up any column index by name
|
||||
feature_name_to_index = {}
|
||||
for i, name in enumerate(features):
|
||||
feature_name_to_index[name] = i # using the name (as key), assign the value (i)
|
||||
print(f"feature_name_to_index: {feature_name_to_index}")
|
||||
|
||||
# %%
|
||||
##############################
|
||||
# BLOCK 8: INSPECTING DATA
|
||||
##############################
|
||||
|
||||
#
|
||||
# let's look at our cleaned-up dataframe...
|
||||
#
|
||||
df_clean.info()
|
||||
print('=' * 70)
|
||||
|
||||
#
|
||||
# Notice that the non-null count is _different_ for irisname!
|
||||
# Why? Show a table and inspect...
|
||||
print(df_clean)
|
||||
print('=' * 70)
|
||||
|
||||
# or more to the point, grab that column and inspect:
|
||||
print(f"Irisname entries: {df_clean['irisname'].unique()}")
|
||||
|
||||
# also note how the last two rows in the df have problems, among others...
|
||||
|
||||
|
||||
# %%
|
||||
df.columns
|
||||
|
||||
# %%
|
||||
##############################
|
||||
# BLOCK 9: USING DF'S dropna
|
||||
##############################
|
||||
|
||||
#
|
||||
# typically, after dropping columns that we don't want,
|
||||
# we drop rows with missing data (other approaches are possible, too)
|
||||
#
|
||||
df_clean = df_clean.dropna() # this removes all rows with nan items
|
||||
df_clean.info()
|
||||
print('=' * 70)
|
||||
df_clean
|
||||
|
||||
#
|
||||
# notice that _all_ of the rows now have 144 non-null items
|
||||
# also, the first and last rows (among others) aren't valid data...
|
||||
# we'll handle that next
|
||||
|
||||
# %%
|
||||
################################
|
||||
# BLOCK 10: REMOVING BOGUS DATA
|
||||
################################
|
||||
|
||||
# or more to the point, grab that column and inspect:
|
||||
print(f"Irisname entries: {df_clean['irisname'].unique()}")
|
||||
print(df_clean['irisname'] == 'alieniris') # what does this show?
|
||||
print(df_clean['irisname'] != 'alieniris') # what does this show?
|
||||
|
||||
# define a final version of the DataFrame by pulling out the
|
||||
# bad alieniris data (remember that you can pass a boolean
|
||||
# Series to select data that you want)
|
||||
df_final = df_clean[df_clean['irisname'] != 'alieniris'].copy()
|
||||
# ^^^^ YOU NEED TO WRITE CODE HERE...
|
||||
|
||||
print(df_final.shape)
|
||||
df_final
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 11: CONVERT SPECIES NAME TO INDEX
|
||||
##########################################
|
||||
|
||||
# all of scikit-learn's ML routines need numbers, not strings
|
||||
# ... even for categories/classifications (like species!)
|
||||
# so, we will convert the flower-species to numbers:
|
||||
|
||||
species_names = df_final['irisname'].unique()
|
||||
species_name_to_index = { species_names[i]:i for i in range(len(species_names))}
|
||||
print(species_name_to_index)
|
||||
print(type(species_name_to_index))
|
||||
|
||||
def convertSpecies(species_name: str) -> int:
|
||||
''' return the species index (a unique integer/category) '''
|
||||
#print(f"converting {species_name}...")
|
||||
return species_name_to_index[species_name]
|
||||
|
||||
# Let's try it out...
|
||||
for name in species_names:
|
||||
print(f"{name} maps to {convertSpecies(name)}")
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 12: USING DF'S .apply
|
||||
##########################################
|
||||
|
||||
#
|
||||
# we can "apply" our new convertSpecies function to a whole column
|
||||
#
|
||||
# (The following will issue a "SettingWithCopyWarning" here...)
|
||||
# see https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
|
||||
#
|
||||
# >>> ADD CODE HERE TO KEEP THE WARNING FROM HAPPENING <<<
|
||||
|
||||
df_final.loc[:, 'irisname'] = df_final['irisname'].apply(convertSpecies)
|
||||
#df_final.loc[:, 'irisname'] = df_final['irisname'].apply(convertSpecies)
|
||||
# Don't run this twice! Why?! What's "KeyError: 0"?
|
||||
# (of course, you can always go back and re-establish definitions of df_final)
|
||||
|
||||
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 13: CONFIRMING FINAL DATAFRAME
|
||||
##########################################
|
||||
|
||||
#
|
||||
# let's see it! (this is safe to run many times...)
|
||||
#
|
||||
df_final # print(df_final.tostring()) # for _all_ rows...
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 14: CONVERTING TO NUMPY FORMAT
|
||||
##########################################
|
||||
|
||||
#
|
||||
# let's convert our dataframe to a numpy array, named A
|
||||
# Our ML library, scikit-learn operates entirely on numpy arrays.
|
||||
#
|
||||
#A = df_final.values
|
||||
A = df_final.to_numpy() # better -- self-documenting!
|
||||
|
||||
print(f"type of A: {type(A)}")
|
||||
print(df_final.head())
|
||||
print(f"A[0] = {A[0]}")
|
||||
|
||||
# %%
|
||||
##################################################
|
||||
# BLOCK 15: CONVERTING NUMPY ARRAY TO ALL FLOATS
|
||||
##################################################
|
||||
|
||||
#
|
||||
# let's convert to make sure it's all floating-point, so we can multiply and divide
|
||||
#
|
||||
A = A.astype('float64') # so many: www.tutorialspoint.com/numpy/numpy_data_types.htm
|
||||
A
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 16: USING NUMPY'S .shape
|
||||
##########################################
|
||||
|
||||
#
|
||||
# nice to have num_rows and num_cols variables handy...
|
||||
#
|
||||
num_rows, num_cols = A.shape
|
||||
print(f"\nThe dataset has {num_rows} rows and {num_cols} cols")
|
||||
print(A)
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 17: PRINTING FLOWER INFO
|
||||
##########################################
|
||||
|
||||
# let's use all of our previously-defined variables, to reinforce names...
|
||||
|
||||
# choose a row index (particular flower) arbitrarily:
|
||||
flower = 132
|
||||
print(f"flower #{flower} data is {A[flower]}")
|
||||
|
||||
for i in range(len(features)):
|
||||
col_name = features[i]
|
||||
if col_name != 'irisname':
|
||||
print(f" Its {col_name} is {A[flower][i]}")
|
||||
else:
|
||||
species_num = int(A[flower][i])
|
||||
species_name = species_names[species_num]
|
||||
print(f" Its {col_name} is {species_name} ({species_num})")
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 18: WRITING OUR OWN 1-NN FUNCTION
|
||||
##########################################
|
||||
|
||||
#
|
||||
# We don't have to use scikit-learn to implement NN!
|
||||
#
|
||||
|
||||
#
|
||||
# data-driven predictive model (1-nearest-neighbor)
|
||||
#
|
||||
|
||||
# Python functions are first-class objects!
|
||||
dist = np.linalg.norm # built in to numpy... but what does norm do?
|
||||
|
||||
num_rows, num_cols = A.shape # data size
|
||||
|
||||
def predictiveModel( features: list[float] ) -> str:
|
||||
""" input: a list of four features
|
||||
[ sepallen, sepalwid, petallen, petalwid ]
|
||||
output: the predicted species of iris, from
|
||||
setosa (0), versicolor (1), virginica (2)
|
||||
"""
|
||||
our_features = np.asarray(features) # make a numpy array
|
||||
|
||||
closest_flower = A[0]
|
||||
closest_features = A[0,0:4]
|
||||
closest_distance = dist(our_features - closest_features)
|
||||
|
||||
for i in range(1, num_rows, 1):
|
||||
current_flower = A[i]
|
||||
current_features = A[i,0:4]
|
||||
current_distance = dist(our_features - current_features)
|
||||
|
||||
if current_distance < closest_distance:
|
||||
closest_distance = current_distance # remember closest!
|
||||
closest_flower = current_flower
|
||||
|
||||
# done comparing with every flower in the dataset
|
||||
predicted_species = int(round(closest_flower[4])) # what type is closest_flower?
|
||||
name = species_names[predicted_species]
|
||||
return f"{name} ({predicted_species})"
|
||||
|
||||
#
|
||||
# Try it!
|
||||
#
|
||||
# features = eval(input("Enter new features: "))
|
||||
#
|
||||
features = [ 4.6, 3.6, 3.0, 1.2 ]
|
||||
result = predictiveModel( features )
|
||||
print(f"I predict {result} from features {features}")
|
||||
|
||||
# %%
|
||||
##########################################
|
||||
# BLOCK 19: COMMENTS ON SCIKIT-LEARN kNN
|
||||
##########################################
|
||||
|
||||
#
|
||||
# but, we don't have to write our own ... because
|
||||
#
|
||||
# we want knn for any k (not just k=1 as above)
|
||||
# we want an already-debugged algorithm!
|
||||
# we want to ask iris-related questions instead of implementation ones...
|
||||
#
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 20: DEFINIING FEATURES & LABELS FOR kNN
|
||||
################################################
|
||||
|
||||
print("+++ Start of data definitions +++\n")
|
||||
|
||||
X_all = A[:,0:4] # X (features) ... is all rows, columns 0, 1, 2, 3
|
||||
y_all = A[:,4] # y (labels) ... is all rows, column 4 only
|
||||
# (look back at slide 20)
|
||||
print(f"X_all (just features) is \n {X_all}")
|
||||
print(f"y_all (just labels) is \n {y_all}")
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 21: REWEIGHTING FEATURES
|
||||
################################################
|
||||
|
||||
#
|
||||
# we can re-weight different features here...
|
||||
#
|
||||
|
||||
col_weights = { # could be called feature weight...
|
||||
'sepallen':1.0,
|
||||
'sepalwid':1.0,
|
||||
'petallen':1.0,
|
||||
'petalwid':1.0,
|
||||
}
|
||||
|
||||
for col_name in col_weights:
|
||||
i = feature_name_to_index[col_name] # get the column index, i, of the column name
|
||||
weight = col_weights[col_name] # from the dictionary above
|
||||
print(f"Weighting {col_name} by {weight}")
|
||||
# weighting == "multiplying"
|
||||
X_all[:,i] *= weight # multiply by the weight to give this column ("feature")
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 22: PERMUTING THE DATA
|
||||
################################################
|
||||
|
||||
#
|
||||
#
|
||||
# we scramble the data, to give a different TRAIN/TEST split each time...
|
||||
#
|
||||
indices = np.random.permutation(len(y_all)) # indices is a permutation-list
|
||||
|
||||
# we scramble both X and y, necessarily with the same permutation
|
||||
X_labeled = X_all[indices] # we apply the _same_ permutation to each!
|
||||
y_labeled = y_all[indices] # again...
|
||||
print(X_labeled) # note that X_labeled and y_labeled are permuted identically
|
||||
print(y_labeled)
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 23: DEFINING TRAIN VS TEST SETS
|
||||
################################################
|
||||
|
||||
#
|
||||
# We next separate into test data and training data ...
|
||||
# + We will train on the training data...
|
||||
# + We will _not_ look at the testing data when building the model
|
||||
#
|
||||
# Then, afterward, we will test on the testing data -- and see how well we do!
|
||||
#
|
||||
|
||||
#
|
||||
# a common convention: train on 80%, test on 20% Let's define the TEST_PERCENT
|
||||
#
|
||||
num_rows = X_labeled.shape[0] # the number of labeled rows
|
||||
test_percent = 0.20
|
||||
test_size = int(test_percent * num_rows) # no harm in rounding down
|
||||
|
||||
X_test = X_labeled[:test_size] # first section are for testing
|
||||
y_test = y_labeled[:test_size]
|
||||
|
||||
X_train = X_labeled[test_size:] # all the rest are for training
|
||||
y_train = y_labeled[test_size:]
|
||||
|
||||
num_train_rows = len(y_train)
|
||||
num_test_rows = len(y_test)
|
||||
print(f"total rows: {num_rows}; training with {num_train_rows} rows; testing with {num_test_rows} rows" )
|
||||
print(f"\t(sanity check: {num_train_rows} + {num_test_rows} = {num_train_rows + num_test_rows})")
|
||||
|
||||
# %%
|
||||
#######################################################
|
||||
# BLOCK 24: FIRST ATTEMPT TO BUILD & TRAIN A kNN MODEL
|
||||
#######################################################
|
||||
|
||||
#
|
||||
# +++ This is the "Model-building and Model-training Cell"
|
||||
#
|
||||
# Create a kNN model and train it!
|
||||
#
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
|
||||
k = 84 # we don't know what k to use, so we guess for now! (this will _not_ be a good value)
|
||||
knn_model = KNeighborsClassifier(n_neighbors = k) # here, k is the "k" in kNN
|
||||
|
||||
# we train the model (it's one line!)
|
||||
knn_model.fit(X_train, y_train) # yay! trained!
|
||||
print("Created and trained a knn classifier with k =", k)
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 25: TEST THE kNN MODEL
|
||||
################################################
|
||||
|
||||
#
|
||||
# +++ This is the "Model-testing Cell"
|
||||
#
|
||||
# Now, let's see how well we did on our "held-out data" (the testing data)
|
||||
#
|
||||
|
||||
# We run our test set!
|
||||
predicted_labels = knn_model.predict(X_test)
|
||||
actual_labels = y_test
|
||||
|
||||
# Let's print them so we can compare...
|
||||
print("Predicted labels:", predicted_labels)
|
||||
print("Actual labels :", actual_labels)
|
||||
|
||||
# And, some overall results
|
||||
num_correct = sum(predicted_labels == actual_labels)
|
||||
total = len(actual_labels)
|
||||
print(f"\nResults on test set: {num_correct} correct out of {total} total.")
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 26: PRETTY-PRINT PREDICTED LABELS
|
||||
################################################
|
||||
|
||||
#
|
||||
# Let's print these more helpfully, in a vertical table
|
||||
#
|
||||
|
||||
def compareLabels(predicted_labels: np.ndarray, actual_labels: np.ndarray) -> int:
|
||||
''' a more neatly formatted comparison, returning the number correct '''
|
||||
num_labels = len(predicted_labels)
|
||||
num_correct = 0
|
||||
|
||||
for i in range(num_labels):
|
||||
predicted = int(round(predicted_labels[i])) # round-to-int protects from float imprecision
|
||||
actual = int(round(actual_labels[i]))
|
||||
result = "incorrect"
|
||||
if predicted == actual: # if they match,
|
||||
result = "" # no longer incorrect
|
||||
num_correct += 1 # and we count a match!
|
||||
|
||||
# note the justification formatting:
|
||||
# :>3d right justifies integers (d) to width 3
|
||||
# :<12s left justifies strings (s) to width 12
|
||||
print(f"row {i:>3d} : ", end = "")
|
||||
print(f"{species_names[predicted]:>12s} ", end = "")
|
||||
print(f"{species_names[actual]:<12s} {result}")
|
||||
|
||||
print()
|
||||
print(f"Correct: {num_correct} out of {num_labels}")
|
||||
return num_correct
|
||||
|
||||
#
|
||||
# let's try it out!
|
||||
#
|
||||
|
||||
compareLabels(predicted_labels,actual_labels)
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 27: USE THE FIRST-ATTEMPT kNN MODEL
|
||||
################################################
|
||||
|
||||
#
|
||||
# Ok! We have our knn model, we could just use it...
|
||||
#
|
||||
|
||||
#
|
||||
# data-driven predictive model (k-nearest-neighbor), using scikit-learn
|
||||
#
|
||||
|
||||
def predictiveModel( features: list[float] ) -> str:
|
||||
''' input: a list of four features
|
||||
[ sepallen, sepalwid, petallen, petalwid ]
|
||||
output: the predicted species of iris, from
|
||||
setosa (0), versicolor (1), virginica (2)
|
||||
'''
|
||||
our_features = np.asarray([features]) # extra brackets needed
|
||||
predicted_species = knn_model.predict(our_features)
|
||||
print(f"predicted_species = {predicted_species}")
|
||||
|
||||
predicted_species = int(round(predicted_species[0])) # unpack one element
|
||||
name = species_names[predicted_species]
|
||||
return f"{name} ({predicted_species})"
|
||||
|
||||
#
|
||||
# Try it!
|
||||
#
|
||||
# features = eval(input("Enter new features: "))
|
||||
#
|
||||
features = [6.7,3.3,5.7,2.1] # [5.8,2.7,4.1,1.0] [4.6,3.6,3.0,2.2] [6.7,3.3,5.7,2.1]
|
||||
result = predictiveModel( features )
|
||||
print(f"I predict {result} from features {features}")
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 28: COMMENTS ON CHOICE OF BEST k
|
||||
################################################
|
||||
|
||||
#
|
||||
# Except, we didn't really explore whether this was the BEST model we could build!
|
||||
#
|
||||
#
|
||||
# We used k = 84 (a neighborhood size of 84 flowers)
|
||||
# In a dataset of only 140ish flowers, with three species, this seems like a bad idea!
|
||||
#
|
||||
# Perhaps we should try ALL the neighborhood sizes in their own TRAIN/TEST split
|
||||
# and see which neighborhood size works the best, for irises, at least...
|
||||
#
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 29: USING CROSS VALIDATION
|
||||
################################################
|
||||
|
||||
#
|
||||
# to do this, we use "cross validation"
|
||||
# (see slide 45)
|
||||
#
|
||||
|
||||
import seaborn as sns
|
||||
import matplotlib.pyplot as plt
|
||||
from sklearn.model_selection import cross_val_score
|
||||
|
||||
#
|
||||
# cross-validation splits the training set into two pieces:
|
||||
# + model-building and model-validation. We'll use "build" and "validate"
|
||||
#
|
||||
|
||||
max_k = 85
|
||||
all_accuracies = []
|
||||
best_k = 1
|
||||
best_accuracy = -1
|
||||
|
||||
for k in range(1, max_k, 1):
|
||||
knn_cv_model = KNeighborsClassifier(n_neighbors=k)
|
||||
cv_scores = cross_val_score(knn_cv_model, X_train, y_train, cv=5)
|
||||
this_cv_accuracy = cv_scores.mean()
|
||||
print(f"k: {k:2d} cv accuracy: {this_cv_accuracy:7.4f}")
|
||||
all_accuracies.append(this_cv_accuracy)
|
||||
if this_cv_accuracy > best_accuracy:
|
||||
best_accuracy = this_cv_accuracy
|
||||
best_k = k
|
||||
# assign best value of k to best_k
|
||||
#best_k = k # *** AT THE MOMENT THIS IS INCORRECT ***
|
||||
# you'll need to modify the loop above to find and remember the real best_k
|
||||
|
||||
print(f"best_k = {best_k} yields the highest average cv accuracy.") # print the best one
|
||||
|
||||
plt.figure(figsize=(10, 6))
|
||||
sns.lineplot(x=range(1,len(all_accuracies)+1), y=all_accuracies)
|
||||
plt.xlabel("k value (index)")
|
||||
plt.ylabel("Cross-validated accuracy")
|
||||
plt.title("kNN Accuracy vs k Value")
|
||||
plt.show()
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 30: RE-BUILD & RE-TRAIN USING BEST k
|
||||
################################################
|
||||
|
||||
#
|
||||
# Now, we re-create and re-run the "Model-building and -training Cell"
|
||||
#
|
||||
# Now, using best_k instead of the original, randomly-guessed value How does it do?!
|
||||
#
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
knn_model_tuned = KNeighborsClassifier(n_neighbors = best_k) # here, we use the best_k
|
||||
|
||||
# we train the model (one line!)
|
||||
knn_model_tuned.fit(X_train, y_train) # yay! trained!
|
||||
print(f"Created + trained a knn classifier, now tuned with a (best) k of {best_k}")
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 31: RE-TEST THE BEST-k MODEL
|
||||
################################################
|
||||
|
||||
#
|
||||
# Re-create and re-run the "Model-testing Cell" How does it do with best_k?!
|
||||
#
|
||||
predicted_labels = knn_model_tuned.predict(X_test)
|
||||
actual_labels = y_test
|
||||
|
||||
# Let's print them so we can compare...
|
||||
print("Predicted labels:", predicted_labels)
|
||||
print("Actual labels:", actual_labels)
|
||||
print()
|
||||
# and, we'll print our nicer table...
|
||||
compareLabels(predicted_labels,actual_labels)
|
||||
|
||||
# %%
|
||||
################################################
|
||||
# BLOCK 32: TRYING DIFFERENT PERMUTATIONS
|
||||
################################################
|
||||
|
||||
#
|
||||
# Before moving on, go back and choose a new permutation to give
|
||||
# new testing and training sets, and go back through the steps
|
||||
# for identifying the "best" k (starting at Block 22 and re-doing
|
||||
# up through Block 31).
|
||||
#
|
||||
# Repeat this several times.
|
||||
# Do you get the same value for k each time? Why or why not?
|
||||
#
|
||||
|
||||
# %%
|
||||
####################################################
|
||||
# BLOCK 33: REBUILD & TRAIN USING BEST k & ALL DATA
|
||||
####################################################
|
||||
|
||||
# Ok! Now we have tuned knn to use the "best" value of k...
|
||||
#
|
||||
# And, we should really use ALL available data to train our final predictive model
|
||||
# (not split into test and train as before)
|
||||
#
|
||||
|
||||
knn_model_final = KNeighborsClassifier(n_neighbors=best_k) # here, we use the best_k
|
||||
knn_model_final.fit(X_all, y_all) # yay! trained!
|
||||
print(f"Created + trained a 'final' knn classifier, with a (best) k of {best_k}")
|
||||
|
||||
# %%
|
||||
####################################################
|
||||
# BLOCK 34: TRYING FINAL MODEL "IN THE WILD"
|
||||
####################################################
|
||||
|
||||
#
|
||||
# final predictive model (k-nearest-neighbor), with tuned k + ALL data incorporated
|
||||
#
|
||||
|
||||
def predictiveModel( features: list[float] ) -> str:
|
||||
''' input: a list of four features
|
||||
[ sepallen, sepalwid, petallen, petalwid ]
|
||||
output: the predicted species of iris, from
|
||||
setosa (0), versicolor (1), virginica (2)
|
||||
'''
|
||||
our_features = np.asarray([features]) # extra brackets needed
|
||||
predicted_species = knn_model_final.predict(our_features)
|
||||
|
||||
predicted_species = int(round(predicted_species[0])) # unpack one element
|
||||
name = species_names[predicted_species]
|
||||
return f"{name} ({predicted_species})"
|
||||
|
||||
#
|
||||
# Try it on several!
|
||||
#
|
||||
# features = eval(input("Enter new features: "))
|
||||
#
|
||||
features = [6.7,3.3,5.7,2.1] # [5.8,2.7,4.1,1.0] [4.6,3.6,3.0,2.2] [6.7,3.3,5.7,2.1]
|
||||
result = predictiveModel( features )
|
||||
print(f"I predict {result} from features {features}")
|
||||
|
||||
# %%
|
||||
################################################################
|
||||
# BLOCK 35a: HOW DOES THE MODEL PERFORM ON MEAN OF EACH FLOWER?
|
||||
################################################################
|
||||
|
||||
# let's recall the species names and their order in the list
|
||||
print(species_names)
|
||||
print('=' * 70)
|
||||
|
||||
# and let's recall what the final DataFrame looks like, noting that
|
||||
# the irisname was converted to the corresponding index in species_names
|
||||
print(df_final)
|
||||
|
||||
# %%
|
||||
################################################################
|
||||
# BLOCK 35b: HOW DOES THE MODEL PERFORM ON MEAN OF EACH FLOWER?
|
||||
################################################################
|
||||
|
||||
# let's grab the data from df_final corresponding to versicolor
|
||||
versicolor_data = df_final[ df_final['irisname'] == convertSpecies('versicolor') ]
|
||||
print(versicolor_data)
|
||||
print('=' * 70)
|
||||
|
||||
# let's print the mean of each column
|
||||
print(versicolor_data.mean())
|
||||
print('=' * 70)
|
||||
|
||||
# and let's grab the features means only (don't need the label) for versicolor
|
||||
versicolor_features_means = np.asarray(versicolor_data.mean()[:-1])
|
||||
print(versicolor_features_means)
|
||||
|
||||
# now run the predictive model (see Block 34 above) and print a corresponding
|
||||
# message
|
||||
|
||||
# >>> YOU ADD CODE HERE
|
||||
result = predictiveModel(versicolor_features_means)
|
||||
print(f"Mean versicolor features {versicolor_features_means} -> {result}")
|
||||
|
||||
# %%
|
||||
################################################################
|
||||
# BLOCK 35c: HOW DOES THE MODEL PERFORM ON MEAN OF EACH FLOWER?
|
||||
################################################################
|
||||
|
||||
# Automate the process used in Block 35b, across all species:
|
||||
#
|
||||
# Loop across species names, and for each species,
|
||||
# (a) pull that corresponding data from df_final
|
||||
# (b) compute the means of the features, storing as a numpy array
|
||||
# (c) call the predictive model using those features
|
||||
# (d) print a corresponding message
|
||||
|
||||
# >> YOU ADD CODE HERE -- YOU SHOULD NEED NO MORE THAN 5 LINES OF CODE
|
||||
for name in species_names:
|
||||
species_data = df_final[df_final['irisname'] == convertSpecies(name)]
|
||||
species_features_means = np.asarray(species_data.mean()[:-1])
|
||||
result = predictiveModel(species_features_means)
|
||||
print(f"Mean {name} features {species_features_means} -> {result}")
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
6
TextBlob/test.json
Normal file
6
TextBlob/test.json
Normal file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{"text": "The beer was good.", "label": "pos"},
|
||||
{"text": "I do not enjoy my job", "label": "neg"},
|
||||
{"text": "I feel amazing!", "label": "pos"},
|
||||
{"text": "I am very tired", "label": "neg"}
|
||||
]
|
||||
31
TextBlob/text_classifier.py
Normal file
31
TextBlob/text_classifier.py
Normal file
@@ -0,0 +1,31 @@
|
||||
from textblob.classifiers import NaiveBayesClassifier
|
||||
from pathlib import Path
|
||||
|
||||
def main():
|
||||
# Get directory where this script is located
|
||||
base_dir = Path(__file__).parent
|
||||
|
||||
# Build paths to data files
|
||||
train_path = base_dir / "train.json"
|
||||
test_path = base_dir / "test.json"
|
||||
|
||||
# Load training data
|
||||
with open(train_path, "r") as train_file:
|
||||
classifier = NaiveBayesClassifier(train_file, format="json")
|
||||
|
||||
# Load test data
|
||||
with open(test_path, "r") as test_file:
|
||||
accuracy = classifier.accuracy(test_file)
|
||||
|
||||
print("Accuracy:", accuracy)
|
||||
|
||||
print("Classifying sentences:")
|
||||
print("I love this place ->", classifier.classify("I love this place"))
|
||||
print("I hate this job ->", classifier.classify("I hate this job"))
|
||||
|
||||
print("\nMost Informative Features:")
|
||||
classifier.show_informative_features(5)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
12
TextBlob/train.json
Normal file
12
TextBlob/train.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{"text": "I love this sandwich.", "label": "pos"},
|
||||
{"text": "This is an amazing place!", "label": "pos"},
|
||||
{"text": "I feel very good about these beers.", "label": "pos"},
|
||||
{"text": "This is my best work.", "label": "pos"},
|
||||
{"text": "What an awesome view", "label": "pos"},
|
||||
{"text": "I do not like this restaurant", "label": "neg"},
|
||||
{"text": "I am tired of this stuff.", "label": "neg"},
|
||||
{"text": "I can't deal with this", "label": "neg"},
|
||||
{"text": "He is my sworn enemy!", "label": "neg"},
|
||||
{"text": "My boss is horrible.", "label": "neg"}
|
||||
]
|
||||
Reference in New Issue
Block a user