当前位置:首页 > Python 工业工具 > 正文内容

数据类型:一个Lot ID引发的20万损失事故

数据类型:一个Lot ID引发的20万损失事故

一、问题背景:Lot ID格式错误导致晶圆混淆

去年冬天,我们FAB发生了一起严重的在制品混淆事故。

事故经过

11月15日下午3点,ETCH工序的工程师小李在MES系统里录入一批新的Lot。按照我们的命名规则,Lot ID应该是`FAB-ETCH-2026-001`,表示FAB ETCH工序2026年第1批。

但是小李觉得"001"前面的两个0没必要,就写成了`FAB-ETCH-2026-1`。

问题出现

系统认为这是两个不同的Lot:

  • `FAB-ETCH-2026-001`:已经在制,25片晶圆正在ETCH
  • `FAB-ETCH-2026-1`:新录入,系统分配了新的在制品编号

结果第二批晶圆被错误派工到了IMP工序,而第一批晶圆还在ETCH。

损失统计

| 项目 | 数量 |

|------|------|

| 混淆晶圆数量 | 25片 |

| 返工成本 | 12万 |

| 工时损失 | 3天 |

| 客户交期延误 | 5天 |

| 总损失 | 约20万 |

根本原因分析

事后复盘,我们发现了三个层面的原因:

1. 系统层面:MES的Lot ID字段设计成了VARCHAR,但没有做格式校验

2. 流程层面:没有Lot ID命名规范的培训和检查

3. 技术层面:开发工程师对数据类型理解不足——Lot ID应该是字符串,系统不应该把它当数字处理

这个事故让我意识到:数据类型不只是编程基础知识,更是工程实践中的关键细节。

这篇文章,我用半导体FAB的真实场景,带你深入理解Python的四大基础数据类型:

  • 字符串(str):所有标识符的正确类型
  • 数字(int/float):计数和测量的区分
  • 布尔值(bool):状态表达的规范
  • None:缺失值的正确处理

---

二、技术原理:为什么数据类型如此重要?

2.1 数据类型的本质

数据类型决定了三个关键问题:

| 问题 | 说明 | 示例 |

|------|------|------|

| 存储空间 | 数据占用多少内存 | int: 28字节, str: 49+字节 |

| 取值范围 | 数据可以是什么值 | bool: True/False, int: 任意整数 |

| 操作方式 | 可以对数据做什么 | 数字可以加减,字符串可以拼接 |

为什么Python需要数据类型?

假设Python没有数据类型,会发生什么:

```python

如果没有类型区分...

a = "001" # 这是字符串还是数字?

b = 1 # 能和a相加吗?

如果自动转换

a + b = "002"? # 还是 "0011"? 还是报错?

实际Python的行为

a = "001"

b = 1

a + b # TypeError: 不能把字符串和数字相加

```

Python通过类型系统,在代码运行前就能发现潜在的错误,而不是等到生产环境才暴露问题。

2.2 Python的四大基础数据类型

2.2.1 字符串(str)

字符串是文本数据,用引号包围。

在半导体场景中,几乎所有标识符都应该用字符串

```python

✓ 正确:标识符用字符串

lot_id = "FAB-ETCH-2026-001"

equip_id = "AMAT-ETCH-01"

process_step = "PHOTO_LITHO_01"

recipe_id = "RECIPE-ETCH-TI-001"

为什么用字符串而不是数字?

原因1:保留前导零

print(001) # 输出: 1(数字,前导零被忽略)

print("001") # 输出: 001(字符串,前导零保留)

原因2:包含非数字字符

print("ETCH-01") # 合法的字符串

print(ETCH-01) # 语法错误

原因3:统一处理

所有标识符都用字符串,代码逻辑统一

```

字符串的核心操作

```python

lot_id = "FAB-ETCH-2026-001"

1. 分割(提取各部分)

parts = lot_id.split("-")

parts = ['FAB', 'ETCH', '2026', '001']

fab = parts[0] # 'FAB'

process = parts[1] # 'ETCH'

year = parts[2] # '2026'

seq = parts[3] # '001'

2. 拼接(生成新的Lot ID)

new_lot_id = f"FAB-{process}-{year}-{int(seq)+1:03d}"

new_lot_id = 'FAB-ETCH-2026-002'

3. 查找(判断是否属于某工序)

is_etch = "ETCH" in lot_id # True

is_photo = "PHOTO" in lot_id # False

4. 替换(修改工序名)

new_lot = lot_id.replace("ETCH", "PHOTO")

new_lot = 'FAB-PHOTO-2026-001'

5. 格式化(标准化输出)

为什么用:03d?保证序号始终是3位,不足补零

seq_num = 5

formatted_seq = f"{seq_num:03d}" # '005'

```

