libz 0.6__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 (66) hide show
  1. {libz-0.6 → 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.6 → libz-0.7}/libz/DLG/__init__.py +4 -3
  5. {libz-0.6 → libz-0.7}/libz/DLG/prac1.py +10 -2
  6. {libz-0.6 → libz-0.7}/libz/DLG/prac2.py +10 -2
  7. {libz-0.6 → libz-0.7}/libz/DLG/prac3.py +15 -2
  8. {libz-0.6 → libz-0.7}/libz/DLG/prac4.py +15 -2
  9. {libz-0.6 → libz-0.7}/libz/__init__.py +4 -1
  10. {libz-0.6 → libz-0.7}/libz/_core.py +10 -3
  11. libz-0.7/libz/_update.py +47 -0
  12. {libz-0.6 → libz-0.7}/libz.egg-info/PKG-INFO +1 -1
  13. {libz-0.6 → libz-0.7}/libz.egg-info/SOURCES.txt +2 -3
  14. {libz-0.6 → libz-0.7}/pyproject.toml +1 -1
  15. libz-0.6/libz/DL/prac8.py +0 -114
  16. libz-0.6/libz/DL/prac9.py +0 -158
  17. libz-0.6/libz/DLG/prac8.py +0 -231
  18. libz-0.6/libz/DLG/prac9.py +0 -132
  19. {libz-0.6 → libz-0.7}/README.md +0 -0
  20. {libz-0.6 → libz-0.7}/libz/AWT/__init__.py +0 -0
  21. {libz-0.6 → libz-0.7}/libz/AWT/prac1.py +0 -0
  22. {libz-0.6 → libz-0.7}/libz/AWT/prac10.py +0 -0
  23. {libz-0.6 → libz-0.7}/libz/AWT/prac2.py +0 -0
  24. {libz-0.6 → libz-0.7}/libz/AWT/prac3.py +0 -0
  25. {libz-0.6 → libz-0.7}/libz/AWT/prac4.py +0 -0
  26. {libz-0.6 → libz-0.7}/libz/AWT/prac5.py +0 -0
  27. {libz-0.6 → libz-0.7}/libz/AWT/prac6.py +0 -0
  28. {libz-0.6 → libz-0.7}/libz/AWT/prac7.py +0 -0
  29. {libz-0.6 → libz-0.7}/libz/AWT/prac8.py +0 -0
  30. {libz-0.6 → libz-0.7}/libz/AWT/prac9.py +0 -0
  31. {libz-0.6 → libz-0.7}/libz/BDA/__init__.py +0 -0
  32. {libz-0.6 → libz-0.7}/libz/BDA/prac1.py +0 -0
  33. {libz-0.6 → libz-0.7}/libz/BDA/prac10.py +0 -0
  34. {libz-0.6 → libz-0.7}/libz/BDA/prac2.py +0 -0
  35. {libz-0.6 → libz-0.7}/libz/BDA/prac3.py +0 -0
  36. {libz-0.6 → libz-0.7}/libz/BDA/prac4.py +0 -0
  37. {libz-0.6 → libz-0.7}/libz/BDA/prac5.py +0 -0
  38. {libz-0.6 → libz-0.7}/libz/BDA/prac6.py +0 -0
  39. {libz-0.6 → libz-0.7}/libz/BDA/prac7.py +0 -0
  40. {libz-0.6 → libz-0.7}/libz/BDA/prac8.py +0 -0
  41. {libz-0.6 → libz-0.7}/libz/BDA/prac9.py +0 -0
  42. {libz-0.6 → libz-0.7}/libz/BIO/__init__.py +0 -0
  43. {libz-0.6 → libz-0.7}/libz/BIO/prac1.py +0 -0
  44. {libz-0.6 → libz-0.7}/libz/BIO/prac10.py +0 -0
  45. {libz-0.6 → libz-0.7}/libz/BIO/prac2.py +0 -0
  46. {libz-0.6 → libz-0.7}/libz/BIO/prac3.py +0 -0
  47. {libz-0.6 → libz-0.7}/libz/BIO/prac4.py +0 -0
  48. {libz-0.6 → libz-0.7}/libz/BIO/prac5.py +0 -0
  49. {libz-0.6 → libz-0.7}/libz/BIO/prac6.py +0 -0
  50. {libz-0.6 → libz-0.7}/libz/BIO/prac7.py +0 -0
  51. {libz-0.6 → libz-0.7}/libz/BIO/prac8.py +0 -0
  52. {libz-0.6 → libz-0.7}/libz/BIO/prac9.py +0 -0
  53. {libz-0.6 → libz-0.7}/libz/DL/__init__.py +0 -0
  54. {libz-0.6 → libz-0.7}/libz/DL/prac1.py +0 -0
  55. {libz-0.6 → libz-0.7}/libz/DL/prac2.py +0 -0
  56. {libz-0.6 → libz-0.7}/libz/DL/prac3.py +0 -0
  57. {libz-0.6 → libz-0.7}/libz/DL/prac4.py +0 -0
  58. {libz-0.6 → libz-0.7}/libz/DL/prac5.py +0 -0
  59. {libz-0.6 → libz-0.7}/libz/DL/prac6.py +0 -0
  60. {libz-0.6 → libz-0.7}/libz/DL/prac7.py +0 -0
  61. {libz-0.6 → libz-0.7}/libz/DLG/prac5.py +0 -0
  62. {libz-0.6 → libz-0.7}/libz/DLG/prac6.py +0 -0
  63. {libz-0.6 → libz-0.7}/libz/DLG/prac7.py +0 -0
  64. {libz-0.6 → libz-0.7}/libz.egg-info/dependency_links.txt +0 -0
  65. {libz-0.6 → libz-0.7}/libz.egg-info/top_level.txt +0 -0
  66. {libz-0.6 → libz-0.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: libz
3
- Version: 0.6
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)
@@ -8,8 +8,9 @@ TITLES = {
8
8
  5: "CNN-based handwriting recognition (any image folder / CSV / MNIST)",
9
9
  6: "CNN - unsupervised feature learning (any image folder / CSV / digits)",
10
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)",
11
+ 8: "Recursive neural network (tree)",
12
+ 9: "PCA vs linear autoencoder",
13
13
  }
