#P3648. 第2题-异常检测算法
-
1000ms
Tried: 11
Accepted: 8
Difficulty: 4
所属公司 :
阿里
时间 :2025年9月11日-阿里云算法岗
-
算法标签>PCA
第2题-异常检测算法
解题思路
核心方法
-
标准化:将
train与test按行拼接后,用StandardScaler一次性fit_transform,得到标准化矩阵Z_all(避免因分别拟合造成的数据偏移)。 -
PCA降维与重构:在
Z_all上用PCA(n_components=1, svd_solver="full", random_state=42)拟合,分别对Z_all做transform → inverse_transform得到重构矩阵Z_hat_all。 -
误差与阈值:
- 训练部分重构误差:对
Z_all的训练行计算 ei=∑j(Zij−Z^ij)2。 - 阈值 T:取训练误差的第 95 百分位数。
- 判别:对测试样本误差 etest 若 ≤T 输出
0,否则输出1。
- 训练部分重构误差:对
-
输出:仅输出测试部分标签,单行 JSON 数组,如
[0, 1](逗号后带空格)。
代码实现
Python
import sys, json
import numpy as np
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
def main():
s = sys.stdin.read().strip()
data = json.loads(s)
train = np.array(data["train"], dtype=float)
test = np.array(data["test"], dtype=float)
# 基本校验:至少二维特征,且 train/test 维度一致
assert train.ndim == 2 and test.ndim == 2
assert train.shape[1] == test.shape[1] and train.shape[1] >= 2
# 1) 拼接后一次性标准化
X_all = np.vstack([train, test])
scaler = StandardScaler()
Z_all = scaler.fit_transform(X_all) # 避免偏移:train+test 一次性 fit_transform
# 2) PCA=1 维,拟合在拼接的标准化数据上
pca = PCA(n_components=1, svd_solver="full", random_state=42)
Z_proj = pca.fit_transform(Z_all) # 在 Z_all 上 fit
Z_hat_all = pca.inverse_transform(Z_proj) # 标准化空间的重构
# 3) 误差:在标准化空间计算
errs = np.sum((Z_all - Z_hat_all) ** 2, axis=1)
# 4) 阈值:训练部分的第95百分位
n = train.shape[0]
T = float(np.percentile(errs[:n], 95)) # 第95百分位
# 5) 测试样本标签:e_test <= T -> 0,否则 1
test_errs = errs[n:]
y = (test_errs > T).astype(int).tolist()
# 6) 输出:单行 JSON,逗号后带空格
print(json.dumps(y, ensure_ascii=False))
if __name__ == "__main__":
main()
题目内容
请在仅使用 numpy/pandas/scikit−learn 的前提下,实现一个基于 PCA 重构误差的异常检测算法,对测试样本判定“正常 (0) /异常 (1) ”。
1.读取数据
-
train:二维列表,只含数值特征(无标签)
-
test:二维列表,与 train 同维度
2.标准化
-
使用 StandardScaler
-
必须将 train 和 test 拼接后一次性 fit_transform,以避免数据偏移
3.降维&重构
-
PCA 降维,你可能会用到的固定参数:n_components=1,svd _solver=“full”,random _state=42
-
在拼接后的标准化数据上 fit 后,再分别 transform/inverse_transform 获得重构样本
4.重构误差与阀值
-
对训练部分计算 ei=∑j(xij−x^ij)2
-
阈值 T 取第 95 百分位
-
判别准则:
$\text { label }=\left\{\begin{array}{ll}0, & e_{\text {test }} \leq T \\1, & e_{\text {test }}>T\end{array}\right.$
5.结果输出
-
仅输出 test 部分的预测标签序列 (0/1)
-
单行 JSON 数组,如 [0,1]
-
顺序须与输入 test 保持一致
输入描述
标准输入仅一行 JSON ,示例
{
"train":[[0,0],[0.1,0],[0,-0.1],[0.05,0.05]],
"test":[[0.04,0.02],[3,3]]
}
-
题目要求至少二维特征
-
所有值为整数/浮点数,无空行
输出描述
仅输出一行:[0,1]
-
长度等于测试样本数
-
合法 JSON,逗号后带空格
补充说明
为确保通过测试用例,允许使用 numpy/pandas/scikit−learn
样例1
输入
{"train":[[0,0],[0.1,0],[0,-0.1],[0.05,0.05],[0.2,0.1],[0.1,-0.1]],"test":[[0.05,0],[0.2,-0.6],[0.1,0.1],[0.2,0]]}
输出
[0, 0, 0, 0]