libz 0.5__tar.gz → 0.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. {libz-0.5 → libz-0.7}/PKG-INFO +1 -1
  2. libz-0.7/libz/DL/prac8.py +73 -0
  3. libz-0.7/libz/DL/prac9.py +73 -0
  4. {libz-0.5 → libz-0.7}/libz/DLG/__init__.py +16 -15
  5. libz-0.7/libz/DLG/prac1.py +145 -0
  6. libz-0.7/libz/DLG/prac2.py +180 -0
  7. libz-0.7/libz/DLG/prac3.py +196 -0
  8. libz-0.7/libz/DLG/prac4.py +177 -0
  9. libz-0.7/libz/DLG/prac5.py +269 -0
  10. libz-0.7/libz/DLG/prac6.py +253 -0
  11. libz-0.7/libz/DLG/prac7.py +194 -0
  12. {libz-0.5 → libz-0.7}/libz/__init__.py +4 -1
  13. {libz-0.5 → libz-0.7}/libz/_core.py +10 -3
  14. libz-0.7/libz/_update.py +47 -0
  15. {libz-0.5 → libz-0.7}/libz.egg-info/PKG-INFO +1 -1
  16. {libz-0.5 → libz-0.7}/libz.egg-info/SOURCES.txt +2 -3
  17. {libz-0.5 → libz-0.7}/pyproject.toml +1 -1
  18. libz-0.5/libz/DL/prac8.py +0 -114
  19. libz-0.5/libz/DL/prac9.py +0 -158
  20. libz-0.5/libz/DLG/prac1.py +0 -71
  21. libz-0.5/libz/DLG/prac2.py +0 -108
  22. libz-0.5/libz/DLG/prac3.py +0 -108
  23. libz-0.5/libz/DLG/prac4.py +0 -105
  24. libz-0.5/libz/DLG/prac5.py +0 -99
  25. libz-0.5/libz/DLG/prac6.py +0 -119
  26. libz-0.5/libz/DLG/prac7.py +0 -110
  27. libz-0.5/libz/DLG/prac8.py +0 -141
  28. libz-0.5/libz/DLG/prac9.py +0 -93
  29. {libz-0.5 → libz-0.7}/README.md +0 -0
  30. {libz-0.5 → libz-0.7}/libz/AWT/__init__.py +0 -0
  31. {libz-0.5 → libz-0.7}/libz/AWT/prac1.py +0 -0
  32. {libz-0.5 → libz-0.7}/libz/AWT/prac10.py +0 -0
  33. {libz-0.5 → libz-0.7}/libz/AWT/prac2.py +0 -0
  34. {libz-0.5 → libz-0.7}/libz/AWT/prac3.py +0 -0
  35. {libz-0.5 → libz-0.7}/libz/AWT/prac4.py +0 -0
  36. {libz-0.5 → libz-0.7}/libz/AWT/prac5.py +0 -0
  37. {libz-0.5 → libz-0.7}/libz/AWT/prac6.py +0 -0
  38. {libz-0.5 → libz-0.7}/libz/AWT/prac7.py +0 -0
  39. {libz-0.5 → libz-0.7}/libz/AWT/prac8.py +0 -0
  40. {libz-0.5 → libz-0.7}/libz/AWT/prac9.py +0 -0
  41. {libz-0.5 → libz-0.7}/libz/BDA/__init__.py +0 -0
  42. {libz-0.5 → libz-0.7}/libz/BDA/prac1.py +0 -0
  43. {libz-0.5 → libz-0.7}/libz/BDA/prac10.py +0 -0
  44. {libz-0.5 → libz-0.7}/libz/BDA/prac2.py +0 -0
  45. {libz-0.5 → libz-0.7}/libz/BDA/prac3.py +0 -0
  46. {libz-0.5 → libz-0.7}/libz/BDA/prac4.py +0 -0
  47. {libz-0.5 → libz-0.7}/libz/BDA/prac5.py +0 -0
  48. {libz-0.5 → libz-0.7}/libz/BDA/prac6.py +0 -0
  49. {libz-0.5 → libz-0.7}/libz/BDA/prac7.py +0 -0
  50. {libz-0.5 → libz-0.7}/libz/BDA/prac8.py +0 -0
  51. {libz-0.5 → libz-0.7}/libz/BDA/prac9.py +0 -0
  52. {libz-0.5 → libz-0.7}/libz/BIO/__init__.py +0 -0
  53. {libz-0.5 → libz-0.7}/libz/BIO/prac1.py +0 -0
  54. {libz-0.5 → libz-0.7}/libz/BIO/prac10.py +0 -0
  55. {libz-0.5 → libz-0.7}/libz/BIO/prac2.py +0 -0
  56. {libz-0.5 → libz-0.7}/libz/BIO/prac3.py +0 -0
  57. {libz-0.5 → libz-0.7}/libz/BIO/prac4.py +0 -0
  58. {libz-0.5 → libz-0.7}/libz/BIO/prac5.py +0 -0
  59. {libz-0.5 → libz-0.7}/libz/BIO/prac6.py +0 -0
  60. {libz-0.5 → libz-0.7}/libz/BIO/prac7.py +0 -0
  61. {libz-0.5 → libz-0.7}/libz/BIO/prac8.py +0 -0
  62. {libz-0.5 → libz-0.7}/libz/BIO/prac9.py +0 -0
  63. {libz-0.5 → libz-0.7}/libz/DL/__init__.py +0 -0
  64. {libz-0.5 → libz-0.7}/libz/DL/prac1.py +0 -0
  65. {libz-0.5 → libz-0.7}/libz/DL/prac2.py +0 -0
  66. {libz-0.5 → libz-0.7}/libz/DL/prac3.py +0 -0
  67. {libz-0.5 → libz-0.7}/libz/DL/prac4.py +0 -0
  68. {libz-0.5 → libz-0.7}/libz/DL/prac5.py +0 -0
  69. {libz-0.5 → libz-0.7}/libz/DL/prac6.py +0 -0
  70. {libz-0.5 → libz-0.7}/libz/DL/prac7.py +0 -0
  71. {libz-0.5 → libz-0.7}/libz.egg-info/dependency_links.txt +0 -0
  72. {libz-0.5 → libz-0.7}/libz.egg-info/top_level.txt +0 -0
  73. {libz-0.5 → libz-0.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: libz
3
- Version: 0.5
3
+ Version: 0.7
4
4
  Summary: A lightweight Python utility toolkit.
5
5
  Requires-Python: >=3.7
6
6
  Description-Content-Type: text/markdown
@@ -0,0 +1,73 @@
1
+ # Recursive Neural Networks
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+
8
+ class RecursiveNN(nn.Module):
9
+
10
+ def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes):
11
+ super().__init__()
12
+
13
+ self.embedding = nn.Embedding(vocab_size, embed_dim)
14
+ self.combine = nn.Linear(embed_dim * 2, hidden_dim)
15
+ self.classifier = nn.Linear(hidden_dim, num_classes)
16
+
17
+ def forward(self, tree):
18
+
19
+ # Leaf node
20
+ if isinstance(tree, int):
21
+ return self.embedding(torch.tensor(tree))
22
+
23
+ # Recursive case
24
+ left, right = tree
25
+
26
+ left_vec = self.forward(left)
27
+ right_vec = self.forward(right)
28
+
29
+ combined = torch.cat([left_vec, right_vec])
30
+
31
+ return torch.tanh(self.combine(combined))
32
+
33
+
34
+ # Parameters
35
+ VOCAB_SIZE = 100
36
+ EMBED_DIM = 16
37
+ HIDDEN_DIM = 16
38
+ NUM_CLASSES = 2
39
+
40
+ # Create model
41
+ model = RecursiveNN(
42
+ VOCAB_SIZE,
43
+ EMBED_DIM,
44
+ HIDDEN_DIM,
45
+ NUM_CLASSES
46
+ )
47
+
48
+ # Word IDs
49
+ vocab = {
50
+ "the": 10,
51
+ "movie": 25,
52
+ "was": 4,
53
+ "great": 82
54
+ }
55
+
56
+ # Tree: ((the, movie), (was, great))
57
+ tree = (
58
+ (vocab["the"], vocab["movie"]),
59
+ (vocab["was"], vocab["great"])
60
+ )
61
+
62
+ # Get root vector
63
+ root = model(tree)
64
+
65
+ # Classify root
66
+ logits = model.classifier(root)
67
+
68
+ # Convert scores to probabilities
69
+ probabilities = F.softmax(logits, dim=0)
70
+
71
+ print("Root:", root)
72
+ print("Logits:", logits)
73
+ print("Probabilities:", probabilities)
@@ -0,0 +1,73 @@
1
+ # Linear Factor Models
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.optim as optim
6
+ from sklearn.datasets import make_blobs
7
+ from sklearn.decomposition import PCA
8
+
9
+
10
+ # 1. Create data
11
+ X, _ = make_blobs(
12
+ n_samples=1000,
13
+ n_features=10,
14
+ centers=3,
15
+ random_state=42
16
+ )
17
+
18
+ X = torch.tensor(X, dtype=torch.float32)
19
+
20
+
21
+ # 2. Linear Factor Model using PCA
22
+ pca = PCA(n_components=3)
23
+ factors = pca.fit_transform(X.numpy())
24
+
25
+ print("PCA Variance:", pca.explained_variance_ratio_)
26
+
27
+
28
+ # 3. Linear Autoencoder
29
+ class LinearAutoencoder(nn.Module):
30
+
31
+ def __init__(self, input_dim, factor_dim):
32
+ super().__init__()
33
+
34
+ self.encoder = nn.Linear(input_dim, factor_dim)
35
+ self.decoder = nn.Linear(factor_dim, input_dim)
36
+
37
+ def forward(self, x):
38
+ factors = self.encoder(x)
39
+ output = self.decoder(factors)
40
+
41
+ return output, factors
42
+
43
+
44
+ # 4. Create model
45
+ model = LinearAutoencoder(10, 3)
46
+
47
+ loss_fn = nn.MSELoss()
48
+ optimizer = optim.Adam(model.parameters(), lr=0.01)
49
+
50
+
51
+ # 5. Train model
52
+ for epoch in range(200):
53
+
54
+ optimizer.zero_grad()
55
+
56
+ output, factors = model(X)
57
+
58
+ loss = loss_fn(output, X)
59
+
60
+ loss.backward()
61
+ optimizer.step()
62
+
63
+ if (epoch + 1) % 50 == 0:
64
+ print(
65
+ "Epoch:", epoch + 1,
66
+ "Loss:", loss.item()
67
+ )
68
+
69
+
70
+ # 6. Get factor loading matrix
71
+ W = model.decoder.weight.detach()
72
+
73
+ print("Factor Loading Matrix Shape:", W.shape)
@@ -1,15 +1,16 @@
1
- from libz._core import register
2
-
3
- TITLES = {
4
- 1: "Deep feed forward (any CSV)",
5
- 2: "Regularization and optimization (any CSV)",
6
- 3: "Semi-supervised learning (any text CSV)",
7
- 4: "Multitasking (any CSV)",
8
- 5: "CNN-based handwriting recognition (any image folder / MNIST)",
9
- 6: "CNN - unsupervised feature learning (any image folder / digits)",
10
- 7: "Recurrent neural network (any text CSV / IMDB)",
11
- 8: "Recursive neural network (tree) (any text CSV / sample)",
12
- 9: "PCA vs linear autoencoder (any numeric CSV / synthetic)",
13
- }
14
-
15
- register(__name__, globals(), TITLES)
1
+ from libz._core import register
2
+
3
+ TITLES = {
4
+ 1: "Deep feed forward (any CSV)",
5
+ 2: "Regularization and optimization (any CSV)",
6
+ 3: "Semi-supervised learning (any text CSV)",
7
+ 4: "Multitasking (any CSV)",
8
+ 5: "CNN-based handwriting recognition (any image folder / CSV / MNIST)",
9
+ 6: "CNN - unsupervised feature learning (any image folder / CSV / digits)",
10
+ 7: "Recurrent neural network (any text CSV / IMDB)",
11
+ 8: "Recursive neural network (tree)",
12
+ 9: "PCA vs linear autoencoder",
13
+ }
14
+
15
+ # prac8 and prac9 show the DL code (no dynamic version needed)
16
+ register(__name__, globals(), TITLES, links={8: "DL", 9: "DL"})
@@ -0,0 +1,145 @@
1
+ # Deep Feed Forward Neural Network - works with any CSV classification dataset
2
+ # The target column and the feature columns are picked automatically.
3
+ # If accuracy is low, you are asked which columns to use and the model is retrained.
4
+ # Press Enter to use the built-in Breast Cancer dataset (from scikit-learn, no download).
5
+ import numpy as np
6
+ import pandas as pd
7
+ from sklearn.datasets import load_breast_cancer
8
+ from sklearn.model_selection import train_test_split
9
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
10
+ from sklearn.metrics import classification_report, confusion_matrix
11
+ from tensorflow.keras.models import Sequential
12
+ from tensorflow.keras.layers import Input, Dense, Dropout
13
+ from tensorflow.keras.callbacks import EarlyStopping
14
+
15
+ MIN_ACCURACY = 0.70 # below this you get to choose the columns yourself
16
+ TARGET_NAMES = {"target", "label", "labels", "class", "output", "outcome", "result", "y"}
17
+
18
+
19
+ # ---------- helpers ----------
20
+ def read_csv(path):
21
+ """Read a CSV with any separator (, ; tab |) and encoding."""
22
+ with open(path, encoding="latin-1") as f:
23
+ first_line = f.readline()
24
+ sep = max([",", ";", "\t", "|"], key=first_line.count)
25
+ try:
26
+ df = pd.read_csv(path, sep=sep)
27
+ except UnicodeDecodeError:
28
+ df = pd.read_csv(path, sep=sep, encoding="latin-1")
29
+ df = df.loc[:, ~df.columns.astype(str).str.startswith("Unnamed")]
30
+ return df.dropna(axis=1, how="all")
31
+
32
+
33
+ def is_id(col):
34
+ name = str(col.name).lower()
35
+ return (name in ("id", "index") or name.endswith("_id")
36
+ or (pd.api.types.is_integer_dtype(col) and col.nunique() == len(col)))
37
+
38
+
39
+ def guess_target(df):
40
+ for c in df.columns:
41
+ if str(c).lower() in TARGET_NAMES:
42
+ return c
43
+ return [c for c in df.columns if not is_id(df[c]) and df[c].nunique() >= 2][-1]
44
+
45
+
46
+ def make_labels(col):
47
+ """Numeric columns with many values become High / Low (split at the median)."""
48
+ if pd.api.types.is_numeric_dtype(col) and col.nunique() > 10:
49
+ col = pd.Series(np.where(col >= col.median(), "High", "Low"), index=col.index)
50
+ encoder = LabelEncoder()
51
+ return encoder.fit_transform(col.astype(str)), [str(c) for c in encoder.classes_]
52
+
53
+
54
+ def make_features(X):
55
+ """Drop ID / constant / free-text columns, fill missing values, one-hot encode."""
56
+ keep = [c for c in X.columns
57
+ if not is_id(X[c]) and X[c].nunique() > 1
58
+ and (pd.api.types.is_numeric_dtype(X[c]) or X[c].nunique() <= 50)]
59
+ X = X[keep].copy()
60
+ for c in X.columns:
61
+ if pd.api.types.is_numeric_dtype(X[c]):
62
+ X[c] = X[c].fillna(X[c].median())
63
+ else:
64
+ X[c] = X[c].fillna(X[c].mode()[0])
65
+ return pd.get_dummies(X, drop_first=True, dtype=int), keep
66
+
67
+
68
+ def ask_columns(df, target, dropped):
69
+ print(f"\nAccuracy is below {MIN_ACCURACY:.0%}. You can choose the columns yourself.")
70
+ print("Columns:", list(df.columns))
71
+ new_target = input(f"Target column (Enter to keep '{target}'): ").strip() or target
72
+ if new_target not in df.columns:
73
+ print(f"'{new_target}' not found, keeping '{target}'.")
74
+ new_target = target
75
+ drop = [c.strip() for c in input("Columns to leave out, comma separated (Enter for none): ").split(",")]
76
+ drop = [c for c in drop if c in df.columns and c != new_target]
77
+ changed = new_target != target or set(drop) != set(dropped)
78
+ return new_target, drop, changed
79
+
80
+
81
+ # ---------- 1. Load dataset ----------
82
+ path = input("Enter CSV file path or press Enter for built-in Breast Cancer data: ").strip().strip('"')
83
+ if path:
84
+ df = read_csv(path)
85
+ else:
86
+ data = load_breast_cancer(as_frame=True)
87
+ df = data.frame.copy()
88
+ df["target"] = data.target_names[data.target]
89
+ print("Using built-in Breast Cancer dataset")
90
+ print(df.head())
91
+ print("Shape:", df.shape)
92
+
93
+ target = guess_target(df)
94
+ dropped = []
95
+
96
+ # ---------- 2. Train (repeats if accuracy is low and you choose other columns) ----------
97
+ while True:
98
+ data = df.dropna(subset=[target]).drop_duplicates()
99
+ y, class_names = make_labels(data[target])
100
+ X, used = make_features(data.drop(columns=[target] + dropped))
101
+ print(f"\nTarget column: {target} -> classes {class_names}")
102
+ print("Feature columns used:", used)
103
+
104
+ stratify = y if np.bincount(y).min() >= 2 else None
105
+ X_train, X_test, y_train, y_test = train_test_split(
106
+ X, y, test_size=0.2, random_state=42, stratify=stratify
107
+ )
108
+ scaler = StandardScaler()
109
+ X_train = scaler.fit_transform(X_train)
110
+ X_test = scaler.transform(X_test)
111
+
112
+ # Deep feed forward network
113
+ model = Sequential([
114
+ Input(shape=(X_train.shape[1],)),
115
+ Dense(128, activation="relu"),
116
+ Dropout(0.3),
117
+ Dense(64, activation="relu"),
118
+ Dropout(0.2),
119
+ Dense(32, activation="relu"),
120
+ Dense(len(class_names), activation="softmax"),
121
+ ])
122
+ model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
123
+ model.fit(X_train, y_train, epochs=50, batch_size=32, validation_split=0.2, verbose=0,
124
+ callbacks=[EarlyStopping(monitor="val_loss", patience=5, restore_best_weights=True)])
125
+
126
+ test_acc = model.evaluate(X_test, y_test, verbose=0)[1]
127
+ print(f"Testing Accuracy: {test_acc * 100:.2f}%")
128
+ if test_acc >= MIN_ACCURACY:
129
+ break
130
+ target, dropped, changed = ask_columns(df, target, dropped)
131
+ if not changed:
132
+ break
133
+
134
+ # ---------- 3. Final results ----------
135
+ model.summary()
136
+ train_acc = model.evaluate(X_train, y_train, verbose=0)[1]
137
+ y_pred = model.predict(X_test, verbose=0).argmax(axis=1)
138
+
139
+ print(f"\nTraining Accuracy: {train_acc * 100:.2f}%")
140
+ print(f"Testing Accuracy: {test_acc * 100:.2f}%")
141
+ print("\nClassification Report:")
142
+ print(classification_report(y_test, y_pred, labels=range(len(class_names)),
143
+ target_names=class_names, zero_division=0))
144
+ print("Confusion Matrix:")
145
+ print(confusion_matrix(y_test, y_pred))
@@ -0,0 +1,180 @@
1
+ # Regularization and Optimization - works with any CSV classification dataset
2
+ # Compares: no regularization vs L2 + Dropout + Early Stopping,
3
+ # and the optimizers Adam, SGD and RMSprop.
4
+ # The target column and the feature columns are picked automatically.
5
+ # If accuracy is low, you are asked which columns to use and the models are retrained.
6
+ # Press Enter to use the built-in Wine dataset (from scikit-learn, no download).
7
+ import numpy as np
8
+ import pandas as pd
9
+ import matplotlib.pyplot as plt
10
+ from sklearn.datasets import load_wine
11
+ from sklearn.model_selection import train_test_split
12
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
13
+ from sklearn.metrics import classification_report, confusion_matrix
14
+ from tensorflow.keras.models import Sequential
15
+ from tensorflow.keras.layers import Input, Dense, Dropout
16
+ from tensorflow.keras.regularizers import l2
17
+ from tensorflow.keras.callbacks import EarlyStopping
18
+
19
+ MIN_ACCURACY = 0.70 # below this you get to choose the columns yourself
20
+ TARGET_NAMES = {"target", "label", "labels", "class", "output", "outcome", "result", "y"}
21
+
22
+
23
+ # ---------- helpers ----------
24
+ def read_csv(path):
25
+ """Read a CSV with any separator (, ; tab |) and encoding."""
26
+ with open(path, encoding="latin-1") as f:
27
+ first_line = f.readline()
28
+ sep = max([",", ";", "\t", "|"], key=first_line.count)
29
+ try:
30
+ df = pd.read_csv(path, sep=sep)
31
+ except UnicodeDecodeError:
32
+ df = pd.read_csv(path, sep=sep, encoding="latin-1")
33
+ df = df.loc[:, ~df.columns.astype(str).str.startswith("Unnamed")]
34
+ return df.dropna(axis=1, how="all")
35
+
36
+
37
+ def is_id(col):
38
+ name = str(col.name).lower()
39
+ return (name in ("id", "index") or name.endswith("_id")
40
+ or (pd.api.types.is_integer_dtype(col) and col.nunique() == len(col)))
41
+
42
+
43
+ def guess_target(df):
44
+ for c in df.columns:
45
+ if str(c).lower() in TARGET_NAMES:
46
+ return c
47
+ return [c for c in df.columns if not is_id(df[c]) and df[c].nunique() >= 2][-1]
48
+
49
+
50
+ def make_labels(col):
51
+ """Numeric columns with many values become High / Low (split at the median)."""
52
+ if pd.api.types.is_numeric_dtype(col) and col.nunique() > 10:
53
+ col = pd.Series(np.where(col >= col.median(), "High", "Low"), index=col.index)
54
+ encoder = LabelEncoder()
55
+ return encoder.fit_transform(col.astype(str)), [str(c) for c in encoder.classes_]
56
+
57
+
58
+ def make_features(X):
59
+ """Drop ID / constant / free-text columns, fill missing values, one-hot encode."""
60
+ keep = [c for c in X.columns
61
+ if not is_id(X[c]) and X[c].nunique() > 1
62
+ and (pd.api.types.is_numeric_dtype(X[c]) or X[c].nunique() <= 50)]
63
+ X = X[keep].copy()
64
+ for c in X.columns:
65
+ if pd.api.types.is_numeric_dtype(X[c]):
66
+ X[c] = X[c].fillna(X[c].median())
67
+ else:
68
+ X[c] = X[c].fillna(X[c].mode()[0])
69
+ return pd.get_dummies(X, drop_first=True, dtype=int), keep
70
+
71
+
72
+ def ask_columns(df, target, dropped):
73
+ print(f"\nBest accuracy is below {MIN_ACCURACY:.0%}. You can choose the columns yourself.")
74
+ print("Columns:", list(df.columns))
75
+ new_target = input(f"Target column (Enter to keep '{target}'): ").strip() or target
76
+ if new_target not in df.columns:
77
+ print(f"'{new_target}' not found, keeping '{target}'.")
78
+ new_target = target
79
+ drop = [c.strip() for c in input("Columns to leave out, comma separated (Enter for none): ").split(",")]
80
+ drop = [c for c in drop if c in df.columns and c != new_target]
81
+ changed = new_target != target or set(drop) != set(dropped)
82
+ return new_target, drop, changed
83
+
84
+
85
+ def build_model(n_inputs, n_classes, regularize, optimizer):
86
+ reg = l2(0.001) if regularize else None
87
+ drop = 0.3 if regularize else 0.0
88
+ model = Sequential([
89
+ Input(shape=(n_inputs,)),
90
+ Dense(128, activation="relu", kernel_regularizer=reg),
91
+ Dropout(drop),
92
+ Dense(64, activation="relu", kernel_regularizer=reg),
93
+ Dropout(drop),
94
+ Dense(n_classes, activation="softmax"),
95
+ ])
96
+ model.compile(optimizer=optimizer, loss="sparse_categorical_crossentropy", metrics=["accuracy"])
97
+ return model
98
+
99
+
100
+ EXPERIMENTS = [
101
+ ("No regularization (Adam)", False, "adam"),
102
+ ("L2 + Dropout + EarlyStop (Adam)", True, "adam"),
103
+ ("L2 + Dropout + EarlyStop (SGD)", True, "sgd"),
104
+ ("L2 + Dropout + EarlyStop (RMSprop)", True, "rmsprop"),
105
+ ]
106
+
107
+ # ---------- 1. Load dataset ----------
108
+ path = input("Enter CSV file path or press Enter for built-in Wine data: ").strip().strip('"')
109
+ if path:
110
+ df = read_csv(path)
111
+ else:
112
+ data = load_wine(as_frame=True)
113
+ df = data.frame.copy()
114
+ df["target"] = data.target_names[data.target]
115
+ print("Using built-in Wine dataset")
116
+ print(df.head())
117
+ print("Shape:", df.shape)
118
+
119
+ target = guess_target(df)
120
+ dropped = []
121
+
122
+ # ---------- 2. Train all experiments (repeats if accuracy is low and you choose other columns) ----------
123
+ while True:
124
+ data = df.dropna(subset=[target]).drop_duplicates()
125
+ y, class_names = make_labels(data[target])
126
+ X, used = make_features(data.drop(columns=[target] + dropped))
127
+ print(f"\nTarget column: {target} -> classes {class_names}")
128
+ print("Feature columns used:", used)
129
+
130
+ stratify = y if np.bincount(y).min() >= 2 else None
131
+ X_train, X_test, y_train, y_test = train_test_split(
132
+ X, y, test_size=0.2, random_state=42, stratify=stratify
133
+ )
134
+ scaler = StandardScaler()
135
+ X_train = scaler.fit_transform(X_train)
136
+ X_test = scaler.transform(X_test)
137
+
138
+ results, histories, models = [], {}, {}
139
+ for name, regularize, optimizer in EXPERIMENTS:
140
+ print("Training:", name)
141
+ model = build_model(X_train.shape[1], len(class_names), regularize, optimizer)
142
+ callbacks = [EarlyStopping(monitor="val_loss", patience=5, restore_best_weights=True)] if regularize else []
143
+ history = model.fit(X_train, y_train, epochs=50, batch_size=32,
144
+ validation_split=0.2, callbacks=callbacks, verbose=0)
145
+ train_acc = model.evaluate(X_train, y_train, verbose=0)[1]
146
+ test_acc = model.evaluate(X_test, y_test, verbose=0)[1]
147
+ results.append([name, train_acc * 100, test_acc * 100, len(history.history["loss"])])
148
+ histories[name] = history
149
+ models[name] = model
150
+
151
+ results_df = pd.DataFrame(results, columns=["Model", "Train Acc", "Test Acc", "Epochs"])
152
+ best_acc = results_df["Test Acc"].max() / 100
153
+ print(f"Best Test Accuracy: {best_acc * 100:.2f}%")
154
+ if best_acc >= MIN_ACCURACY:
155
+ break
156
+ target, dropped, changed = ask_columns(df, target, dropped)
157
+ if not changed:
158
+ break
159
+
160
+ # ---------- 3. Compare results ----------
161
+ print("\nComparison:")
162
+ print(results_df.round(2).to_string(index=False))
163
+
164
+ plt.figure(figsize=(9, 5))
165
+ for name, history in histories.items():
166
+ plt.plot(history.history["val_loss"], label=name)
167
+ plt.title("Validation Loss: Regularization and Optimizers")
168
+ plt.xlabel("Epoch")
169
+ plt.ylabel("Validation Loss")
170
+ plt.legend()
171
+ plt.grid(True)
172
+ plt.show()
173
+
174
+ best = results_df.sort_values("Test Acc", ascending=False).iloc[0]["Model"]
175
+ y_pred = models[best].predict(X_test, verbose=0).argmax(axis=1)
176
+ print(f"\nBest model: {best}")
177
+ print(classification_report(y_test, y_pred, labels=range(len(class_names)),
178
+ target_names=class_names, zero_division=0))
179
+ print("Confusion Matrix:")
180
+ print(confusion_matrix(y_test, y_pred))