14
14
 
15
- register(__name__, globals(), TITLES)
15
+ # prac8 and prac9 show the DL code (no dynamic version needed)
16
+ register(__name__, globals(), TITLES, links={8: "DL", 9: "DL"})
@@ -1,8 +1,10 @@
1
1
  # Deep Feed Forward Neural Network - works with any CSV classification dataset
2
2
  # The target column and the feature columns are picked automatically.
3
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).
4
5
  import numpy as np
5
6
  import pandas as pd
7
+ from sklearn.datasets import load_breast_cancer
6
8
  from sklearn.model_selection import train_test_split
7
9
  from sklearn.preprocessing import StandardScaler, LabelEncoder
8
10
  from sklearn.metrics import classification_report, confusion_matrix
@@ -77,8 +79,14 @@ def ask_columns(df, target, dropped):
77
79
 
78
80
 
79
81
  # ---------- 1. Load dataset ----------
80
- path = input("Enter CSV file path: ").strip().strip('"')
81
- df = read_csv(path)
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")
82
90
  print(df.head())
83
91
  print("Shape:", df.shape)
84
92
 
@@ -3,9 +3,11 @@
3
3
  # and the optimizers Adam, SGD and RMSprop.
4
4
  # The target column and the feature columns are picked automatically.
5
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).
6
7
  import numpy as np
7
8
  import pandas as pd
8
9
  import matplotlib.pyplot as plt
10
+ from sklearn.datasets import load_wine
9
11
  from sklearn.model_selection import train_test_split
10
12
  from sklearn.preprocessing import StandardScaler, LabelEncoder
11
13
  from sklearn.metrics import classification_report, confusion_matrix
@@ -103,8 +105,14 @@ EXPERIMENTS = [
103
105
  ]
104
106
 
105
107
  # ---------- 1. Load dataset ----------
106
- path = input("Enter CSV file path: ").strip().strip('"')
107
- df = read_csv(path)
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")
108
116
  print(df.head())
109
117
  print("Shape:", df.shape)
110
118
 
@@ -3,6 +3,7 @@
3
3
  # (only predictions it is confident about) and retrains on the bigger dataset.
4
4
  # The text column (longest average text) and the label column are picked automatically.
5
5
  # If the semi-supervised accuracy is low, you are asked which columns to use and it retrains.
6
+ # Press Enter instead of a path to use the built-in 20 Newsgroups data (downloaded once, cached).
6
7
  import numpy as np
7
8
  import pandas as pd
8
9
  from sklearn.model_selection import train_test_split
@@ -96,8 +97,20 @@ def train_model(X, y, n_classes):
96
97
 
97
98
 
98
99
  # ---------- 1. Load dataset ----------
99
- path = input("Enter CSV file path: ").strip().strip('"')
100
- df = read_csv(path)
100
+ # Press Enter for the built-in 20 Newsgroups data (rec.autos vs sci.space).
101
+ # It is downloaded once (~14 MB) and then cached by scikit-learn.
102
+ path = input("Enter CSV file path or press Enter for built-in 20 Newsgroups data "
103
+ "(downloads once, ~14 MB): ").strip().strip('"')
104
+ if path:
105
+ df = read_csv(path)
106
+ else:
107
+ from sklearn.datasets import fetch_20newsgroups
108
+ news = fetch_20newsgroups(subset="all", categories=["rec.autos", "sci.space"],
109
+ remove=("headers", "footers", "quotes"))
110
+ df = pd.DataFrame({"text": news.data,
111
+ "label": [news.target_names[t] for t in news.target]})
112
+ df = df[df["text"].str.strip() != ""].reset_index(drop=True) # drop empty posts
113
+ print("Using built-in 20 Newsgroups dataset (rec.autos vs sci.space)")
101
114
  print(df.head())
102
115
  print("Shape:", df.shape)
103
116
 
@@ -2,6 +2,7 @@
2
2
  # One shared network predicts several target columns at the same time.
3
3
  # The target columns and the feature columns are picked automatically.
4
4
  # If average accuracy is low, you are asked which columns to use and the model is retrained.
5
+ # Press Enter instead of a path to use the built-in scikit-learn Breast Cancer data (offline).
5
6
  import numpy as np
6
7
  import pandas as pd
7
8
  import matplotlib.pyplot as plt
@@ -78,8 +79,20 @@ def ask_columns(df, targets, dropped):
78
79
 
79
80
 
80
81
  # ---------- 1. Load dataset ----------