2.2.2 数字(int和float)

Python有两种数字类型:

整数(int):用于计数

```python

整数:不可分割的计数单位

wafer_count = 25 # 一个Lot有25片Wafer

defect_count = 3 # 缺陷数量

lot_count = 150 # 当月产量(Lot)

operator_count = 12 # 操作员人数

为什么Wafer数量用int而不是float?

因为Wafer是不可分割的,不存在25.5片晶圆

```

浮点数(float):用于测量

```python

浮点数:可测量的连续值

temperature = 85.5 # 温度(℃)

pressure = 1.23 # 压力(Torr)

thickness = 1250.5 # 厚度(Å)

etch_rate = 3200.75 # 刻蚀速率(Å/min)

为什么温度用float?

因为温度是连续变化的,可以是任意小数

```

整数 vs 浮点数的陷阱

```python

陷阱1:整数除法

a = 7

b = 3

print(a / b) # 2.3333333333333335(浮点数除法)

print(a // b) # 2(整数除法,向下取整)

陷阱2:浮点数精度

print(0.1 + 0.2) # 0.30000000000000004(不是精确的0.3!)

print(0.1 + 0.2 == 0.3) # False!

为什么会有精度问题?

浮点数在计算机中用二进制表示,有些小数无法精确表示

类似于十进制无法精确表示1/3 = 0.333...

解决方案:使用Decimal处理精度要求高的场景

from decimal import Decimal

a = Decimal('0.1')

b = Decimal('0.2')

print(a + b) # Decimal('0.3')

print(a + b == Decimal('0.3')) # True

半导体场景:良率计算需要精确

yield_rate = Decimal('98.5') / Decimal('100')

print(yield_rate) # Decimal('0.985')

```

2.2.3 布尔值(bool)

布尔值只有两个值:`True`和`False`。

在半导体场景中,布尔值用于表示状态

```python

✓ 正确:状态用布尔值

is_online = True # 设备在线

is_alarm = False # 有报警

is_rework = False # 需要返工

is_held = True # 已Hold

is_qualify = True # 已Qualify

为什么不用0和1?

原因1:可读性

if is_online: # 一目了然

pass

if status == 1: # 1是什么意思?需要查文档

原因2:类型安全

is_online = True

is_online = 2 # 如果是bool类型,赋值2会被警告

原因3:语义明确

def check_status(is_online, is_alarm):

# 参数名和类型都清楚表达含义

return is_online and not is_alarm

```

布尔运算

```python

布尔运算:and, or, not

is_online = True

is_alarm = False

is_maintenance = False

设备就绪条件:在线 且 无报警 且 无维护

is_ready = is_online and not is_alarm and not is_maintenance

设备异常条件:有报警 或 在维护

is_issue = is_alarm or is_maintenance

取反

is_normal = not is_issue

```

2.2.4 None(空值)

None表示"没有值"或"缺失数据"。

在半导体场景中,None用于表示数据缺失

```python

✓ 正确:缺失用None

measurement = None # 测量数据未上传

recipe_id = None # Recipe未分配

operator_id = None # 操作员未签到

为什么不用空字符串或0?

场景:厚度测量

thickness_1 = 0 # 厚度是0?还是未测量?

thickness_2 = None # 明确表示:未测量

thickness_3 = "" # 空字符串?厚度不应该是字符串

thickness_4 = None # 明确表示:缺失

判断是否缺失

if measurement is None: # ✓ 正确:用is判断

print("数据缺失")

if measurement == None: # ⚠ 不推荐:==可能被重载

print("数据缺失")

if not measurement: # ✗ 错误:0和空字符串也会进入

print("数据缺失") # 可能误判

```

2.3 类型检查与转换

类型检查

```python

方法1:type()

lot_id = "FAB-001"

print(type(lot_id)) #

方法2:isinstance()(推荐)

print(isinstance(lot_id, str)) # True

print(isinstance(lot_id, int)) # False

为什么推荐isinstance?

isinstance支持继承关系检查

print(isinstance(True, int)) # True!bool是int的子类

```

类型转换

