The rough version of the Local Outlier Factor divides a point's reach by its neighbours' average reach. The full formula keeps that idea, but averages over all k neighbours and smooths the distances. Your job is to implement it exactly.
Points are lists of coordinates (any number of dimensions, no two identical), and d(p,o) is the Euclidean distance between them.
- k-distance. kdist(p) is the distance from p to its k-th nearest other point.
- Neighbourhood. N(p) is every other point whose distance from p is at most kdist(p). When several points tie, this can hold more than k points: keep them all.
- Reachability distance from p to one of its neighbours o:
reach(p,o)=max(kdist(o), d(p,o))
This is the smoothing: any point inside o's own k-distance counts as exactly that far from o, so tiny distances inside a crowd don't swing the result.
- Local reachability density, one over the average reach:
lrd(p)=∑o∈N(p)reach(p,o)∣N(p)∣
- Local Outlier Factor, the neighbours' average density compared with p's own:
LOF(p)=∣N(p)∣1o∈N(p)∑lrd(p)lrd(o)
Task: write lof_scores(points, k) returning one LOF per point, in the order given, each rounded to 4 decimal places. You may assume 1≤k< the number of points.
A score near 1 means the point is as crowded as its own neighbours, so it fits its region, however sparse that region is. A score well above 1 means it has far more empty space around it than they do.