81
- path = input("Enter CSV file path: ").strip().strip('"')
82
- df = read_csv(path)
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
+ # Built-in scikit-learn data (offline). Three tasks are derived from its columns;
87
+ # the source columns are then dropped so the targets are not leaked as features.
88
+ from sklearn.datasets import load_breast_cancer
89
+ cancer = load_breast_cancer(as_frame=True)
90
+ df = cancer.frame.copy()
91
+ df["diagnosis"] = [cancer.target_names[t] for t in df["target"]] # malignant / benign
92
+ df["large_tumour"] = np.where(df["mean area"] >= df["mean area"].median(), "yes", "no")
93
+ df["smooth_surface"] = np.where(df["mean smoothness"] <= df["mean smoothness"].median(), "yes", "no")
94
+ df = df.drop(columns=["target", "mean area", "mean smoothness"])
95
+ print("Using built-in Breast Cancer dataset (tasks: diagnosis, large_tumour, smooth_surface)")
83
96
  print(df.head())
84
97
  print("Shape:", df.shape)
85
98
 
@@ -1,5 +1,8 @@
1
1
  """libz - a lightweight Python utility toolkit."""
2
2
  from libz import AWT, DL, DLG, BIO, BDA
3
+ from libz._update import check_for_update
3
4
 
4
- __version__ = "0.6"
5
+ __version__ = "0.7"
5
6
  __all__ = ["AWT", "DL", "DLG", "BIO", "BDA"]
7
+
8
+ check_for_update(__version__)
@@ -2,9 +2,14 @@ import os
2
2
  import re
3
3
 
4
4
 
5
- def register(module_name, namespace, titles=None):
6
- """Register the functions of a module."""
5
+ def register(module_name, namespace, titles=None, links=None):
6
+ """Register the functions of a module.
7
+
8
+ links maps a number to another subject's file, e.g. {8: "DL"} makes prac8
9
+ show DL/prac8.py, so both always print the same code.
10
+ """
7
11
  titles = titles or {}
12
+ links = links or {}
8
13
  folder = os.path.dirname(namespace["__file__"])
9
14
  subject = module_name.split(".")[-1]
10
15
  numbers = sorted(
@@ -12,9 +17,11 @@ def register(module_name, namespace, titles=None):
12
17
  for m in (re.fullmatch(r"prac(\d+)\.py", f) for f in os.listdir(folder))
13
18
  if m
14
19
  )
20
+ numbers = sorted(set(numbers) | set(links))
15
21
 
16
22
  def make(n):
17
- path = os.path.join(folder, "prac{}.py".format(n))
23
+ source = os.path.join(os.path.dirname(folder), links[n]) if n in links else folder
24
+ path = os.path.join(source, "prac{}.py".format(n))
18
25
 
19
26
  def prac():
20
27
  with open(path, encoding="utf-8") as f:
@@ -0,0 +1,47 @@
1
+ """Tell the user when a newer libz is on PyPI (checked at most once a day)."""
2
+ import json
3
+ import os
4
+ import sys
5
+ import time
6
+ from urllib.request import urlopen
7
+
8
+ PYPI_URL = "https://pypi.org/pypi/libz/json"
9
+ CACHE_FILE = os.path.join(os.path.expanduser("~"), ".libz_update_check.json")
10
+ CHECK_EVERY = 24 * 60 * 60 # seconds
11
+ TIMEOUT = 1.5 # seconds to wait for PyPI
12
+
13
+
14
+ def _as_tuple(version):
15
+ return tuple(int(part) for part in version.split(".") if part.isdigit())
16
+
17
+
18
+ def _latest_version():
19
+ """Latest version on PyPI, using the saved answer if it is less than a day old."""
20
+ try:
21
+ with open(CACHE_FILE) as f:
22
+ cache = json.load(f)
23
+ if time.time() - cache["checked"] < CHECK_EVERY:
24
+ return cache["latest"]
25
+ except (OSError, ValueError, KeyError):
26
+ pass
27
+
28
+ with urlopen(PYPI_URL, timeout=TIMEOUT) as response:
29
+ latest = json.load(response)["info"]["version"]
30
+ try:
31
+ with open(CACHE_FILE, "w") as f:
32
+ json.dump({"checked": time.time(), "latest": latest}, f)
33
+ except OSError:
34
+ pass
35
+ return latest
36
+
37
+
38
+ def check_for_update(current):
39
+ if os.environ.get("LIBZ_NO_UPDATE_CHECK"):
40
+ return
41
+ try:
42
+ latest = _latest_version()
43
+ if _as_tuple(latest) > _as_tuple(current):
44
+ print("libz {} is available (you have {}). Update with: pip install -U libz".format(latest, current),
45
+ file=sys.stderr)
46
+ except Exception:
47
+ pass # offline or PyPI unreachable: never get in the way
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: libz
3
- Version: 0.6
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
@@ -2,6 +2,7 @@ README.md
2
2
  pyproject.toml
3
3
  libz/__init__.py
4
4
  libz/_core.py
5
+ libz/_update.py
5
6
  libz.egg-info/PKG-INFO
6
7
  libz.egg-info/SOURCES.txt
7
8
  libz.egg-info/dependency_links.txt
@@ -56,6 +57,4 @@ libz/DLG/prac3.py
56
57
  libz/DLG/prac4.py
