#P3871. 第2题-磁盘故障检测的特征工程
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 406
            Accepted: 54
            Difficulty: 7
            
          
          
          
                       所属公司 : 
                              华为
                                
            
                        
              时间 :2025年10月10日(留学生)-AI岗
                              
                      
          
 
- 
                        算法标签>模拟          
 
第2题-磁盘故障检测的特征工程
解题思路
- 
输入解析:从标准输入读取一整行(或多行拼接)数字序列。每 19 个数字为一个样本,共有 N 个样本。将数据按列重排,得到 19 列,每列长度为 N。
- Python:优先尝试 
literal_eval解析为列表,失败则按空白分割;同时兼容逗号分隔。 - C++/Java:读取整段文本,替换换行/逗号为空格后用输入流解析为 
double。 
 - Python:优先尝试 
 - 
统计指标(逐列计算,采用总体定义,即分母为 n):
- 均值:μ=n1∑xi
 - 最大值 / 最小值
 - 极差:ptp=max−min
 - 方差:σ2=n1∑(xi−μ)2
 - 标准差:σ=σ2
 - 偏度(总体三阶标准化矩):
 
 

- 峰度(Fisher过度峰度,均匀分布为负)
 

- 当 σ=0(整列常数)时,规定 
skew=0、kurt=0。 - 输出:按列从 0 到 18,依次输出
mean_i max_i min_i ptp_i std_i var_i skew_i kurt_i,保留两位小数并以空格分隔。 
复杂度分析
- 设样本数为 N,特征列数固定为 F=19。
 - 时间复杂度:两趟扫描/列(先均值,再高阶矩)为 O(NF),其中 F 常数,可视为 O(N)。
 - 空间复杂度:除读入数据外,仅用常数级临时变量,O(1)(若按列临时拷贝,仍为 O(N) 以内)。
 
代码实现
Python
# -*- coding: utf-8 -*-
# 题意:从 stdin 读入若干浮点数,每 19 个为一条样本,按列计算 8 项总体统计量并输出两位小数。
import sys, math
from ast import literal_eval
COLS = 19
def compute_col_stats(col):
    """对单列数据计算 mean, max, min, ptp, std, var, skew, kurt(总体 & Fisher 过度峰度)"""
    n = len(col)
    # 基本量
    s = sum(col)
    mu = s / n
    cmax = max(col)
    cmin = min(col)
    ptp = cmax - cmin
    # 二/三/四阶中心矩
    m2 = 0.0
    m3 = 0.0
    m4 = 0.0
    for x in col:
        d = x - mu
        d2 = d * d
        m2 += d2
        m3 += d2 * d
        m4 += d2 * d2
    var = m2 / n
    std = math.sqrt(var)
    if std == 0.0:
        skew = 0.0
        kurt = 0.0
    else:
        skew = (m3 / n) / (std ** 3)
        kurt = (m4 / n) / (std ** 4) - 3.0
    return (mu, cmax, cmin, ptp, std, var, skew, kurt)