```python

字符串 → 数字

wafer_count_str = "25"

wafer_count = int(wafer_count_str) # 25

thickness_str = "1250.5"

thickness = float(thickness_str) # 1250.5

数字 → 字符串

seq = 1

lot_id = f"FAB-{seq:03d}" # "FAB-001"

布尔转换

status = "True"

is_online = status.lower() == "true" # True

注意:空值转换

int(None) # TypeError!

float(None) # TypeError!

```

---

三、实战案例:设计一个健壮的Lot数据结构

3.1 需求分析

我们需要在MES系统中存储一个Lot的完整信息:

| 字段 | 类型 | 示例 | 说明 |

|------|------|------|------|

| lot_id | str | FAB-ETCH-2026-001 | Lot唯一标识 |

| process | str | ETCH | 当前工序 |

| wafer_count | int | 25 | Wafer数量(1-25) |

| thickness | float | 1250.5 | 平均厚度(Å) |

| is_completed | bool | False | 是否完成 |

| remark | str或None | None | 备注(可选) |

3.2 错误示范

```python

✗ 错误示范:类型混乱

def create_lot(lot_id, process, wafer_count, thickness, is_completed, remark):

# 问题1:没有类型检查,传入什么都可以

# 问题2:没有值域检查,wafer_count可以是-100

# 问题3:没有文档,调用者不知道应该传什么类型

return {

'lot_id': lot_id,

'process': process,

'wafer_count': wafer_count,

'thickness': thickness,

'is_completed': is_completed,

'remark': remark,

}

这样调用不会报错,但会产生错误数据

lot = create_lot(

lot_id=1, # 错误:数字而非字符串

process="ETCH",

wafer_count="25", # 错误:字符串而非整数

thickness=1250.5,

is_completed=0, # 错误:数字而非布尔值

remark=""

)

数据进入系统后,后续处理会出问题

例如:lot_id = 1, 查询"WHERE lot_id = '1'" 会失败

```

3.3 正确示范

```python

✓ 正确示范:类型注解 + 验证

from typing import Optional

def create_lot(

lot_id: str,

process: str,

wafer_count: int,

thickness: float,

is_completed: bool,

remark: Optional[str] = None

) -> dict:

"""

创建Lot数据

参数:

lot_id: Lot唯一标识,格式:FAB-工序-年份-序号

process: 当前工序名称

wafer_count: Wafer数量,范围1-25

thickness: 平均厚度(Å),必须大于0

is_completed: 是否完成

remark: 备注(可选)

返回:

Lot数据字典

异常:

TypeError: 类型错误

ValueError: 值域错误

"""

# 类型检查

if not isinstance(lot_id, str):

raise TypeError(f"lot_id应为str,实际为{type(lot_id).__name__}")

if not isinstance(wafer_count, int):

raise TypeError(f"wafer_count应为int,实际为{type(wafer_count).__name__}")

if not isinstance(thickness, (int, float)):

raise TypeError(f"thickness应为数字,实际为{type(thickness).__name__}")

if not isinstance(is_completed, bool):

raise TypeError(f"is_completed应为bool,实际为{type(is_completed).__name__}")

# 值域检查

if not lot_id.startswith("FAB-"):

raise ValueError(f"lot_id格式错误,应以'FAB-'开头")

if wafer_count < 1 or wafer_count > 25:

raise ValueError(f"wafer_count应在1-25之间,实际为{wafer_count}")

if thickness <= 0:

raise ValueError(f"thickness应大于0,实际为{thickness}")

# 构建数据

return {

'lot_id': lot_id,

'process': process,

'wafer_count': wafer_count,

'thickness': float(thickness), # 统一转为float

'is_completed': is_completed,

'remark': remark,

}

调用示例

lot = create_lot(

lot_id="FAB-ETCH-2026-001",

process="ETCH",

wafer_count=25,

thickness=1250.5,

is_completed=False,

remark=None

)

```

---

四、完整代码:Lot数据验证工具

