Skip to content

Commit 2281a23

Browse files
authored
Merge pull request #283 from emharsha1812/main
Addition : ML Problems on Logistic Regression, Cross Entropy Loss, Early stopping
2 parents 873dbf5 + 8a2e184 commit 2281a23

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Binary Classification with Logistic Regression
2+
3+
Logistic Regression is a fundamental algorithm for binary classification. Given input features and learned model parameters (weights and bias), your task is to implement the prediction function that computes class probabilities.
4+
5+
### Mathematical Background
6+
7+
The logistic regression model makes predictions using the sigmoid function:
8+
9+
$\sigma(z) = \frac{1}{1 + e^{-z}}$
10+
11+
where z is the linear combination of features and weights plus bias:
12+
13+
$z = \mathbf{w}^T\mathbf{x} + b = \sum_{i=1}^{n} w_ix_i + b$
14+
15+
### Implementation Requirements
16+
17+
Your task is to implement a function that:
18+
19+
- Takes a batch of samples $\mathbf{X}$ (shape: N × D), weights $\mathbf{w}$ (shape: D), and bias b
20+
- Computes $z = \mathbf{X}\mathbf{w} + b$ for all samples
21+
- Applies the sigmoid function to get probabilities
22+
- Returns binary predictions i.e 0 or 1 using a threshold of 0.5
23+
24+
### Important Considerations
25+
26+
- Handle numerical stability in sigmoid computation
27+
- Ensure efficient vectorized operations using numpy
28+
- Return binary predictions i.e zeroes and ones
29+
30+
### Hint
31+
32+
To prevent overflow in the exponential calculation of sigmoid function, use np.clip to limit z values:
33+
34+
```python
35+
z = np.clip(z, -500, 500)
36+
```
37+
38+
This ensures numerical stability when dealing with large input values.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import numpy as np
2+
3+
def predict_logistic(X: np.ndarray, weights: np.ndarray, bias: float) -> np.ndarray:
4+
5+
z = np.dot(X, weights) + bias
6+
z = np.clip(z, -500, 500) # Prevent overflow in exp
7+
probabilities = 1 / (1 + np.exp(-z))
8+
return (probabilities >= 0.5).astype(int)
9+
10+
def test_predict_logistic():
11+
# Test case 1: Simple linearly separable case
12+
X1 = np.array([[1, 1], [2, 2], [-1, -1], [-2, -2]])
13+
w1 = np.array([1, 1])
14+
b1 = 0
15+
expected1 = np.array([1, 1, 0, 0])
16+
assert np.array_equal(predict_logistic(X1, w1, b1), expected1), "Test case 1 failed"
17+
18+
# Test case 2: Decision boundary case
19+
X2 = np.array([[0, 0], [0.1, 0.1], [-0.1, -0.1]])
20+
w2 = np.array([1, 1])
21+
b2 = 0
22+
expected2 = np.array([1, 1, 0])
23+
assert np.array_equal(predict_logistic(X2, w2, b2), expected2), "Test case 2 failed"
24+
25+
# Test case 3: Higher dimensional input
26+
X3 = np.array([[1, 2, 3], [-1, -2, -3], [0.5, 1, 1.5]])
27+
w3 = np.array([0.1, 0.2, 0.3])
28+
b3 = -1
29+
expected3 = np.array([1, 0, 0])
30+
assert np.array_equal(predict_logistic(X3, w3, b3), expected3), "Test case 3 failed"
31+
32+
# # Test case 4: Single feature
33+
X4 = np.array([[1], [2], [-1], [-2]]).reshape(-1, 1)
34+
w4 = np.array([2])
35+
b4 = 0
36+
expected4 = np.array([1, 1, 0, 0])
37+
assert np.array_equal(predict_logistic(X4, w4, b4), expected4), "Test case 4 failed"
38+
39+
# # Test case 5: Numerical stability test with large values
40+
X6 = np.array([[1000, 2000], [-1000, -2000]])
41+
w6 = np.array([0.1, 0.1])
42+
b6 = 0
43+
result6 = predict_logistic(X6, w6, b6)
44+
assert result6[0] == 1 and result6[1] == 0, "Test case 5 failed"
45+
46+
if __name__ == "__main__":
47+
test_predict_logistic()
48+
print("All test cases passed!")

0 commit comments

Comments
 (0)