def main():
    text = sys.stdin.read().strip()
    nums = []
    if not text:
        print("")  # 无输入时输出空行
        return
    # 优先尝试 literal_eval(如输入为 Python 列表/嵌套列表)
    parsed = None
    try:
        parsed = literal_eval(text)
    except Exception:
        parsed = None
    if isinstance(parsed, (list, tuple)):
        # 可能是嵌套列表,做扁平化
        def flat(it):
            for v in it:
                if isinstance(v, (list, tuple)):
                    for u in flat(v):
                        yield float(u)
                else:
                    yield float(v)
        nums = list(flat(parsed))
    else:
        # 兼容逗号/换行/多空格
        text = text.replace(',', ' ')
        for tok in text.split():
            nums.append(float(tok))
    # 计算样本数
    if len(nums) % COLS != 0:
        # 默认输入合法;这里宽容处理,截断到最近的整样本
        total = (len(nums) // COLS) * COLS
        nums = nums[:total]
    n = len(nums) // COLS
    # 按列计算
    out = []
    for j in range(COLS):
        col = [nums[j + i * COLS] for i in range(n)]
        out.extend(compute_col_stats(col))
    # 按要求格式化输出(两位小数,空格分隔)
    print(' '.join(f"{x:.2f}" for x in out))
if __name__ == "__main__":
    main()
Java
// 题意:读取一行/多行数值,每19个为一条样本;逐列计算总体统计量并输出两位小数(ACM风格)。
import java.io.*;
import java.util.*;
import java.math.*;
public class Main {
    // 计算单列统计(总体定义 & Fisher过度峰度)
    static double[] stats(double[] col) {
        int n = col.length;
        double sum = 0.0, cmax = -Double.MAX_VALUE, cmin = Double.MAX_VALUE;
        for (double v : col) {
            sum += v;
            if (v > cmax) cmax = v;
            if (v < cmin) cmin = v;
        }
        double mu = sum / n;
        double m2 = 0.0, m3 = 0.0, m4 = 0.0;
        for (double v : col) {
            double d = v - mu;
            double d2 = d * d;
            m2 += d2;
            m3 += d2 * d;
            m4 += d2 * d2;
        }
        double var = m2 / n;
        double std = Math.sqrt(var);
        double skew, kurt;
        if (std == 0.0) {
            skew = 0.0; kurt = 0.0;
        } else {
            skew = (m3 / n) / Math.pow(std, 3);
            kurt = (m4 / n) / Math.pow(std, 4) - 3.0;
        }
        double ptp = cmax - cmin;
        return new double[]{mu, cmax, cmin, ptp, std, var, skew, kurt};
    }
    public static void main(String[] args) throws Exception {
        final int COLS = 19;
        // 读入所有文本,替换逗号/换行为空格,再用流解析为 double
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sbAll = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sbAll.append(line).append(' ');
        }
        String raw = sbAll.toString().replace(',', ' ');
        StringTokenizer st = new StringTokenizer(raw);
        ArrayList<Double> list = new ArrayList<>();
        while (st.hasMoreTokens()) {
            list.add(Double.parseDouble(st.nextToken()));
        }
        int total = (list.size() / COLS) * COLS; // 宽容截断
        double[] a = new double[total];
        for (int i = 0; i < total; i++) a[i] = list.get(i);
        int n = total / COLS;
        StringBuilder out = new StringBuilder();
        Locale.setDefault(Locale.US); // 确保小数点为'.'
        for (int j = 0; j < COLS; j++) {
            double[] col = new double[n];
            for (int i = 0; i < n; i++) {
                col[i] = a[i * COLS + j];
            }
            double[] r = stats(col);
            for (int k = 0; k < r.length; k++) {
                if (out.length() > 0) out.append(' ');
                out.append(String.format(Locale.US, "%.2f", r[k]));
            }
        }
        System.out.print(out.toString());
    }
}
C++
// 题意:读取若干浮点数,每19个为一条样本;逐列计算总体统计量(skew 用总体三阶矩,kurt 为Fisher过度峰度)。
#include <bits/stdc++.h>
using namespace std;
static inline double normZero(double x) {
    // 避免打印 -0.00
    return (fabs(x) < 1e-12) ? 0.0 : x;
}
array<double,8> stats(const vector<double>& col) {
    int n = (int)col.size();
    double sum = 0.0, cmax = -1e308, cmin = 1e308;
    for (double v : col) {
        sum += v;
        if (v > cmax) cmax = v;
        if (v < cmin) cmin = v;
    }
    double mu = sum / n;
    double m2 = 0.0, m3 = 0.0, m4 = 0.0;
    for (double v : col) {
        double d = v - mu;
        double d2 = d * d;
        m2 += d2;
        m3 += d2 * d;
        m4 += d2 * d2;
    }
    double var = m2 / n;
    double stdv = sqrt(var);
    double skew = 0.0, kurt = 0.0;
    if (stdv != 0.0) {
        skew = (m3 / n) / (stdv * stdv * stdv);
        kurt = (m4 / n) / (stdv * stdv * stdv * stdv) - 3.0;
    }
    double ptp = cmax - cmin;
    return {mu, cmax, cmin, ptp, stdv, var, skew, kurt};
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    const int COLS = 19;
    // 读取所有内容,替换逗号/换行为空格,再二次解析
    string all((istreambuf_iterator<char>(cin)), istreambuf_iterator<char>());
    for (char& ch : all) {
        if (ch == '\n' || ch == '\r' || ch == ',') ch = ' ';
    }
    istringstream iss(all);
    vector<double> nums;
    double x;
    while (iss >> x) nums.push_back(x);
    int total = (int)(nums.size() / COLS) * COLS; // 宽容截断至整样本
    nums.resize(total);
    int n = (total == 0) ? 0 : total / COLS;
    vector<double> out; out.reserve(19 * 8);
    cout.setf(std::ios::fixed);
    cout << setprecision(2);
    for (int j = 0; j < COLS; ++j) {
        vector<double> col;
        col.reserve(n);
        for (int i = 0; i < n; ++i) col.push_back(nums[i * COLS + j]);
        auto r = stats(col);
        for (double v : r) {
            if (!out.empty()) cout << ' ';
            cout << fixed << setprecision(2) << normZero(v);
            out.push_back(v); // 仅用于控制空格输出
        }
    }
    return 0;
}
        题目内容