```python

"""

Lot数据验证工具

功能:验证Lot数据的类型和值域,防止错误数据进入系统

适用于:MES数据录入、数据导入、API接口验证

"""

from typing import Optional, Dict, Any, List, Tuple

from dataclasses import dataclass

from enum import Enum

class ProcessType(Enum):

"""工序类型枚举"""

PHOTO = "PHOTO"

ETCH = "ETCH"

IMP = "IMP"

CVD = "CVD"

PVD = "PVD"

CMP = "CMP"

WET = "WET"

@dataclass

class LotData:

"""

Lot数据类

为什么用dataclass?

1. 自动生成__init__、__repr__等方法

2. 类型注解清晰

3. 支持默认值

"""

lot_id: str

process: str

wafer_count: int

thickness: float

is_completed: bool = False

remark: Optional[str] = None

class LotValidator:

"""Lot数据验证器"""

# 类常量:业务规则

MIN_WAFER_COUNT = 1

MAX_WAFER_COUNT = 25

MIN_THICKNESS = 0.1

MAX_THICKNESS = 10000.0

LOT_ID_PREFIX = "FAB-"

LOT_ID_PATTERN = r"^FAB-[A-Z]+-\d{4}-\d{3}$"

def __init__(self):

self.errors: List[str] = []

self.warnings: List[str] = []

def validate(self, data: Dict[str, Any]) -> Tuple[bool, List[str], List[str]]:

"""

验证Lot数据

返回: (是否有效, 错误列表, 警告列表)

"""

self.errors = []

self.warnings = []

self._validate_lot_id(data.get('lot_id'))

self._validate_process(data.get('process'))

self._validate_wafer_count(data.get('wafer_count'))

self._validate_thickness(data.get('thickness'))

self._validate_is_completed(data.get('is_completed'))

self._validate_remark(data.get('remark'))

return len(self.errors) == 0, self.errors, self.warnings

def _validate_lot_id(self, lot_id: Any):

"""验证Lot ID"""

import re

if lot_id is None:

self.errors.append("lot_id: 不能为空")

return

if not isinstance(lot_id, str):

self.errors.append(f"lot_id: 应为str,实际为{type(lot_id).__name__}")

return

if not lot_id.startswith(self.LOT_ID_PREFIX):

self.errors.append(f"lot_id: 应以'{self.LOT_ID_PREFIX}'开头")

return

if not re.match(self.LOT_ID_PATTERN, lot_id):

self.warnings.append(f"lot_id: 格式不符合规范 {self.LOT_ID_PATTERN}")

def _validate_process(self, process: Any):

"""验证工序"""

if process is None:

self.errors.append("process: 不能为空")

return

if not isinstance(process, str):

self.errors.append(f"process: 应为str,实际为{type(process).__name__}")

return

valid_processes = [p.value for p in ProcessType]

if process not in valid_processes:

self.warnings.append(f"process: '{process}'不在标准工序列表中")

def _validate_wafer_count(self, count: Any):

"""验证Wafer数量"""

if count is None:

self.errors.append("wafer_count: 不能为空")

return

if not isinstance(count, int):

# 如果是float但值是整数,给出警告

if isinstance(count, float) and count.is_integer():

self.warnings.append(f"wafer_count: 应为int,实际为float(建议转为int)")

else:

self.errors.append(f"wafer_count: 应为int,实际为{type(count).__name__}")

return

if count < self.MIN_WAFER_COUNT or count > self.MAX_WAFER_COUNT:

self.errors.append(

f"wafer_count: 应在{self.MIN_WAFER_COUNT}-{self.MAX_WAFER_COUNT}之间,"

f"实际为{count}"

)

def _validate_thickness(self, thickness: Any):

"""验证厚度"""

if thickness is None:

self.errors.append("thickness: 不能为空")

return

if not isinstance(thickness, (int, float)):

self.errors.append(f"thickness: 应为数字,实际为{type(thickness).__name__}")

return

if thickness < self.MIN_THICKNESS or thickness > self.MAX_THICKNESS:

self.warnings.append(

f"thickness: {thickness}Å 超出常规范围 "

f"({self.MIN_THICKNESS}-{self.MAX_THICKNESS}Å)"

)

def _validate_is_completed(self, is_completed: Any):

"""验证完成状态"""

if is_completed is None:

self.errors.append("is_completed: 不能为空")

return

if not isinstance(is_completed, bool):

self.errors.append(f"is_completed: 应为bool,实际为{type(is_completed).__name__}")

def _validate_remark(self, remark: Any):

"""验证备注"""

if remark is None:

return # 备注可以为空

if not isinstance(remark, str):

self.errors.append(f"remark: 应为str或None,实际为{type(remark).__name__}")

return

if len(remark) > 500:

self.warnings.append(f"remark: 长度{len(remark)}超过建议上限500")

使用示例

if __name__ == '__main__':

validator = LotValidator()

# 测试数据

test_data = {

'lot_id': 'FAB-ETCH-2026-001',

'process': 'ETCH',

'wafer_count': 25,

'thickness': 1250.5,

'is_completed': False,

'remark': None,

}

is_valid, errors, warnings = validator.validate(test_data)

print(f"验证结果: {'通过' if is_valid else '失败'}")

if errors:

print(f"错误: {errors}")

if warnings:

print(f"警告: {warnings}")

```

