Classify rows using given weights w and bias b (no training). For each row: z = dot(w,x)+b; p = sigmoid(z); class = 1 if p>=0.5 else 0. Library: NumPy matrix multiply X@w+b, then scipy.special.expit and threshold. RESULT: list of predicted classes (0/1).

By hand

w=[1.0,−1.0], b=0.0. X=[[2,1],[1,3],[4,2]]. z: 2−1=1, 1−3=−2, 4−2=2. p: 0.7311, 0.1192, 0.8808. Threshold 0.5 → classes: 1, 0, 1.

naive.py
Replay: real traced execution (multi-file project)
import math
w = [1.0, -1.0]
b = 0.0
X = [[2, 1], [1, 3], [4, 2]]
classes = []
for row in X:
    z = w[0] * row[0] + w[1] * row[1] + b
    p = 1 / (1 + math.exp(-z))
    c = 1 if p >= 0.5 else 0
    classes.append(c)
print('RESULT:', classes)
  1. import math

    1import math2w = [1.0, -1.0]
  2. w ← [1.0, -1.0]

    1import math2w = [1.0, -1.0]3b = 0.0
    values this step[1.0, -1.0]w
  3. b ← 0.0

    2w = [1.0, -1.0]3b = 0.04X = [[2, 1], [1, 3], [4, 2]]
    values this step0.0b
  4. X ← [[2, 1], [1, 3], [4, 2]]

    3b = 0.04X = [[2, 1], [1, 3], [4, 2]]5classes = []
    values this step[[2, 1], [1, 3], [4, 2]]X
  5. classes ← []

    4X = [[2, 1], [1, 3], [4, 2]]5classes = []6for row in X:
    values this step[]classes
  6. row ← [2, 1]

    5classes = []6for row in X:7    z = w[0] * row[0] + w[1] * row[1] + b
    values this step[2, 1]row
  7. z ← 1.0

    6for row in X:7    z = w[0] * row[0] + w[1] * row[1] + b8    p = 1 / (1 + math.exp(-z))
    values this step1.0z
  8. p ← 0.7310585786300049

    7z = w[0] * row[0] + w[1] * row[1] + b8p = 1 / (1 + math.exp(-z))9c = 1 if p >= 0.5 else 0
    values this step0.7310585786300049p
  9. c ← 1

    8p = 1 / (1 + math.exp(-z))9c = 1 if p >= 0.5 else 010classes.append(c)
    values this step1c
  10. classes ← [1]

    9    c = 1 if p >= 0.5 else 010    classes.append(c)11print('RESULT:', classes)
    values this step[] [1]classes
  11. row ← [1, 3]

    5classes = []6for row in X:7    z = w[0] * row[0] + w[1] * row[1] + b
    values this step[2, 1] [1, 3]row
  12. z ← -2.0

    6for row in X:7    z = w[0] * row[0] + w[1] * row[1] + b8    p = 1 / (1 + math.exp(-z))
    values this step1.0 -2.0z
  13. p ← 0.11920292202211755

    7z = w[0] * row[0] + w[1] * row[1] + b8p = 1 / (1 + math.exp(-z))9c = 1 if p >= 0.5 else 0
    values this step0.7310585786300049 0.11920292202211755p
  14. c ← 0

    8p = 1 / (1 + math.exp(-z))9c = 1 if p >= 0.5 else 010classes.append(c)
    values this step1 0c
  15. classes ← [1, 0]

    9    c = 1 if p >= 0.5 else 010    classes.append(c)11print('RESULT:', classes)
    values this step[1] [1, 0]classes
  16. row ← [4, 2]

    5classes = []6for row in X:7    z = w[0] * row[0] + w[1] * row[1] + b
    values this step[1, 3] [4, 2]row
  17. z ← 2.0

    6for row in X:7    z = w[0] * row[0] + w[1] * row[1] + b8    p = 1 / (1 + math.exp(-z))
    values this step-2.0 2.0z
  18. p ← 0.8807970779778823

    7z = w[0] * row[0] + w[1] * row[1] + b8p = 1 / (1 + math.exp(-z))9c = 1 if p >= 0.5 else 0
    values this step0.11920292202211755 0.8807970779778823p
  19. c ← 1

    8p = 1 / (1 + math.exp(-z))9c = 1 if p >= 0.5 else 010classes.append(c)
    values this step0 1c
  20. classes ← [1, 0, 1]

    9    c = 1 if p >= 0.5 else 010    classes.append(c)11print('RESULT:', classes)
    values this step[1, 0] [1, 0, 1]classes
  21. for row in X:

    5classes = []6for row in X:7    z = w[0] * row[0] + w[1] * row[1] + b
  22. stdout ← RESULT: [1, 0, 1]

    10    classes.append(c)11print('RESULT:', classes)
    values this stepRESULT: [1, 0, 1]stdout

With NumPy

X @ w + b computes all dot products in one vectorized step. expit applies sigmoid element-wise; list comprehension thresholds at 0.5.

library.py
import numpy as np
from scipy.special import expit
from dalib.display import set_display
set_display()

w = np.array([1.0, -1.0])
b = 0.0
X = np.array([[2, 1], [1, 3], [4, 2]])
z = X @ w + b
raw_probs = expit(z)
probs = [round(float(p), 4) for p in raw_probs]
classes = [1 if float(p) >= 0.5 else 0 for p in raw_probs]
print('z scores:', [round(float(v), 4) for v in z])
print('probs:', probs)
print('RESULT:', classes)
z scores: [1.0, -2.0, 2.0]
probs: [0.7311, 0.1192, 0.8808]
RESULT: [1, 0, 1]

Implementation notes

  • Weights are given, not trained — this lesson isolates the predict step. Training (e.g. gradient descent on log-loss) is a separate concern.
  • The linear score z = dot(w,x)+b is the same as in linear regression; sigmoid converts it to a probability. Cross-reference: normal-equation-1d (ch03) for the linear-score part.
  • Threshold 0.5 corresponds to z=0 (s(0)=0.5). Different thresholds trade precision against recall — not shown here.
  • X @ w requires X as a 2D numpy array and w as a 1D array; the result is a 1D array of scores, one per row.
  • Cross-reference: sigmoid-function (this chapter) for the activation; sklearn's LogisticRegression.predict_proba wraps the same computation after fitting.