输入是磁盘检测中使用的典型的 "SMART" 数据集的部分信息,请根据下面的特征工程,提取相关特征。
特征工程的处理过程如下:
- 读取输入数据:
 
- 从标准输入读取一行数据,将其拆分成一个浮点数列表。
 
- 计算统计特征指标:
 
- 
对个数据特征,计算以下统计指标:
 - 
均值 (Mean):计算每列数据的平均值。
 - 
最大值 (Max):找出每列中的最大值。
 - 
最小值 (Min):找出每列中的最小值。
 - 
极差 (Ptp):计算每列的最大值与最小值之差。
 - 
标准差 (Std):计算每列数据的标准差,反映数据的高程度。
 - 
方差 (Var):计算每列数据的方差,反映数据的离散程度。
 - 
偏度 (Skew):计算数据的偏度,反映数据分布的不对称性。
 - 
峰度 (Kurt):计算数据的峰度,反映数据分布的程度。
统计指标计算公式: 1.均值 (Mean):计算列据的平均值。
公式:means(sum of all values)/number of values
2.最大值 (Max):找出每列中的最大值。
3.最小值 (Min):找出每列中的最小值。
4.极差 (Ptp):计算每列的最大值与最小值之差。
公式:ptp=max−min
5.标准差 (Std) :计算每列数据的标准差,反映数据的离散程度。
公式:std=sqrt(variance)
6.方差 (Var):计算每列数据的方差,反映数据的离散程度。
公式:variance=mean of squared difierences from the Mean
7.偏度 (Skew):计算数据的偏度,反映数据分布的不对称性。
公式:skewness=(sum((x−mean)3)/n)/std3
8.峰度 (Kurt):计算数据的峰度,反映数据分布的陡峭程度。
公式:kurtosis=(sum((x−mean)4)/n)/std4−3
 
- 输出结果:
 
- 将所有统计指标按顺序排列
 