这段代码的设计思路

1. 使用dataclass:简洁地定义数据结构,自动生成方法

2. 使用枚举:工序类型标准化,防止拼写错误

3. 分层验证:类型检查 → 值域检查 → 业务规则检查

4. 错误分级:errors(必须修复)和warnings(建议修复)

5. 配置化:业务规则作为类常量,便于维护

---

五、效果对比:类型规范 vs 类型混乱

我们在MES系统改造前后做了对比:

| 维度 | 改造前 | 改造后 | 提升 |

|------|--------|--------|------|

| 数据错误率 | 5.2% | 0.3% | -94% |

| 数据录入返工次数 | 12次/周 | 0.5次/周 | -96% |

| 查询失败次数 | 8次/周 | 0次/周 | -100% |

| 新人培训时间 | 3天 | 4小时 | -94% |

| Bug定位时间 | 2小时 | 10分钟 | -92% |

真实案例

改造后一个月,新来的工程师小李在录入数据时,系统自动拦截了以下错误:

```

错误: wafer_count: 应为int,实际为str

值: "25"

建议: 转换为整数 25

```

小李立刻意识到问题,修正后数据正确入库。如果按照改造前的系统,这个错误会进入数据库,后续SPC分析时会报错,排查时间至少30分钟。

---

六、实施建议:建立数据类型规范体系

6.1 数据类型对照表

| 数据类型 | Python类型 | 示例 | 数据库类型 | 说明 |

|---------|-----------|------|-----------|------|

| Lot ID | str | "FAB-ETCH-2026-001" | VARCHAR(20) | 唯一标识,必须字符串 |

| 工序名称 | str | "ETCH" | VARCHAR(10) | 枚举值,规范拼写 |

| Wafer数量 | int | 25 | INT | 范围1-25 |

| 测量值 | float | 1250.5 | DECIMAL(10,2) | 精度要求高的场景用Decimal |

| 设备状态 | bool | True | BOOLEAN | 不用0/1 |

| 备注 | str或None | None | VARCHAR(500) NULL | 可选字段 |

6.2 代码规范

规范1:所有标识符用字符串

```python

✓ 正确

lot_id: str = "FAB-001"

equip_id: str = "AMAT-01"

✗ 错误

lot_id: int = 1 # 前导零会丢失

```

规范2:计数用int,测量用float

```python

✓ 正确

wafer_count: int = 25 # 计数

thickness: float = 1250.5 # 测量

✗ 错误

wafer_count: float = 25.0 # 计数不应该是float

```

规范3:状态用bool,不用0/1

```python

✓ 正确

is_online: bool = True

if is_online:

pass

✗ 错误

status: int = 1

if status == 1: # 1代表什么?

pass

```

规范4:缺失用None,不用空字符串或0

```python

✓ 正确

remark: Optional[str] = None

✗ 错误

remark: str = "" # 空字符串和None语义不同

```

6.3 避坑清单

| 坑 | 表现 | 后果 | 解决方法 |

|---|------|------|---------|

| 字符串数字混淆 | `"001" == 1` 不报错但结果错 | Lot ID匹配失败 | 统一用字符串,加类型检查 |

| 浮点精度问题 | `0.1 + 0.2 != 0.3` | 良率计算错误 | 用Decimal处理财务/精度数据 |

| None判断错误 | `if value:` 把0和None都当False | 数据误判 | 用`if value is None:` |

| 类型转换遗漏 | CSV读取后全是字符串 | 计算错误 | 入库前显式转换 |

| bool是int子类 | `isinstance(True, int) == True` | 类型检查误判 | 用`type(x) is bool`精确判断 |

---

七、进阶方向:Pydantic与数据验证

7.1 当前方案的局限

我们手写的验证器虽然完整,但有一些问题:

  • 每个字段都要写验证逻辑,代码冗余
  • 错误信息格式不统一
  • 没有自动生成API文档

7.2 Pydantic:自动验证利器

Pydantic是Python最流行的数据验证库:

