导语
百年德企博世放出真实独家生产场景脱敏数据,邀你为工业 4.0 制造练就 AI 大脑。
目前,由北京智源人工智能研究院联合博世和 biendata 共同发布的“INSPEC 工业大数据质量预测赛”(2019 年 12 月 — 2020 年 4 月)正在火热进行中,总奖金为 10 万元。比赛发布了博世某系列产品近年来的质量检测相关数据,要求选手根据已有产品质检环节记录的相关参数,使用机器学习算法对正在测试的产品进行质量预测,提前判断次品,节省整体检测时间。比赛和数据可于下方链接查看,或点击“阅读原文”,欢迎所有感兴趣的报名读者参赛。
目前,赛事已接近半程,为帮助选手进一步提升模型预测结果,biendata 邀请排行榜前列的 sijinabc 选手分享分数在 0.60 左右的 baseline ,希望可以为大家在数据探索、特征工程、模型选择、参数调优等方面提供参考和思路。此外比赛 Models 专区还有三篇高分 Baseline,欢迎感兴趣的读者查阅。
Baseline 概览
选手 sijinabc 经过对数据的理解,其分类模型将在以下几点假设的基础上建立:(1)对于产品检测的过程数据,不同检测步骤之间互不影响,因此认为检测数据不存在时间序列关系;(2)对于各检测序列中正常的检测数据,不同产品之间的数值差别可以体现产品的不同质量;(3)不同产品的检测序列长度、检测顺序、检测内容不同,模型需有较好的泛化性,注意防止过拟合。
其主要思路为:(1)简化数据表,减小数据维度;(2)建立训练集,其中包括将检测参数序列号(ID_F_PARAMETER_S )顺序排列作为特征名;对应的数值型检测结果(RESULT_VALUE)或参数检测结果(PARAMETER_RESULT_STATE)作为模型特征;产品实例的最终检测结果(PROCESS_RESULT_STATE)作为样本标签;分别取前四个、前十个检测步骤的序列 ID(ID_F_PHASE_S)0~9 对应的检测参数序列及检测结果用于训练模型;识别并删除异常数据。(3)建立二分类模型。该 Baseline 最终线上成绩为 0.6,具体代码实现欢迎查看下文或访问页面(https://biendata.com/models/category/4224/L_notebook/)查看。
Baseline详情
一、赛题引入与问题分析
赛题引入
博世的工厂会对每种产品进行若干工序(产品不同,工序数量和类目也不尽相同)的检测,每道工序中可能包括若干步骤,每道检测步骤会反馈相关结果和参数
若产品检测在各个检测步骤皆为合格,并判定该产品实例为合格;若产品检测在某一步骤反馈不合格,检测流程将于该步骤所在工序停止,并判定该产品实例为不合格
赛题任务:
使用机器学习算法,对正在测试的产品进行质量提前预测,对次品提前进行判断,节省整体检测时间。
分别根据产品前 3 步骤和前10步骤的数据预测该产品是否最终被检测为次品。
问题分析
可体现产品质量的数据为数值型和文字型参数检测结果。
因此,本模型将检测序列ID所对应的检测数值作为特征,将任务转化为二分类问题,利用适当的分类算法进行质量预测。
二、数据探索性分析
经过对数据的理解,分类模型将在以下几点假设的基础上建立:
对于产品检测的过程数据,不同检测步骤之间互不影响,因此认为检测数据不存在时间序列关系;
对于各检测序列中正常的检测数据,不同产品之间的数值差别可以体现产品的不同质量;
不同产品的检测序列长度、检测顺序、检测内容不同,模型需有较好的泛化性,注意防止过拟合。
三、思路分析
1.简化数据表,减小数据维度
2.建立训练集
A.将检测参数序列号(ID_F_PARAMETER_S )顺序排列作为特征名。
B.对应的数值型检测结果(RESULT_VALUE)或参数检测结果(PARAMETER_RESULT_STATE)作为模型特征。
C.产品实例的最终检测结果(PROCESS_RESULT_STATE)作为样本标签。
D.分别取前四个、前十个检测步骤的序列 ID(ID_F_PHASE_S)0~9对应的检测参数序列及检测结果用于训练模型。
E.识别并删除异常数据
3.建立二分类模型
四、代码和代码解释
1.数据清洗:简化数据表,减小数据维度
import os
import xlrd #引入模块
import pandas as pd
import numpy as np
import time
import matplotlib.pyplot as plt
#获取目录文件夹下的文件,文件名后缀为xlsx
def file_name(file_dir):
L=[]
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] == .xlsx :
L.append(os.path.join(root, file))
return L
def readxlsx(path):
print("正在处理:" + path)
workbook = xlrd.open_workbook(path)
#sheet1
sheet1 = workbook.sheet_by_index(0)
rows = sheet1.nrows
#sheet2
sheet2 = workbook.sheet_by_index(1)
rows1 = sheet2.nrows
#sheet3
sheet3 = workbook.sheet_by_index(2)
rows2 = sheet3.nrows
# 将不同sheet的list整理到一个list里
dataslice_out = []
# 拼接list
dataslice_in = []
# 分开存储sheet
dataslice_in1 = []
dataslice_in2 = []
dataslice_in3 = []
for i in range(rows):
# 表头跳过
if(i==0):
continue
else:
dataslice_in1.append(sheet1.cell(i, 3).value)
dataslice_in1.append(sheet1.cell(i, 2).value)
dataslice_in1.append(sheet1.cell(i, 0).value)
dataslice_in1.append(sheet1.cell(i, 1).value)
ID_F_PROCESS = sheet1.cell(i, 0).value
if(len(dataslice_in1)>4):
dataslice_in1 = dataslice_in1[4:]
for j in range(rows1):
if(j==0):
continue
#sheet1 按照ID_F_PROCESS 拼接 sheet2
elif(sheet2.cell(j, 0).value == ID_F_PROCESS):
dataslice_in2.append(sheet2.cell(j, 1).value)
dataslice_in2.append(sheet2.cell(j, 2).value)
dataslice_in2.append(sheet2.cell(j, 3).value)
dataslice_in2.append(sheet2.cell(j, 4).value)
ID_F_PHASE = sheet2.cell(j, 1).value
if(len(dataslice_in2)>4):
dataslice_in2 = dataslice_in2[4:]
for k in range(rows2):
if(k == 0):
continue
# sheet2 按照ID_F_PHASE拼接 sheet3
elif(ID_F_PHASE == sheet3.cell(k, 0).value):
dataslice_in3.append(sheet3.cell(k, 1).value)
dataslice_in3.append(sheet3.cell(k, 2).value)
dataslice_in3.append(sheet3.cell(k, 3).value)
dataslice_in3.append(sheet3.cell(k, 4).value)
dataslice_in3.append(sheet3.cell(k, 5).value)
dataslice_in3.append(sheet3.cell(k, 6).value)
dataslice_in3.append(sheet3.cell(k, 7).value)
dataslice_in3.append(sheet3.cell(k, 8).value)
dataslice_in3.append(sheet3.cell(k, 9).value)
#dataslice_out.append(dataslice_in)
#print(dataslice_in1)
#print(dataslice_in2)
#print(dataslice_in3)
dataslice_in = dataslice_in1 + dataslice_in2 + dataslice_in3
dataslice_out.append(dataslice_in)
dataslice_in3 = []
return dataslice_out
namelist=file_name("D:\baseline\INSPEC_Data\INSPEC_train")
save_path = "D:\baseline\clean\"
for i in range(len(namelist)):
dataslice_out = readxlsx(namelist[i])
df = pd.DataFrame(dataslice_out, columns=[ PRODUCTGROUP_NAME , TYPE_NUMBER , ID_F_PROCESS , PROCESS_RESULT_STATE ,
ID_F_PHASE , PHASE_RESULT_STATE , PHASE_NAME , ID_F_PHASE_S ,
RESULT_STRING , RESULT_VALUE , PARAMETER_RESULT_STATE , LOWER_LIMIT , UPPER_LIMIT , AXIS , SIDE , ID_F_PHASE_S , ID_F_PARAMETER_S ])
file_name = namelist[i].split("\")[-1].split(".")[0]
df.to_csv(save_path+file_name+".csv")
print(save_path+file_name+".csv,处理结束")
(1)清洗后的数据进行预处理、建立训练集
def file_name(file_dir):
L=[]
for root, dirs, files in os.walk(file_dir):
for file in files:
if os.path.splitext(file)[1] == .csv :
L.append(os.path.join(root, file))
return L
# 筛选并保存前十步检测的数据
def general10(path):
print("正在处理:" + path)
data = pd.read_csv(path)
class_mapping = { E : 1, J : 2, S : 3} # 把RESULT_STRING中的字母替换为数字
data[ RESULT_STRING ] = data[ RESULT_STRING ].map(class_mapping)
data[ RESULT_STRING ].fillna(0, inplace=True)
data[ RESULT_VALUE ].fillna(0, inplace=True)
data[ parameters ] = data[ RESULT_STRING ] + data[ RESULT_VALUE ] # 合并检测结果
# 通过 ID_F_PROCESS 分离样本
flag_process = data[ ID_F_PROCESS ]
len_data = len(flag_process)
flag = [-1, ]
for i in range(0, len_data - 1):
# print(flag_process[i],flag_process[i+1])
if flag_process[i + 1] == flag_process[i]:
continue
else:
flag.append(i)
flag.append(len_data)
# print(flag)
x = []
parameter_dataset = [] # 存放每个产品的检测参数
for j in range(0, len(flag) - 1):
# 判断样本标签
result_temp = data[ PROCESS_RESULT_STATE ][flag[j] + 1:flag[j + 1] + 1].unique()
# print(result_temp)
if 2 in result_temp:
label = int(2)
else:
label = int(1)
# print(label)
data_pad = np.zeros(232) # 建立长度为232的特征矩阵(检测序列数最多为232个)
# 提取样本前10个检测步骤对应的检测参数,作为训练数据
num_phase = 9.0
list_phase = data[ ID_F_PHASE_S ][flag[j] + 1:flag[j + 1] + 1].tolist()
if num_phase + 1 in list_phase: # 若原数据中产品有第10步检测
num_temp = flag[j], list_phase.index(num_phase + 1)
id_temp = data["ID_F_PARAMETER_S"][flag[j] + 1:flag[j] + 1 + list(num_temp)[1]].tolist()
if id_temp:
for k in range(0, len(id_temp)):
data_pad[int(id_temp[k]-1)] = data["parameters"][flag[j] + 1 + k] # 将参数放入对应检测参数序列号中
else:
continue
elif num_phase + 1 not in list_phase and label == 2: # 若原数据中产品因故障没有第10步检测
id_temp = data["ID_F_PARAMETER_S"][flag[j] + 1:flag[j + 1] + 1].tolist()
for k in range(0, len(id_temp)):
data_pad[int(id_temp[k]-1)] = data["parameters"][flag[j] + 1 + k]
else:
continue
data_pad = data_pad.tolist()
data_pad.append(label) # 特征+标签
# print(data_pad)
parameter_dataset.append(data_pad)
return parameter_dataset
# 筛选并保存前四步检测的数据
def general4(path):
print("正在处理:" + path)
data = pd.read_csv(path)
class_mapping = { E : 1, J : 2, S : 3} # 把RESULT_STRING中的字母替换为数字
data[ RESULT_STRING ] = data[ RESULT_STRING ].map(class_mapping)
data[ RESULT_STRING ].fillna(0, inplace=True)
data[ RESULT_VALUE ].fillna(0, inplace=True)
data[ parameters ] = data[ RESULT_STRING ] + data[ RESULT_VALUE ] # 合并检测结果
# 通过 ID_F_PROCESS 分离样本
flag_process = data[ ID_F_PROCESS ]
len_data = len(flag_process)
flag = [-1, ]
for i in range(0, len_data - 1):
# print(flag_process[i],flag_process[i+1])
if flag_process[i + 1] == flag_process[i]:
continue
else:
flag.append(i)
flag.append(len_data)
# print(flag)
x = []
parameter_dataset = [] # 存放每个产品的检测参数
for j in range(0, len(flag) - 1):
# 判断样本标签
result_temp = data[ PROCESS_RESULT_STATE ][flag[j] + 1:flag[j + 1] + 1].unique()
# print(result_temp)
if 2 in result_temp:
label = int(2)
else:
label = int(1)
# print(label)
data_pad = np.zeros(232) # 建立长度为232的特征矩阵(检测序列数最多为232个)
# 提取样本前4个检测步骤对应的检测参数,作为训练数据
num_phase = 3.0
list_phase = data[ ID_F_PHASE_S ][flag[j] + 1:flag[j + 1] + 1].tolist()
if num_phase + 1 in list_phase: # 若原数据中产品有第10步检测
num_temp = flag[j], list_phase.index(num_phase + 1)
id_temp = data["ID_F_PARAMETER_S"][flag[j] + 1:flag[j] + 1 + list(num_temp)[1]].tolist()
if id_temp:
for k in range(0, len(id_temp)):
data_pad[int(id_temp[k]-1)] = data["parameters"][flag[j] + 1 + k] # 将参数放入对应检测参数序列号中
else:
continue
elif num_phase + 1 not in list_phase and label == 2: # 若原数据中产品因故障没有第10步检测
id_temp = data["ID_F_PARAMETER_S"][flag[j] + 1:flag[j + 1] + 1].tolist()
for k in range(0, len(id_temp)):
data_pad[int(id_temp[k]-1)] = data["parameters"][flag[j] + 1 + k]
else:
continue
data_pad = data_pad.tolist()
data_pad.append(label) # 特征+标签
# print(data_pad)
parameter_dataset.append(data_pad)
return parameter_dataset
start = time.time()
namelist = file_name("D:\baseline\clean\") # 存放清洗数据的文件夹
datasets = []
for i in range(len(namelist)):
data_sample = general10(namelist[i])
for j in range(len(data_sample)):
datasets.append(data_sample[j])
print(len(datasets))
dataset = np.array(datasets)
np.save("parameter_datasets10.npy", datasets) # 保存前十步数据的训练集
end = time.time()
print( Running time: %s Seconds % (end-start))
start = time.time()
namelist = file_name("D:\baseline\clean\") # 存放清洗数据的文件夹
datasets = []
for i in range(len(namelist)):
data_sample = general4(namelist[i])
for j in range(len(data_sample)):
datasets.append(data_sample[j])
print(len(datasets))
dataset = np.array(datasets)
np.save("parameter_datasets4.npy", datasets) # 保存前四步数据的训练集
end = time.time()
print( Running time: %s Seconds % (end-start))
# 处理验证数据,建立验证集
def general1(path):
print("正在处理:" + path)
data = pd.read_csv(path)
class_mapping = { E : 1, J : 2, S : 3}
data[ RESULT_STRING ] = data[ RESULT_STRING ].map(class_mapping)
data[ RESULT_STRING ].fillna(0, inplace=True)
data[ RESULT_VALUE ].fillna(0, inplace=True)
data[ parameters ] = data[ RESULT_STRING ] + data[ RESULT_VALUE ]
# 通过 Product_ID 分离样本
flag_process = data[ Product_ID ]
len_data = len(flag_process)
flag = [-1, ]
for i in range(0, len_data - 1):
if flag_process[i + 1] == flag_process[i]:
continue
else:
flag.append(i)
flag.append(len_data)
parameter_dataset = [] # 存放每个产品的检测参数
for j in range(0, len(flag) - 1):
data_pad = np.zeros(232)
id_temp = data["ID_F_PARAMETER_S"][flag[j] + 1:flag[j + 1] + 1].tolist()
for k in range(0, len(id_temp)):
if str(id_temp[k]) == nan :
continue
else:
data_pad[int(id_temp[k]-1)] = data["parameters"][flag[j] + 1 + k]
data_pad = data_pad.tolist()
ID = data["Product_ID"][flag[j] + 1]
data_pad.append(ID)
parameter_dataset.append(data_pad)
return parameter_dataset
# 保存十步预测的验证集
datasets = []
data_sample = general1("D:\baseline\INSPEC_Data\INSPEC_validation\validation_predict_11.csv")
for j in range(len(data_sample)):
datasets.append(data_sample[j])
dataset = np.array(datasets)
np.save("parameter_validation10.npy", datasets)
# 保存四步预测的验证集
datasets = []
data_sample = general1("D:\baseline\INSPEC_Data\INSPEC_validation\validation_predict_4.csv")
for j in range(len(data_sample)):
datasets.append(data_sample[j])
dataset = np.array(datasets)
np.save("parameter_validation4.npy", datasets)
检测数据可视化
# 观察每列的数据分布 均值 方差 标准差
test1=np.load( parameter_datasets10.npy ,encoding = "latin1") #加载文件
test2=np.load( parameter_datasets4.npy ,encoding = "latin1") #加载文件
print(test1.shape)
print(test2.shape)
mean_v = []
var_v = []
std_v = []
mean_v1 = []
var_v1 = []
std_v1 = []
for i in range(0,232):
mean_v.append(np.mean(test2[:,i]))
var_v.append(np.var(test2[:,i]))
std_v.append(np.std(test2[:,i],ddof=1))
for i in range(0,232):
mean_v1.append(np.mean(test1[:,i]))
var_v1.append(np.var(test1[:,i]))
std_v1.append(np.std(test1[:,i],ddof=1))
plt.figure(figsize=(15,10))
plt.subplot(3, 2, 1)
plt.plot(mean_v)
plt.title( mean_v )
plt.subplot(3, 2, 3)
plt.plot(var_v)
plt.title( var_v )
plt.subplot(3, 2, 5)
plt.plot(std_v)
plt.title( std_v )
plt.subplot(3, 2, 2)
plt.plot(mean_v1)
plt.title( mean_v1 )
plt.subplot(3, 2, 4)
plt.plot(var_v1)
plt.title( var_v1 )
plt.subplot(3, 2, 6)
plt.plot(std_v1)
plt.title( std_v1 )
(17061, 233)
(17345, 233)
Text(0.5, 1.0, std_v1 )
from sklearn.preprocessing import normalize
from sklearn import model_selection
from sklearn import svm
#加载文件 通过比较,选择前四步数据进行训练
para_4 = np.load( parameter_datasets4.npy ,encoding = "latin1")
# 得到训练集
train_x = np.delete(para_4, [232], axis=1)
# 归一化
train_x = normalize(train_x, axis=0, norm= max )
# 获取标签列
train_y = para_4[:,232]
# 随机划分数据集 比例 7:3
X_train, X_test, Y_train, Y_test = model_selection.train_test_split(
train_x, train_y, test_size=0.3, shuffle=True)
#默认的SVM设置
clf = svm.SVC(gamma= scale )
#训练SVM
clf.fit(X_train, Y_train)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape= ovr , degree=3, gamma= scale , kernel= rbf ,
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
#编写LOSS
def loss(x1,x2):
count = 0
for i in range(len(x1)):
y = x1[i] - x2[i]
if(y==0):
count = count + 1
acc = count/len(x1)
return acc
X_pre = clf.predict(X_test)
acc = loss(X_pre,Y_test)
print(acc)
0.9646425826287471
test3=np.load( parameter_validation10.npy ,encoding = "latin1") #加载文件
print(test3.shape)
print(test3[:,-1])
test4=np.load( parameter_validation4.npy ,encoding = "latin1") #加载文件
print(test4.shape)
print(test4[:,-1])
(3784, 233)
[ 0009bd7eca1d49be8853acd9c9985584 000dce1483704360ba073e7f4a7a5403
0014bbaf6e874dc9b152fdf5f4526a45 … ffb18b508de44ddc9ff31d2c6ad8c738
ffcf41baf4c94a9fbc2422f228704a50 ffe65700075d4605b9b50e12dd72a6e2 ]
(3721, 233)
[ 0001be8b94574ed7af4db414d4d3c95c 0008dd2d4c2447d998d3c916df8bc99b
00220f9371ab4a088d443c13ad1310f0 … fff0bd160c944b998887dbd5f80b3cdd
fff2a8aa82c34436a8e348cdc623296b ffff7b1a4e864ea8b84217fe9e5d7fce ]
# 验证集的处理 最后一列是id 将验证集拼接在一起
def validation_data(x1,x2):
train1 = np.delete(x1, [232], axis=1).tolist()
name1 = x1[:,-1].tolist()
train2 = np.delete(x2, [232], axis=1).tolist()
name2 = x2[:,-1].tolist()
train = train1 + train2
name = name1 + name2
return train,name
import pandas as pd
train,name = validation_data(test4,test3)
train_vali = normalize(train, axis=0, norm= max )
X_valid = clf.predict(train_vali)
c={"id" : name,
"label" : X_valid}#将列表a,b转换成字典
data=pd.DataFrame(c)#将字典转换成为数据框
data.to_csv( Result.csv )
biendata 是知名的国际性大数据竞赛平台,面向全球在校学生、科研人员、企业以及自由职业者开放,期待对人工智能感兴趣的小伙伴能在平台上众多比赛中大展身手,在思维与技术的交流碰撞中激发创新和突破。
友情提示,因涉及到数据下载,强烈建议大家登录 PC 页面报名参加~~
INSPEC 工业检测大数据
智源联合博世发布了 INSPEC 工业检测大数据,该数据集包括某系列产品近年来的质量检测相关数据,其中主要为每个产品质量检测环节各个步骤记录的相关参数,每个步骤都标注检测判定结果,整体数据量在 3w 条左右。相比于类似数据集,本比赛数据具有显著优势和特点。
首先,该数据集来自世界顶尖制造企业真实的工厂生产数据,已经过脱敏处理,尽量还原现实环境中产品检测的工序和流程。其次,INSPEC 工业检测大数据详细记录了检测环节生成的具体产品参数,涵盖产品子家族 ID、实例 ID、检测环节 ID、检测环节结果、检测规格和数值等。丰富的数据维度一方面增强了比赛的难度,另一方面有助于选手打造更加鲁棒的模型。
智源算法大赛
2019 年 9 月,智源人工智能算法大赛正式启动。本次比赛由北京智源人工智能研究院主办,清华大学、北京大学、中科院计算所、旷视、知乎、博世、爱数智慧、国家天文台、晶泰等协办,总奖金超过 100 万元,旨在以全球领先的科研数据集与算法竞赛为平台,选拔培育人工智能创新人才。
研究院副院长刘江也表示:“我们希望不拘一格来支持人工智能真正的标志性突破,即使是本科生,如果真的是好苗子,我们也一定支持。”而人工智能大赛就是发现有潜力的年轻学者的重要途径。
本次智源人工智能算法大赛有两个重要的目的,一是通过发布数据集和数据竞赛的方式,推动基础研究的进展。特别是可以让计算机领域的学者参与到其它学科的基础科学研究中。二是可以通过比赛筛选、锻炼相关领域的人才。
智源算法大赛已发布全部的10个数据集,目前仍有5个比赛(奖金50万)尚未结束。
正在角逐的比赛
智源小分子化合物性质预测挑战赛
https://www.biendata.com/competition/molecule/
智源杯天文数据算法挑战赛
https://www.biendata.com/competition/astrodata2019/
智源-INSPEC 工业大数据质量预测赛
https://www.biendata.com/competition/bosch/
智源-MagicSpeechNet 家庭场景中文语音数据集挑战赛
https://www.biendata.com/competition/magicdata/
智源-高能对撞粒子分类挑战赛
https://www.biendata.com/competition/jet/