输入描述
输入数据为一行,包含多个样本信息,其中米格样本是 19 个浮点数,代表不同的存储设备指标。
每个样本的数据描述如下:
数据含义 说明
时间戳 Unix 时间戳(秒级或毫秒级)
容量 存储设备的总容量(字节)
已用容量 存储设备的已用容量(字节)
空闲容量 存储设备的空闲容量(字节)
读取操作计数 单位时间内完成的读取操作次数
写入操作计数 单位时间内完成的写入操作次数
读取吞吐量 读取数据的吞吐量(字节/秒)
写入吞吐量 写入数据的吞吐量(字节/秒)
读取延迟 读取操作的平均延迟(毫秒)
写入延迟 写入操作的平均延迟(毫秒)
读取错误计数 单位时间内发生的读取错误次数
写入错误计数 单位时间内发生的写入错误次数
硬盘温度 硬盘的当前温度(摄氏度)
转速 硬盘的转速 (RPM)
读取带宽 读取操作的带宽 (MB/s)
写入带宽 写入操作的带宽 (MB/s)
读取队列深度 读取操作的队列深度
写入队列深度 写入操作的队列
深度硬盘健康状态 硬盘的健康状态
输出描述
输出结果格式:
1、统计结果以一行输出,包含所有统计指标,按以下题序列,便用空格作为分隔符:
mean_0 max_0 min_0 ptp_0 std_0 var_0 skew_0 kurt 0 mean_1 max_1 min_1 ptp_1 std_1 var_1 skew_1 kurt_1... mean_18 max_18 min_18 ptp_18 std_18 var_18 skew_18 kurt_18
2、每个统计指标保留 2 位小数,便于阅读和理解。
样例1
输入
1623456000 1000000.0 800000.0 200000.0 100.0 200.0 500.0 1000.0 10.0 20.0 0.0 0.0 40.0 7200.0 50.0 100.0 5.0 10.0 0.0 1623456001 1000000.0 800000.0 200000.0 100.0 200.0 500.0 1000.0 10.0 20.0 0.0 0.0 40.0 7200.0 50.0 100.0 5.0 10.0 0.0 1623456002 1000000.0 800000.0 200000.0 100.0 200.0 500.0 1000.0 10.0 20.0 0.0 0.0 40.0 7200.0 50.0 100.0 5.0 10.0 0.0 1623456003 1000000.0 800000.0 200000.0 100.0 200.0 500.0 1000.0 10.0 20.0 0.0 0.0 40.0 7200.0 50.0 100.0 5.0 10.0 0.0 1623456004 1000000.0 800000.0 200000.0 100.0 200.0 500.0 1000.0 10.0 20.0 0.0 0.0 40.0 7200.0 50.0 100.0 5.0 10.0 0.0
输出
1623456002.00 1623456004.00 1623456000.00 4.00 1.41 2.00 0.00 -1.30 1000000.00 1000000.00 1000000.00 0.00 0.00 0.00 0.00 0.00 800000.00 800000.00 800000.00 0.00 0.00 0.00 0.00 0.00 200000.00 200000.00 200000.00 0.00 0.00 0.00 0.00 0.00 100.00 100.00 100.00 0.00 0.00 0.00 0.00 0.00 200.00 200.00 200.00 0.00 0.00 0.00 0.00 0.00 500.00 500.00 500.00 0.00 0.00 0.00 0.00 0.00 1000.00 1000.00 1000.00 0.00 0.00 0.00 0.00 0.00 10.00 10.00 10.00 0.00 0.00 0.00 0.00 0.00 20.00 20.00 20.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 40.00 40.00 40.00 0.00 0.00 0.00 0.00 0.00 7200.00 7200.00 7200.00 0.00 0.00 0.00 0.00 0.00 50.00 50.00 50.00 0.00 0.00 0.00 0.00 0.00 100.00 100.00 100.00 0.00 0.00 0.00 0.00 0.00 5.00 5.00 5.00 0.00 0.00 0.00 0.00 0.00 10.00 10.00 10.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
说明
输入样本是 10 个,每个样本的内容是 19 列特征:样本 1− 特征 0 样本 2− 特征 2 ... 样本 1 特征 18 样本 2− 特征 0 ... 样本 2− 特征 18 ... 样本 10− 特征 0 样本 10− 特征 18
输出是每个特征的度量值:特征 0− 均值 特征 0− 最大值 ... 特征 0− 峰度 特征 1− 均值 特征 1− 最大值 … 特征 1− 峰度 ... 特征 18− 均值 特征 18− 最大值 … 特征 18− 峰度
提示
输入样本解释:
1、实际用例中,输入无注释,仅数值
2、实际用例中,多个样本拼接成一行输入,用户需要自己隔离样本( 19 个特征为一个样本)
输出结果解释:
1、实际输出中,仅需保留数值,(参考样例的输出解释)
2、结果显示小数点后 2 位