#P3436. 第2题-异常检查器
-
ID: 2778
Tried: 48
Accepted: 17
Difficulty: 6
所属公司 :
美团
时间 :2025年8月23日-算法岗
-
算法标签>聚类算法
第2题-异常检查器
思路概述
-
读入数据:从标准输入读取一行 JSON,分别得到
train
与test
的二维数值特征。 -
拼接与标准化:将
train
、test
在样本维度上拼接为整体矩阵X
,对X
使用 一次StandardScaler.fit_transform
完成标准化。 -
DBSCAN 聚类:在标准化后的特征上执行
DBSCAN(eps=0.3, min_samples=3, metric="euclidean", algorithm="auto")
得到原始标签labels
(离群为-1
)。 -
簇重映射(仅针对非
-1
):- 计算每个簇在标准化空间中的质心。
- 按质心第 1 维坐标从小到大排序,得到顺序
l0, l1, ...
。 - 依次重标为
0, 1, 2, ...
;离群点保持-1
。
-
结果输出:仅输出对应于
test
部分的重映射标签,按 单行 JSON 数组 打印(例如[0, -1]
)。
关键细节:
- 标准化必须对合并后的
train+test
一次性fit_transform
;- 质心与排序均在标准化后的坐标系中进行;
- 若所有点均为离群(无簇),直接输出对应位置的
-1
。
Python 代码
import sys
import json
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import DBSCAN
def main():
# 1) 读取输入
raw = sys.stdin.read().strip()
data = json.loads(raw)
train = np.asarray(data["train"], dtype=float)
test = np.asarray(data["test"], dtype=float)
# 2) 拼接与标准化(一次性 fit_transform)
X = np.vstack([train, test])
scaler = StandardScaler()
X_std = scaler.fit_transform(X)
# 3) DBSCAN 聚类
db = DBSCAN(eps=0.3, min_samples=3, metric="euclidean", algorithm="auto")
labels = db.fit_predict(X_std) # shape: (n_samples,)
# 4) 簇标签重映射(保持 -1 不变)
unique_labels = set(labels.tolist())
non_noise = [l for l in unique_labels if l != -1]
mapping = {}
if len(non_noise) > 0:
# 计算各簇质心(在标准化空间中)
centroids = {}
for l in non_noise:
mask = (labels == l)
centroids[l] = X_std[mask].mean(axis=0)
# 按质心第 1 维(索引 0)从小到大排序并建立新标签映射
sorted_labels = sorted(non_noise, key=lambda l: centroids[l][0])
mapping = {old: new for new, old in enumerate(sorted_labels)}
# 应用重映射
remapped = np.array([(-1 if l == -1 else mapping[l]) for l in labels], dtype=int)
# 5) 仅输出 test 部分
n_test = test.shape[0]
test_labels = remapped[-n_test:].tolist()
# 按 JSON 规范打印(逗号后带空格)
print(json.dumps(test_labels))
if __name__ == "__main__":
main()
题目内容
请在仅依赖 numpy/pandas/scikit-learn 的前提下,完成一个基于 DBSCAN 的异常检测器,并对给定测试样本输出聚类结果(正常簇 0,1,2…; 离群点 −1 )。
-
读取数据
-
train 字段:二维列表,元素均为数值特征
-
test 字段:二维列表,特征维度与 train 相同
-
无标签,全为无监督场景
-
-
预处理
-
将 train 与 test 按行拼接得到整体数据集
-
使用 StandardScaler 对所有特征做标准化 (fit_transform一次完成)
-
-
DBSCAN 聚类
- 采用DBSCAN聚类,你可能会用到的参数固定为 eps=0.3,min_samples=3, metric="euclidean", algorithm="auto"
-
簇标签重映射(唯一化输出)
-
设原本的标签集合为 {−1,0,1,…} ,其中 −1 表示离群
-
对所有非 −1 的簇 l :
i.计算簇在标准化特征空间的质心 cl
ii.按质心第一维坐标从小到大排序得到顺序 l0,l1,…
iii. 重新赋值:l0→0,l1→1,...
- 离群点标签保持 −1 不变
-
-
结果输出
-
仅对 test 部分输出重新映射后的标签序列
-
以单行 JSON 数组 输出
-
输入描述
标准输入仅一行 JSON,示例:
{
"train":[[0,0],[0.1,0],[5,5]],
"test":[[0.05,0.05],[9,0]]
}
- 所有数值为整数/浮点数,无空行
输出描述
标准输出仅含一行:[0,−1]
-
数组长度等于测试样本数
-
逗号后须有空格,符合 JSON 规范
补充说明
1.标准化:仅用一次 StandardScaler ;不要对 train、test 分别拟合
2.超参数:eps=0.3,min samples=3 固定
3.为了确保通过测试用例,仅允许使用 numpy / pandas / scikit-learn
样例1
输入
{"train":[[0,0],[0.1,0],[5,5],[5.1,5],[10,0]],"test":[[0.05,0.05],[5.05,5.05],[9,0]]}
输出
[0,1,-1]