```python

from pydantic import BaseModel, Field, validator

from typing import Optional

from enum import Enum

class ProcessType(str, Enum):

PHOTO = "PHOTO"

ETCH = "ETCH"

IMP = "IMP"

class LotModel(BaseModel):

"""Lot数据模型(使用Pydantic自动验证)"""

lot_id: str = Field(..., regex=r"^FAB-[A-Z]+-\d{4}-\d{3}$")

process: ProcessType

wafer_count: int = Field(..., ge=1, le=25) # ge=大于等于,le=小于等于

thickness: float = Field(..., gt=0) # gt=大于

is_completed: bool = False

remark: Optional[str] = Field(None, max_length=500)

@validator('lot_id')

def validate_lot_id_prefix(cls, v):

if not v.startswith('FAB-'):

raise ValueError('lot_id必须以FAB-开头')

return v

自动验证

lot = LotModel(

lot_id="FAB-ETCH-2026-001",

process="ETCH",

wafer_count=25,

thickness=1250.5

)

自动转换类型

lot = LotModel(

lot_id="FAB-ETCH-2026-001",

process="ETCH",

wafer_count="25", # 字符串自动转int

thickness=1250.5

)

类型错误会抛出详细的异常

ValidationError: 1 validation error for LotModel

wafer_count

value is not a valid integer (type=type_error.integer)

```

Pydantic的优势

  • 自动类型验证和转换
  • 详细的错误信息
  • 自动生成JSON Schema(用于API文档)
  • 与FastAPI等框架无缝集成

7.3 行业趋势

越来越多的半导体企业在推动:

  • 数据契约:前后端、系统间通过Schema定义数据格式
  • API优先:先定义API Schema,再写实现代码
  • 类型安全:从动态类型转向静态类型检查(mypy)

掌握Pydantic,是从"写脚本"到"做工程"的重要一步。

---

写在最后

数据类型看似简单,但很多生产事故的根源都在这里。

一个Lot ID的类型错误,可能导致20万的损失。这不是危言耸听,而是我亲身经历的教训。

希望这篇文章能帮你建立起对数据类型的敬畏之心,写出更健壮的代码。

下一篇预告:我们将学习《列表与字典:存储你的第一个Lot数据》,用容器类型管理复杂的数据结构。

---

你在工作中遇到过数据类型相关的Bug吗?评论区分享你的经历,我来帮你分析原因👇

相关文章

FAB工程师学Python的正确路径(附学习地图)

FAB工程师学Python的正确路径(附学习地图)

FAB工程师学Python的正确路径(附学习地图) 我带过一个实习生,非科班出身,学了3个月Python,第一个月工资就涨了2000。 也有干了5年的工艺工程师,手动导数据画图画了5年,月薪还是那点钱...

Python+半导体数据工具完整自学路线(零基础→项目实战)

Python+半导体数据工具完整自学路线(零基础→项目实战)

Python+半导体数据工具完整自学路线(零基础→项目实战) 经常有人问我:我想学Python做FAB数据分析,从哪里开始? 今天我把完整路线画出来,从零基础到能独立做项目,按这个走,90天能出师。...

SPC/MES/FDC工具全家桶:工程师必备Python脚本合集

SPC/MES/FDC工具全家桶:工程师必备Python脚本合集

SPC/MES/FDC工具全家桶:工程师必备Python脚本合集 我在FAB干了15年,最值钱的东西不是经验,是一个攒了多年的Python工具箱。 今天把这个工具箱的核心部分分享出来,从数据采集到SP...

Python日报自动化:MES数据一键生成Excel报告(附完整源码)

Python日报自动化:MES数据一键生成Excel报告(附完整源码)

Python日报自动化:MES数据一键生成Excel报告(附完整源码) 1. 我的血泪史:每天2小时的日报工作 2018年,我在FAB做整合工程师的时候,每天早上第一件事不是分析数据,而是做日报。从M...

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动

Python设备故障预测:XGBoost让FAB的设备维护从被动到主动 1. 问题背景:被动维修的代价 FAB里最贵的不是设备,是设备宕机造成的产能损失。一台光刻机价值$100M+,停机1小时损失约$...

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码)

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码)

Python晶圆良率分析实战:从数据清洗到可视化(附完整代码) 1. 问题背景:我的第一次良率分析 2016年,我在FAB做工艺工程师的时候,第一次被要求分析一批良率异常。工程师把数据发给我——一个E...