57
58
  libz/DLG/prac5.py
58
59
  libz/DLG/prac6.py
59
- libz/DLG/prac7.py
60
- libz/DLG/prac8.py
61
- libz/DLG/prac9.py
60
+ libz/DLG/prac7.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "libz"
7
- version = "0.6"
7
+ version = "0.7"
8
8
  description = "A lightweight Python utility toolkit."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.7"
libz-0.6/libz/DL/prac8.py DELETED
@@ -1,114 +0,0 @@
1
- import torch
2
- import torch.nn as nn
3
- import torch.optim as optim
4
-
5
- # 1. DEFINE RECURSIVE NEURAL NETWORK
6
- class RecursiveNN(nn.Module):
7
-
8
- def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes):
9
- super().__init__()
10
-
11
- # Convert word IDs into vectors
12
- self.embedding = nn.Embedding(vocab_size, hidden_dim)
13
-
14
- # Combine left and right child representations
15
- self.composition = nn.Linear(hidden_dim * 2, hidden_dim)
16
-
17
- # Classify the final tree representation
18
- self.classifier = nn.Linear(hidden_dim, num_classes)
19
-
20
- def forward(self, tree):
21
-
22
- # If the node is a leaf (word ID)
23
- if isinstance(tree, int):
24
- word = torch.tensor(tree, dtype=torch.long)
25
- return self.embedding(word)
26
-
27
- # Recursively process left and right children
28
- left_vector = self.forward(tree[0])
29
- right_vector = self.forward(tree[1])
30
-
31
- # Combine both child vectors
32
- combined = torch.cat((left_vector, right_vector))
33
-
34
- # Generate parent representation
35
- parent_vector = torch.tanh(
36
- self.composition(combined)
37
- )
38
- return parent_vector
39
-
40
- # 2. CREATE SAMPLE TREE DATA
41
- # Label 1 = Positive sentiment
42
- # Label 0 = Negative sentiment
43
- training_data = [
44
- (((10, 25), (4, 82)), 1), # Positive: "the movie was great"
45
- (((10, 25), (4, 50)), 0), # Negative: "the movie was terrible"
46
- ((82, 25), 1), # Positive: "great movie"
47
- ((50, 25), 0) # Negative: "terrible movie"
48
- ]
49
-
50
- # 3. INITIALIZE MODEL
51
- model = RecursiveNN(
52
- vocab_size=100,
53
- embed_dim=16,
54
- hidden_dim=16,
55
- num_classes=2
56
- )
57
-
58
- # 4. DEFINE LOSS AND OPTIMIZER
59
- optimizer = optim.Adam(
60
- model.parameters(),
61
- lr=0.05
62
- )
63
- criterion = nn.CrossEntropyLoss()
64
-
65
- # 5. TRAIN THE MODEL
66
- print("Starting training...")
67
- for epoch in range(20):
68
- total_loss = 0
69
-
70
- for tree, label in training_data:
71
- optimizer.zero_grad()
72
-
73
- # Generate representation of the complete tree
74
- root_vector = model(tree)
75
-
76
- # Predict sentiment from the root vector
77
- logits = model.classifier(root_vector).unsqueeze(0)
78
-
79
- # Actual label
80
- target = torch.tensor([label], dtype=torch.long)
81
-
82
- # Calculate loss and update parameters
83
- loss = criterion(logits, target)
84
-
85
- loss.backward()
86
- optimizer.step()
87
-
88
- total_loss += loss.item()
89
-
90
- if (epoch + 1) % 5 == 0:
91
- print(
92
- f"Epoch {epoch + 1:02d}/20 | "
93
- f"Loss: {total_loss:.4f}"
94
- )
95
-
96
- # 6. TEST THE TRAINED MODEL
97
- print("\nTesting trained model:")
98
- model.eval()
99
-
100
- with torch.no_grad():
101
- for tree, label in training_data:
102
-
103
- root_vector = model(tree)
104
- logits = model.classifier(root_vector)
105
-
106
- prediction = torch.argmax(logits, dim=-1).item()
107
-
108
- actual = "Positive" if label == 1 else "Negative"
109
- predicted = "Positive" if prediction == 1 else "Negative"
110
-
111
- print("Tree:", tree)
112
- print("Actual sentiment:", actual)
113
- print("Predicted sentiment:", predicted)
114
- print("-" * 40)
libz-0.6/libz/DL/prac9.py DELETED
@@ -1,158 +0,0 @@
1
- import torch
2
- import torch.nn as nn
3
- import torch.optim as optim
4
- import numpy as np
5
- import matplotlib.pyplot as plt
6
-
7
- from sklearn.decomposition import PCA
8
- from sklearn.datasets import make_blobs
9
-
10
- # 1. GENERATE SYNTHETIC DATA
11
- X_np, _ = make_blobs(
12
- n_samples=1000,
13
- n_features=10,
14
- centers=3,
15
- random_state=42
16
- )
17
-
18
- X_tensor = torch.tensor(X_np, dtype=torch.float32)
19
- print("Original data shape:", X_np.shape)
20
-
21
- # 2. APPROACH A: PCA
22
- pca = PCA(n_components=3)
23
- X_pca = pca.fit_transform(X_np)
24
-
25
- print("\nPCA Output Shape:", X_pca.shape)
26
- print(
27
- "PCA Explained Variance Ratio:",
28
- pca.explained_variance_ratio_
29
- )
30
-
31
- print(
32
- "Total Explained Variance:",
33
- round(pca.explained_variance_ratio_.sum(), 4)
34
- )
35
-
36
- # 3. DEFINE LINEAR AUTOENCODER
37
- class LinearAutoencoder(nn.Module):
38
- def __init__(self, input_dim, latent_dim):
39
- super().__init__()
40
-
41
- # Encoder reduces dimensions
42
- self.encoder = nn.Linear(
43
- input_dim,
44
- latent_dim,
45
- bias=False
46
- )
47
-
48
- # Decoder reconstructs original dimensions
49
- self.decoder = nn.Linear(
50
- latent_dim,
51
- input_dim,
52
- bias=True
53
- )
54
-
55
- def forward(self, x):
56
- h = self.encoder(x)
57
- x_recon = self.decoder(h)
58
- return x_recon, h
59
-
60
- # 4. SET HYPERPARAMETERS
61
- input_dim = 10
62
- latent_dim = 3
63
-
64
- model = LinearAutoencoder(
65
- input_dim,
66
- latent_dim
67
- )
68
-
69
- criterion = nn.MSELoss()
70
-
71
- optimizer = optim.Adam(
72
- model.parameters(),
73
- lr=0.01
74
- )
75
-
76
- # 5. TRAIN THE AUTOENCODER
77
- model.train()
78
- for epoch in range(200):
79
- optimizer.zero_grad()
80
-
81
- reconstructions, latent_factors = model(X_tensor)
82
- loss = criterion(
83
- reconstructions,
84
- X_tensor
85
- )
86
-
87
- loss.backward()
88
- optimizer.step()
89
-
90
- if (epoch + 1) % 50 == 0:
91
- print(
92
- f"Epoch [{epoch + 1}/200], "
93
- f"Reconstruction MSE Loss: {loss.item():.4f}"
94
- )
95
-
96
- # 6. EXTRACT LEARNED FACTORS
97
- model.eval()
98
- with torch.no_grad():
99
- reconstructions, latent_factors = model(X_tensor)
100
- latent_factors = latent_factors.numpy()
101
- reconstructions = reconstructions.numpy()
102
- W = model.decoder.weight.detach().numpy()
103
-
104
- print(
105
- "\nAutoencoder Latent Shape:",
106
- latent_factors.shape
107
- )
108
-
109
- print(
110
- "Factor Loading Matrix Shape:",
111
- W.shape
112
- )
113
-
114
- # 7. COMPARE RECONSTRUCTION ERROR
115
- pca_reconstructed = pca.inverse_transform(X_pca)
116
- pca_mse = np.mean(
117
- (X_np - pca_reconstructed) ** 2
118
- )
119
-
120
- ae_mse = np.mean(
121
- (X_np - reconstructions) ** 2
122
- )
123
-
124
- print(
125
- "\nPCA Reconstruction MSE:",
126
- round(pca_mse, 4)
127
- )
128
-
129
- print(
130
- "Autoencoder Reconstruction MSE:",
131
- round(ae_mse, 4)
132
- )
133
-
134
- # 8. PLOT PCA EXPLAINED VARIANCE
135
- plt.figure(figsize=(7, 4))
136
- plt.bar(
137
- range(1, 4),
138
- pca.explained_variance_ratio_
139
- )
140
-
141
- plt.title("PCA Explained Variance Ratio")
142
- plt.xlabel("Principal Component")
143
- plt.ylabel("Explained Variance Ratio")
144
- plt.xticks([1, 2, 3])
145
- plt.grid(axis="y")
146
- plt.show()
147
-
148
- # 9. PLOT RECONSTRUCTION ERROR COMPARISON
149
- plt.figure(figsize=(7, 4))
150
- plt.bar(
151
- ["PCA", "Linear Autoencoder"],
152
- [pca_mse, ae_mse]
153
- )
154
-
155
- plt.title("Reconstruction Error Comparison")
156
- plt.ylabel("Mean Squared Error")
157
- plt.grid(axis="y")
158
- plt.show()
@@ -1,231 +0,0 @@
1
- # Recursive Neural Network (tree structured) for sentence classification - any text CSV
2
- # Every sentence is turned into a binary tree automatically (split in halves),
3
- # and the network combines child vectors bottom-up until it reaches the root.
4
- # The text column (longest text) and the label column are picked automatically,
5
- # and the words kept per sentence adapt to the data (95th percentile, max 30).
6
- # If accuracy is low, you are asked which columns to use and the model is retrained.
7
- # Press Enter to use a small built-in sentiment dataset.
8
- import re
9
- import math
10
- import random
11
-
12
- import pandas as pd
13
- import torch
14
- import torch.nn as nn
15
- import torch.optim as optim
16
-
17
- random.seed(42)
18
- torch.manual_seed(42)
19
-
20
- SAMPLE = [
21
- ("the movie was great", "Positive"),
22
- ("the movie was terrible", "Negative"),
23
- ("great movie", "Positive"),
24
- ("terrible movie", "Negative"),
25
- ("i loved the acting", "Positive"),
26
- ("i hated the acting", "Negative"),
27
- ("the story was wonderful and fun", "Positive"),
28
- ("the story was boring and slow", "Negative"),
29
- ("what a fantastic film", "Positive"),
30
- ("what an awful film", "Negative"),
31
- ("really enjoyed it", "Positive"),
32
- ("really disliked it", "Negative"),
33
- ]
34
- MAX_SAMPLES = 2000 # recursive training is slow, so large files are sampled
35
- MAX_WORDS = 30 # upper limit of words kept per sentence
36
- MIN_ACCURACY = 0.70 # below this you get to choose the columns yourself
37
- TARGET_NAMES = {"target", "label", "labels", "class", "output", "outcome", "result", "y",
38
- "sentiment", "category"}
39
- EPOCHS = 20
40
-
41
-
42
- # ---------- helpers ----------
43
- def read_csv(path):
44
- """Read a CSV with any separator (, ; tab |) and encoding."""
45
- with open(path, encoding="latin-1") as f:
46
- first_line = f.readline()
47
- sep = max([",", ";", "\t", "|"], key=first_line.count)
48
- try:
49
- df = pd.read_csv(path, sep=sep)
50
- except UnicodeDecodeError:
51
- df = pd.read_csv(path, sep=sep, encoding="latin-1")
52
- df = df.loc[:, ~df.columns.astype(str).str.startswith("Unnamed")]
53
- return df.dropna(axis=1, how="all")
54
-
55
-
56
- def guess_text_label(df):
57
- """Text = non-numeric column with the longest average text.
58
- Label = a column named like a target, else one with 2..20 unique values, else the first other column."""
59
- text_cols = [c for c in df.columns if not pd.api.types.is_numeric_dtype(df[c])]
60
- if not text_cols:
61
- return None, None
62
- text = max(text_cols, key=lambda c: df[c].dropna().astype(str).str.len().mean())
63
- others = [c for c in df.columns if c != text]
64
- for c in others:
65
- if str(c).lower() in TARGET_NAMES:
66
- return text, c
67
- for c in others:
68
- if 2 <= df[c].nunique() <= 20:
69
- return text, c
70
- return text, others[0]
71
-
72
-
73
- def ask_columns(df, text, label):
74
- print(f"\nAccuracy is below {MIN_ACCURACY:.0%}. You can choose the columns yourself.")
75
- print("Columns:", list(df.columns))
76
- new_text = input(f"Text column (Enter to keep '{text}'): ").strip() or text
77
- if new_text not in df.columns:
78
- print(f"'{new_text}' not found, keeping '{text}'.")
79
- new_text = text
80
- new_label = input(f"Label column (Enter to keep '{label}'): ").strip() or label
81
- if new_label not in df.columns or new_label == new_text:
82
- print(f"'{new_label}' cannot be used, keeping '{label}'.")
83
- new_label = label
84
- changed = new_text != text or new_label != label
85
- return new_text, new_label, changed
86
-
87
-
88
- def tokenize(text, max_words=MAX_WORDS):
89
- return re.findall(r"[a-z0-9']+", str(text).lower())[:max_words]
90
-
91
-
92
- def words_limit(texts):
93
- """95th percentile of sentence lengths, but never more than MAX_WORDS."""
94
- lengths = [len(tokenize(t, None)) for t in texts]
95
- lengths = [n for n in lengths if n > 0] or [1]
96
- p95 = math.ceil(pd.Series(lengths).quantile(0.95))
97
- return max(1, min(MAX_WORDS, p95))
98
-
99
-
100
- def build_tree(ids):
101
- """[w1, w2, w3, w4] -> ((w1, w2), (w3, w4))"""
102
- if len(ids) == 1:
103
- return ids[0]
104
- mid = len(ids) // 2
105
- return (build_tree(ids[:mid]), build_tree(ids[mid:]))
106
-
107
-
108
- # ---------- Recursive Neural Network ----------
109
- class RecursiveNN(nn.Module):
110
- def __init__(self, vocab_size, hidden_dim, num_classes):
111
- super().__init__()
112
- self.embedding = nn.Embedding(vocab_size, hidden_dim)
113
- self.composition = nn.Linear(hidden_dim * 2, hidden_dim)
114
- self.classifier = nn.Linear(hidden_dim, num_classes)
115
-
116
- def encode(self, tree):
117
- if isinstance(tree, int): # leaf = word
118
- return self.embedding(torch.tensor(tree))
119
- left = self.encode(tree[0])
120
- right = self.encode(tree[1])
121
- return torch.tanh(self.composition(torch.cat((left, right))))
122
-
123
- def forward(self, tree):
124
- return self.classifier(self.encode(tree))
125
-
126
-
127
- def predict(model, tree):
128
- with torch.no_grad():
129
- return model(tree).argmax().item()
130
-
131
-
132
- # ---------- 1. Load data ----------
133
- path = input("Enter CSV file path or press Enter for sample data: ").strip().strip('"')
134
- if path:
135
- df = read_csv(path)
136
- print(df.head())
137
- print("Shape:", df.shape)
138
- if df.shape[1] < 2:
139
- raise SystemExit("The CSV needs at least a text column and a label column.")
140
- text_col, label_col = guess_text_label(df)
141
- if text_col is None:
142
- print("\nNo text (non-numeric) column was found. Please choose the columns yourself.")
143
- print("Columns:", list(df.columns))
144
- text_col = input("Text column: ").strip()
145
- if text_col not in df.columns:
146
- print(f"'{text_col}' not found, using '{df.columns[0]}'.")
147
- text_col = df.columns[0]
148
- label_col = input("Label column: ").strip()
149
- if label_col not in df.columns or label_col == text_col:
150
- label_col = [c for c in df.columns if c != text_col][0]
151
- print(f"Using '{label_col}' as label column.")
152
-
153
- # ---------- 2. Train (repeats if accuracy is low and you choose other columns) ----------
154
- while True:
155
- if path:
156
- sub = df[[text_col, label_col]].dropna()
157
- pairs = list(zip(sub[text_col].astype(str), sub[label_col].astype(str)))
158
- random.shuffle(pairs)
159
- pairs = pairs[:MAX_SAMPLES]
160
- print(f"\nText column: {text_col} | Label column: {label_col}")
161
- else:
162
- pairs = SAMPLE
163
-
164
- max_words = words_limit([t for t, _ in pairs])
165
- class_names = sorted(set(label for _, label in pairs))
166
- data = [(tokenize(t, max_words), class_names.index(l)) for t, l in pairs]
167
- data = [(words, l) for words, l in data if words]
168
- print("Classes:", class_names)
169
- print("Words kept per sentence:", max_words)
170
-
171
- if not data:
172
- print("No usable sentences in this column.")
173
- text_col, label_col, changed = ask_columns(df, text_col, label_col)
174
- if not changed:
175
- raise SystemExit("Nothing to train on.")
176
- continue
177
-
178
- # Vocabulary and trees
179
- vocab = {"<unk>": 0}
180
- for words, _ in data:
181
- for w in words:
182
- vocab.setdefault(w, len(vocab))
183
-
184
- trees = [(build_tree([vocab[w] for w in words]), label) for words, label in data]
185
- split = int(len(trees) * 0.8)
186
- train_data, test_data = (trees, trees) if len(trees) < 50 else (trees[:split], trees[split:])
187
- print("Vocabulary size:", len(vocab), "| Train:", len(train_data), "| Test:", len(test_data))
188
- print("Example tree:", train_data[0][0])
189
-
190
- model = RecursiveNN(len(vocab), hidden_dim=32, num_classes=len(class_names))
191
- optimizer = optim.Adam(model.parameters(), lr=0.01)
192
- criterion = nn.CrossEntropyLoss()
193
-
194
- for epoch in range(EPOCHS):
195
- model.train()
196
- random.shuffle(train_data)
197
- total_loss = 0
198
- for tree, label in train_data:
199
- optimizer.zero_grad()
200
- loss = criterion(model(tree).unsqueeze(0), torch.tensor([label]))
201
- loss.backward()
202
- optimizer.step()
203
- total_loss += loss.item()
204
- if (epoch + 1) % 5 == 0:
205
- print(f"Epoch {epoch + 1:02d}/{EPOCHS} | Loss: {total_loss / len(train_data):.4f}")
206
-
207
- model.eval()
208
- test_acc = sum(predict(model, tree) == label for tree, label in test_data) / len(test_data)
209
- print(f"Test Accuracy: {test_acc * 100:.2f}%")
210
- if not path or test_acc >= MIN_ACCURACY:
211
- break
212
- text_col, label_col, changed = ask_columns(df, text_col, label_col)
213
- if not changed:
214
- break
215
-
216
- # ---------- 3. Final results ----------
217
- print(f"\nTest Accuracy: {test_acc * 100:.2f}%")
218
-
219
- print("\nSample predictions:")
220
- for tree, label in test_data[:5]:
221
- print("Tree:", tree)
222
- print("Actual:", class_names[label], "| Predicted:", class_names[predict(model, tree)])
223
- print("-" * 40)
224
-
225
- # ---------- 4. Classify your own sentence ----------
226
- sentence = input("Type a sentence to classify (Enter to skip): ").strip()
227
- if sentence:
228
- ids = [vocab.get(w, 0) for w in tokenize(sentence, max_words)] or [0]
229
- tree = build_tree(ids)
230
- print("Tree:", tree)
231
- print("Predicted:", class_names[predict(model, tree)])
@@ -1,132 +0,0 @@
1
- # PCA vs Linear Autoencoder - works with any numeric CSV
2
- # Both reduce the data to k dimensions; a linear autoencoder learns the same
3
- # subspace as PCA, so their reconstruction errors should be almost equal.
4
- # The numeric columns are picked automatically (ID-like, constant and text columns
5
- # are dropped, missing values filled with the median), and k is chosen automatically
6
- # as the smallest number of components that explains at least 90% of the variance.
7
- # Press Enter to use synthetic data.
8
- import numpy as np
9
- import pandas as pd
10
- import matplotlib.pyplot as plt
11
- from sklearn.decomposition import PCA
12
- from sklearn.datasets import make_blobs
13
- from sklearn.preprocessing import StandardScaler
14
- from tensorflow.keras.models import Sequential
15
- from tensorflow.keras.layers import Input, Dense
16
- from tensorflow.keras.optimizers import Adam
17
-
18
- VARIANCE_TO_KEEP = 0.90 # k = fewest components explaining at least this much variance
19
-
20
-
21
- # ---------- helpers ----------
22
- def read_csv(path):
23
- """Read a CSV with any separator (, ; tab |) and encoding."""
24
- with open(path, encoding="latin-1") as f:
25
- first_line = f.readline()
26
- sep = max([",", ";", "\t", "|"], key=first_line.count)
27
- try:
28
- df = pd.read_csv(path, sep=sep)
29
- except UnicodeDecodeError:
30
- df = pd.read_csv(path, sep=sep, encoding="latin-1")
31
- df = df.loc[:, ~df.columns.astype(str).str.startswith("Unnamed")]
32
- return df.dropna(axis=1, how="all")
33
-
34
-
35
- def is_id(col):
36
- name = str(col.name).lower()
37
- return (name in ("id", "index") or name.endswith("_id")
38
- or (pd.api.types.is_integer_dtype(col) and col.nunique() == len(col)))
39
-
40
-
41
- def numeric_features(df):
42
- """Keep numeric, non-ID, non-constant columns and fill missing values with the median."""
43
- keep = [c for c in df.columns
44
- if pd.api.types.is_numeric_dtype(df[c]) and not is_id(df[c]) and df[c].nunique() > 1]
45
- X = df[keep].copy()
46
- return X.fillna(X.median()), keep
47
-
48
-
49
- # 1. Load data
50
- path = input("Enter CSV file path or press Enter for synthetic data: ").strip().strip('"')
51
- if path:
52
- df = read_csv(path)
53
- print(df.head())
54
- print("Shape:", df.shape)
55
- df, used = numeric_features(df)
56
- print("Numeric columns used:", used)
57
- if len(used) < 2:
58
- raise SystemExit("PCA needs at least 2 usable numeric columns - this CSV does not have them.")
59
- X = df.values
60
- else:
61
- X, _ = make_blobs(n_samples=1000, n_features=10, centers=3, random_state=42)
62
-
63
- X = StandardScaler().fit_transform(X).astype("float32")
64
- n_features = X.shape[1]
65
-
66
- # Choose k automatically from a full PCA
67
- cumulative = np.cumsum(PCA().fit(X).explained_variance_ratio_)
68
- k = int(np.searchsorted(cumulative, VARIANCE_TO_KEEP - 1e-9) + 1)
69
- k = max(1, min(k, n_features))
70
- print(f"Using {k} components (explains {cumulative[k - 1] * 100:.2f}% of variance)")
71
- print("Data shape:", X.shape, "| Components:", k)
72
-
73
- # 2. PCA
74
- pca = PCA(n_components=k)
75
- X_pca = pca.fit_transform(X)
76
- pca_mse = np.mean((X - pca.inverse_transform(X_pca)) ** 2)
77
- print("\nPCA Explained Variance Ratio:", pca.explained_variance_ratio_.round(4))
78
- print("Total Explained Variance:", round(pca.explained_variance_ratio_.sum(), 4))
79
-
80
- # 3. Linear autoencoder: n_features -> k -> n_features, no activation functions
81
- autoencoder = Sequential([
82
- Input(shape=(n_features,)),
83
- Dense(k, use_bias=False, name="encoder"),
84
- Dense(n_features, name="decoder"),
85
- ])
86
- autoencoder.compile(optimizer=Adam(learning_rate=0.01), loss="mse")
87
- history = autoencoder.fit(X, X, epochs=200, batch_size=64, verbose=0)
88
-
89
- encoder = Sequential([Input(shape=(n_features,)), autoencoder.get_layer("encoder")])
90
- latent = encoder.predict(X, verbose=0)
91
- ae_mse = np.mean((X - autoencoder.predict(X, verbose=0)) ** 2)
92
- print("\nAutoencoder latent shape:", latent.shape)
93
- print("Decoder weight (factor loading) shape:", autoencoder.get_layer("decoder").get_weights()[0].shape)
94
-
95
- # 4. Compare
96
- print(f"\nPCA Reconstruction MSE: {pca_mse:.4f}")
97
- print(f"Autoencoder Reconstruction MSE: {ae_mse:.4f}")
98
-
99
- # 5. Plots
100
- plt.figure(figsize=(7, 4))
101
- plt.plot(history.history["loss"])
102
- plt.axhline(pca_mse, color="red", linestyle="--", label="PCA MSE")
103
- plt.title("Autoencoder Training Loss")
104
- plt.xlabel("Epoch")
105
- plt.ylabel("MSE")
106
- plt.legend()
107
- plt.grid(True)
108
- plt.show()
109
-
110
- plt.figure(figsize=(7, 4))
111
- plt.bar(range(1, k + 1), pca.explained_variance_ratio_)
112
- plt.title("PCA Explained Variance Ratio")
113
- plt.xlabel("Principal Component")
114
- plt.ylabel("Explained Variance Ratio")
115
- plt.grid(axis="y")
116
- plt.show()
117
-
118
- plt.figure(figsize=(7, 4))
119
- plt.bar(["PCA", "Linear Autoencoder"], [pca_mse, ae_mse])
120
- plt.title("Reconstruction Error Comparison")
121
- plt.ylabel("Mean Squared Error")
122
- plt.grid(axis="y")
123
- plt.show()
124
-
125
- if k >= 2:
126
- fig, axes = plt.subplots(1, 2, figsize=(11, 4))
127
- axes[0].scatter(X_pca[:, 0], X_pca[:, 1], s=8)
128
- axes[0].set_title("PCA: first 2 components")
129
- axes[1].scatter(latent[:, 0], latent[:, 1], s=8, color="orange")
130
- axes[1].set_title("Autoencoder: first 2 latent factors")
131
- plt.tight_layout()
132
- plt.show()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes