Tree-Based & Instance Methods
Chapter: 2.3 Tree-Based & Instance Methods Time limit: 90 minutes Total marks: 60 Instructions: Answer all three questions. Show full derivations. Code may be pseudocode or Python; correctness of logic matters more than syntax. Use notation for math.
Question 1 — Splitting criteria, entropy vs Gini, and a proof (20 marks)
A binary-classification node contains samples with class-1 proportion .
(a) Write the Gini impurity and the Shannon entropy (base 2) for a binary node. Prove that for all , using the inequality . (6)
(b) A dataset of 14 samples has 9 positives and 5 negatives. A candidate feature Wind splits into Weak (8 samples: 6 pos, 2 neg) and Strong (6 samples: 3 pos, 3 neg). Compute the parent entropy, the weighted child entropy, and the information gain to 3 decimals. (6)
(c) Compute the Gini-based weighted impurity of the same split and the Gini gain. State, with numerical justification, whether entropy and Gini agree on this split being an improvement. (4)
(d) Prove that for any node, information gain is non-negative (i.e. entropy is a concave function of , so splitting cannot increase expected impurity). State the geometric argument precisely. (4)
Question 2 — Ensembles: OOB, AdaBoost weight update, and bias–variance (22 marks)
(a) In bootstrap aggregating with training samples, derive the probability that a specific sample is not selected in a bootstrap sample of size , and its limiting value as . State the expected fraction of out-of-bag (OOB) samples. (5)
(b) AdaBoost (discrete, binary labels ): a weak learner has weighted error . Derive the classifier weight and compute it. Then give the weight-update rule and compute the multiplicative factor applied to a correctly classified point and to a misclassified point (before normalization). (6)
(c) Show that after the update in (b), if is the normalization constant, then , and evaluate it for . Explain why minimizing at each round motivates the choice of . (6)
(d) Contrast bagging and boosting in terms of which component of test error (bias vs variance) each primarily reduces, and explain why boosting is more prone to overfitting noisy labels. (5)
Question 3 — KNN, distance geometry, curse of dimensionality (18 marks)
(a) Given points , , compute the Euclidean, Manhattan, and cosine distance () between them. Show all steps. (6)
(b) Write pseudocode for a weighted KNN classifier that weights neighbours by and predicts by weighted majority vote. State the time complexity of one prediction over training points in dimensions. (5)
(c) Curse of dimensionality: for points uniformly distributed in the unit cube , to capture a fraction of the data volume in a hypercubic neighbourhood the edge length must be . Compute for at . Interpret the implication for choosing and for local methods like KNN in high dimensions. (7)
Answer keyMark scheme & solutions
Question 1
(a) ; . (1) Using : . (3) So , i.e. . Since , and in fact one shows holds pointwise (max ratio at endpoints; both equal 0 at and , so ratio ). The tightest constant is , achieved at . (2)
(b) Parent: . . (2) Weak (6/2): . Strong (3/3): . (2) Weighted child . Information gain . (2)
(c) Parent Gini . Weak Gini ; Strong Gini . Weighted . Gini gain . (3) Both entropy gain () and Gini gain () are positive → they agree the split improves purity. (1)
(d) Entropy is concave (second derivative ). Splitting partitions the parent proportion as a convex combination with weights . By Jensen's inequality for concave : , i.e. parent entropy weighted child entropy, so gain . Equality iff all equal. (4)
Question 2
(a) Probability a given sample is NOT chosen in one draw . Over independent draws: . (3) Limit: . Expected OOB fraction (so in-bag). (2)
(b) . (2) Update: . Correct (): factor . Misclassified (): factor . (4)
(c) . Split into correct (total weight ) and wrong (): . Substitute : . (3) At : . (1) is chosen to minimize (set ) because the training-error bound is ; minimizing each greedily tightens the bound → the exact formula. (2)
(d) Bagging averages many high-variance, low-bias trees → primarily reduces variance (decorrelated averaging). Boosting sequentially fits residuals/reweights → reduces bias (builds a strong learner from weak ones). Boosting overfits noisy labels because it up-weights persistently misclassified points; noisy/mislabeled points receive exploding weights and dominate later rounds. (5)
Question 3
(a) Difference . Euclidean . (2) Manhattan . (2) Cosine: ; , . ; cosine distance . (2)
(b) Pseudocode: (3)
predict(x, X_train, y_train, K):
dists = [ (euclid(x, X_train[i]), y_train[i]) for i in range(N) ]
sort dists ascending by distance
neighbours = first K entries
votes = {}
for (d, y) in neighbours:
w = 1/(d + eps)
votes[y] += w
return argmax_c votes[c]
Complexity of one prediction: distance to all points costs ; selecting top- via sort or partial-select . Total . (2)
(c) , :
- : .
- : .
- : . (4) Interpretation: to capture just 1% of data in 100-D you must span 95.5% of each axis — "local" neighbourhoods are no longer local; all points become nearly equidistant, so distance-based ranking of neighbours loses meaning. To keep neighbourhoods local you'd need tiny (unreliable estimates) or huge . Hence KNN degrades badly in high dimensions; dimensionality reduction / feature selection is required. (3)
[
{"claim":"Q1b information gain = 0.048","code":"import math\ndef H(a,b):\n t=a+b; ps=[a/t,b/t]; return -sum(p*math.log2(p) for p in ps if p>0)\nparent=H(9,5); child=(8/14)*H(6,2)+(6/14)*H(3,3); gain=parent-child\nresult = round(gain,3)==0.048"},
{"claim":"Q1c Gini gain approx 0.0306","code":"def G(a,b):\n t=a+b; return 2*(a/t)*(b/t)\np=G(9,5); c=(8/14)*G(6,2)+(6/14)*G(3,3); result = round(p-c,4)==0.0306"},
{"claim":"Q2b alpha = 0.5493 for eps=0.25","code":"import math\neps=0.25; alpha=0.5*math.log((1-eps)/eps); result = round(alpha,4)==0.5493"},
{"claim":"Q2c Zt = 0.8660 for eps=0.25","code":"import math\neps=0.25; Z=2*math.sqrt(eps*(1-eps)); result = round(Z,4)==0.8660"},
{"claim":"Q3a distances: euclid 5, manhattan 7, cosine dist 0.1091","code":"import math\na=[1,2,2]; b=[4,6,2]\neu=math.sqrt(sum((x-y)**2 for x,y in zip(a,b)))\nman=sum(abs(x-y) for x,y in zip(a,b))\ndot=sum(x*y for x,y in zip(a,b)); na=math.sqrt(sum(x*x for x in a)); nb=math.sqrt(sum(x*x for x in b))\ncd=1-dot/(na*nb)\nresult = eu==5 and man==7 and round(cd,4)==0.1091"},
{"claim":"Q3c edge lengths r=0.01","code":"result = round(0.01**(1/10),4)==0.6310 and round(0.01**(1/100),4)==0.9550"}
]