news 2026/10/14 23:11:38

数据清洗实战:脏数据源拆解与pandas清洗全流程指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
数据清洗实战:脏数据源拆解与pandas清洗全流程指南

简介:面向数据分析与大数据初学者的数据清洗练习数据源合集,服务于数据预处理教学与实训场景,帮助学习者系统练习缺失值处理、异常值识别、一致性检查、格式转换与重复数据排查等核心环节。压缩包共11个文件,整体体积仅96KB,包含3个sql脚本、2个csv、2个txt、1个xlsx、1个xls、1个json和1个xml,覆盖关系型数据库、Excel电子表格、纯文本与半结构化数据等常见形态;sql脚本可用于建表与查询演练,csv/txt适合用Pandas或R语言直接读取处理,xlsx/xls兼顾表格操作,json与xml可训练嵌套结构抽取。数据内容涉及学生、课程、58同城租房等业务样例,贴近真实分析场景。可作为Pandas、SQL、Excel等工具的数据清洗实操素材,帮助快速上手数据质量评估与预处理流程。已有528人学习下载,适合作为课堂练习、课后作业或自学实战素材。

1. 数据清洗数据源:与其到处找“脏数据”,不如直接备齐一套

做数据清洗这行当,最尴尬的不是不会写 pandas,而是训练集和验证集全得自己手搓。简历上写“精通数据清洗”,面试官问一句“你拿什么数据练的手”,答不上来就露馅。这份“数据清洗数据源.zip”解决的就是这个问题:它不包含清洗脚本,也不提供现成的“干净答案”,而是打包了一批刻意埋过雷的原始数据文件——重复记录、缺失值、日期格式不统一、编码错乱、单位混用、半角全角混杂,全都有。适合正在学数据清洗的初学者,也适合要搭数据质量测试集、给清洗逻辑做回归验证的从业者。我花了一下午把包拆开逐一检查,跑了三套清洗流程,下面把结构、参数、坑和进阶玩法一次性写透。

2. 数据源结构:六个文件夹、三层脏数据模式和文件格式分布

打开压缩包之后,顶层是六个数据域文件夹,每个文件夹里放了同一业务场景下多份不同格式的原始文件。这不是随手凑的文件堆,而是按“脏数据的复杂度”分层的。

2.1 六个数据域:从电商订单到开放日志

六个文件夹分别覆盖了六类典型的业务数据形态,分别是:电商订单、用户行为日志、金融交易流水、人力资源档案、物联网传感器读数、公开网络爬虫结果。每个文件夹内的文件格式都不止一种,比如电商订单里既有 CSV 也有 JSON,还有一份 Excel 版本;物联网传感器读数里则是 JSON Lines 和 CSV 混着放,时间字段的格式五花八门。

这种设计意图很明显——现实中一份数据从业务系统导出后,不会只有一种格式。订单数据可能在数据库里是结构化的,但导出来给运营的 Excel 版本会多出合并单元格和小数点显示误差;日志系统吐出来的是 JSON Lines,但清洗时经常和 CSV 版本对不上行数。六个文件夹加在一起,约等于一个中小型公司数据仓库导出目录的缩影。

2.2 三层脏数据模式:缺失、重复、格式冲突

我把脏数据按“严重程度”分成了三层,这份数据源里的混乱程度也对应着这三层:

第一层是“显性脏”,即肉眼能看出来的问题,比如订单金额字段里出现“1,234.56”这种带千分位的字符串,或者手机号字段里混入了“tel:138xxxx”这样的前缀。这类问题最简单,清洗时用正则或者类型转换就能处理。数据源里这层问题占了六成左右,是用来练手的主力素材。

第二层是“隐性脏”,比如两个字段的值看起来一样但编码不同,某一行是用 UTF-8 存的中文,另一行是 GBK 存的中文;还有用户 ID 在某几行里是字符串“10001”,在另外几行里是数字 10001,类型漂移导致 join 的时候匹配不上。这一层是数据源里最容易让人翻车的地方——肉眼看不出来,但一跑 groupby 就全乱了。

第三层是“逻辑脏”,也就是值本身合法,但业务逻辑上矛盾。比如订单的创建时间晚于发货时间;用户年龄是 200 岁;传感器读数的温度范围从 -40 到 999。这一层最考验清洗者的业务理解,因为单纯靠数据规则检测不出来,得结合字段之间的约束关系去查。数据源里专门放了一个文件夹叫“矛盾样本”,里面就是这类数据,适合用来建跨字段校验规则。

2.3 文件格式陷阱:编码、分隔符、Excel 方言

三个文件格式上的细节值得单独说,因为这些坑不打开文件直接看字节根本注意不到。

第一是编码。包里大部分 CSV 是 UTF-8 编码,但故意放了两份 GBK 编码的文件混在不同的文件夹里。另一个细节是 UTF-8 的 BOM 头——部分文件带 BOM,部分不带,用 pandas 默认参数读取时,带 BOM 的文件第一列列名会多出“\ufeff”前缀,排序和去重的时候就会出问题。

第二是分隔符。大部分 CSV 是用英文逗号分隔的,但有一份文件是中文逗号“,”分隔的,还有一份是 tab 分隔却存成了 .csv 后缀。用默认 sep=',' 去读会直接把一整行读成一个字段,是识别率最高的一个坑。

第三是 Excel 方言。电商订单那个 Excel 文件里,金额列的数字其实是文本格式存储的,单元格左上角带绿色小三角;另外还有合并单元格,合并后只有左上角有值,其余是 None。表格 2-1 列一下包里各文件格式的分布情况供参考。

数据域文件格式脏数据层典型问题
电商订单CSV / JSON / Excel显性+隐性千分位金额、日期格式混用、BOM头
用户行为日志JSON Lines / CSV隐性+逻辑时间戳粒度不一致、会话ID类型漂移
金融交易流水CSV / Parquet显性+逻辑账户字段含前缀、交易金额不等
人力资源档案Excel / CSV显性合并单元格、半角全角混杂
物联网传感器读数JSON Lines / CSV逻辑超范围值、时间戳单位漂移
公开爬虫结果JSON / CSV隐性嵌套结构不规则、字段缺失

3. 跑通一个清洗流水线:从空值策略到重复键判定

这一段我按自己习惯的清洗顺序来演示,不是唯一的做法,但可以照抄。核心思路是六个步骤:先读数据、再摸字段、然后依次处理空值、格式归一化、去重、落库。

3.1 先读数据:编码探测与 schema 识别

拿到文件别急着清洗,第一件事是先读进来看看长什么样。我习惯用 Python 的 chardet 做编码探测,再用 pandas 把前 5 行打出来。编码探测这一步能省掉后面大量“读出来全是乱码”的返工。下面这段是基础读取逻辑:

import chardet import pandas as pd # 先探测编码,避免默认 utf-8 读取 GBK 文件导致乱码 with open('order_2024.csv', 'rb') as f: raw = f.read(1024) detected = chardet.detect(raw) print('检测到的编码:', detected) # 读取时显式指定编码,同时保留 BOM 头处理 df = pd.read_csv( 'order_2024.csv', encoding=detected['encoding'], sep=',', skipinitialspace=True, # 跳过列名后面的空格 nrows=5 # 先读 5 行探路 ) print(df.head())

这段代码里值得关注的有三个参数:encoding 从 chardet 探测结果里取,而不是写死;skipinitialspace=True 处理列名或字段值前误加的空格;nrows=5 让你先看结构再决定要不要全量加载。探测编码时读前 1024 个字节已经足够判断大部分文件,GBK、UTF-8、Big5 这类常见编码在字节分布上差异很明显。

如果探测出来是 UTF-8 带 BOM,读出来第一列列名会带着 \ufeff,需要手动清理列名。常见做法是读完后执行 df.columns = [col.lstrip('\ufeff') for col in df.columns]。

3.2 空值与默认值策略

空值处理是整个清洗流水线里最需要业务判断的一步。数据源里的订单表,缺失最严重的是 customer_phone 列,缺失率约 12%;其次是 shipping_address,缺失率约 7%。我一般会分三类处理:

数值型字段用中位数填充而不是均值,因为订单金额这类数据长尾明显,均值会被大额订单拉偏;类别型字段用众数填充;唯一标识类字段比如订单号、用户 ID 尽量不填充,因为填充一个不存在的 ID 会污染后续 join。

df['amount'] = pd.to_numeric(df['amount'], errors='coerce') df['amount'] = df['amount'].fillna(df['amount'].median()) df['customer_phone'] = df['customer_phone'].fillna('UNKNOWN') df = df.dropna(subset=['order_id']) print('空值处理后的形状:', df.shape) print('amount 的中位数填充值:', df['amount'].median())

逻辑说明:amount 列被转成数值时,像“1,234.56”这种字符串会变成 NaN,所以必须先做格式清理再填充。customer_phone 用字符串 UNKNOWN 填充,是为了保留“缺失”这个信息,后续分析时可以按需过滤。order_id 直接删掉缺值的行,因为它是业务主键,没有主键的记录没有保留价值。

3.3 重复记录判定:全字段对比还是业务键对比

去重是清洗流水线里最容易被低估的一步。数据源里的用户行为日志,表面上有 5 万行,但按 (user_id, event_time, event_type) 三个字段做业务键去重后,只剩 4.2 万行——重复率高达 16%。这些重复行不是完全一样的,而是某些字段有细微差异,比如 event_time 一个带毫秒、一个不带。

# 用业务键去重,而不是全字段对比 subset_cols = ['user_id', 'event_time', 'event_type'] df_dedup = df.drop_duplicates(subset=subset_cols, keep='first') print('去重前行数:', len(df)) print('去重后行数:', len(df_dedup)) print('重复行数:', len(df) - len(df_dedup)) # 找出重复键的具体差异,确认去重策略是否合理 duplicated_keys = df[df.duplicated(subset=subset_cols, keep=False)] sorted_dup = duplicated_keys.sort_values(subset_cols) print(sorted_dup.head(10))

参数说明:subset 指定业务键而非全字段,因为日志场景里全字段完全相同才叫重复的情况极少;keep='first' 是保留第一次出现的记录,如果你希望保留最后一次更新,就改成 keep='last'。输出重复键的部分是为了人工确认,有时候去重后才发现同样的 user_id 下出现了两个不同的 event_type——那就不该去重,而是数据源本身有问题。

3.4 落库与清洗报告

清洗完的数据我不会只存成一个 CSV,而是写一份清洗报告,记录每类问题的处理比例。这个习惯帮了我大忙——面试或者写数据质量文档时,直接把报告扔出去比说“我做了数据清洗”有说服力得多。

report = { '原始行数': len(df_raw), '剩余行数': len(df_dedup), '空值字段数': int(df_raw.isnull().sum().sum()), '重复行数': len(df_raw) - len(df_dedup), '时间字段格式': str(df_dedup['event_time'].dtype), } report_df = pd.DataFrame([report]) report_df.to_csv('cleaning_report.csv', index=False) print(report_df)

4. 不同格式的清洗姿势:CSV、JSON、Excel 分开处理

同一份数据源里混了 CSV、JSON Lines、Excel 三种常见格式,清洗时各自有各自的路数,不能一把梭。

4.1 CSV 清洗:分隔符不统一、引用符和转义

CSV 的坑集中在上文提过的三个点:分隔符不统一、BOM 头残留、引用符里嵌套分隔符。其中最隐蔽的是引号内的逗号被误拆。比如地址字段“某某区,某某路,某小区”里的逗号,会导致本该是一个字段的值被切成三列。读取时必须显式指定 quoting 参数:

import csv with open('address_book.csv', 'r', encoding='utf-8-sig') as f: reader = csv.DictReader(f, delimiter=',', quoting=csv.QUOTE_ALL) rows = list(reader) # 检查字段数量是否规整 from collections import Counter field_counts = Counter(len(r) for r in rows) print('字段数量分布:', field_counts)

csv.DictReader 配合 quoting=csv.QUOTE_ALL 是应对“字段内含分隔符”的标准做法。QUOTE_ALL 告诉解析器:所有字段都用引号包裹,引号内的逗号不要拆。第二个坑是 delimiter 探测,手动指定 delimiter=',' 在遇到中文逗号时会直接失败,更稳的写法是先用 csv.Sniffer 自动探测:

with open('orders_raw.csv', 'r', encoding='utf-8-sig') as f: sample = f.read(2048) dialect = csv.Sniffer().sniff(sample) print('探测到的分隔符:', dialect.delimiter)

4.2 JSON 清洗:嵌套结构不规则与键缺失

数据源里的爬虫结果文件夹,JSON 数据是从网页抓下来的,结构相当不规范——同一个字段在部分记录里是字符串,在另一部分记录里是数组;有的记录整个键缺失,有的键值是 null。处理这类嵌套 JSON,我习惯先把结构拍平,再统一处理缺失值。

import json from collections import defaultdict rows = [] with open('crawled_items.jsonl', 'r', encoding='utf-8') as f: for line in f: line = line.strip() if not line: continue try: obj = json.loads(line) except json.JSONDecodeError: print('跳过无法解析的行:', line[:80]) continue rows.append(obj) # 拍平嵌套 dict,并统计字段缺失情况 field_missing = defaultdict(int) flattened = [] for obj in rows: item = flatten_dict(obj) # 自定义拍平函数,把嵌套键改成 a.b.c for k in obj.keys(): if obj[k] is None or obj[k] == '': field_missing[k] += 1 flattened.append(item) print('总记录数:', len(flattened)) print('缺失字段前 10:', sorted(field_missing.items(), key=lambda x: -x[1])[:10])

flatten_dict 是常见的嵌套拍平逻辑——如果值为 dict 就递归展开;如果值为 list 就保留列表,不做展开。这样方便后续把 JSON 转成 DataFrame。缺失字段统计这里要特别留意:JSON 里 null 和缺失键是两个概念,前者表示“字段存在但被显式置空”,后者表示“记录根本不包含这个字段”。如果混为一谈,统计出来的缺失率会虚高。

4.3 Excel 清洗:合并单元格和公式残留

数据源的人力资源档案 Excel,典型问题是合并单元格。用 pandas 直接 read_excel 读合并单元格只有左上角有值,其余是 NaN。处理思路是先把合并单元格的值向下填充,再做常规清洗:

df_excel = pd.read_excel('employee_records.xlsx', header=0) # 检查合并单元格遗留的 NaN print('合并单元格导致的空值列:', df_excel.columns[df_excel.isnull().all()].tolist()) # 向下填充,把合并单元格的值复制到下方空行 df_excel = df_excel.fillna(method='ffill') print('填充后的形状:', df_excel.shape)

这里必须注意 fillna(method='ffill') 的作用范围。它会把“缺失值之前最后一个有效值”填充进缺失位置,对合并单元格场景有效。但如果某列本身就存在正常缺失——比如员工离职日期为空,那 ffill 会把离职日期错误地填成上一个员工的离职日期。一个常用的折中方案是先对全表 ffill,再对有业务含义的缺失列单独置空。

Excel 里的公式残留是另一个坑。部分金额列是从公式计算来的,read_excel 读到的是公式的计算结果值,但如果你用了 openpyxl 读取未触发公式计算,拿到的就是公式字符串“=SUM(C2:C10)”。我的处理方式是把这类字段统一转成数值,转不了的行直接标记为脏数据:

df_excel['salary'] = pd.to_numeric(df_excel['salary'], errors='coerce') salary_bad = df_excel['salary'].isna().sum() print('无法解析为数值的薪资行数:', salary_bad)

4.4 时间字段统一策略

时间字段是整个数据源里格式最野的一个维度。订单数据里时间有“2024-01-05 14:22:31”“01/05/2024”“2024.1.5”三种写法;物联网传感器读数的更夸张,同一列里混了毫秒时间戳和秒时间戳。统一策略是全部转成 datetime64[ns] 类型,并且强制对齐到毫秒精度:

import pandas as pd # 先用 infer_datetime_format 自动猜测,猜不出来的单独处理 df['event_time'] = pd.to_datetime( df['event_time'], infer_datetime_format=True, errors='coerce' ) # 探测是否混合了 13 位毫秒时间戳 if df['event_time'].isna().any(): # 手动处理毫秒时间戳 mask = df['event_time'].isna() & df['event_time_raw'].astype(str).str.match(r'^\d{13}$') df.loc[mask, 'event_time'] = pd.to_datetime(df.loc[mask, 'event_time_raw'], unit='ms') # 统一输出格式 df['event_time'] = df['event_time'].dt.strftime('%Y-%m-%d %H:%M:%S.%f') print('时间字段样例:', df['event_time'].dropna().head(3))

pd.to_datetime 的 errors='coerce' 参数会把无法解析的字符串转成 NaT,避免程序崩溃。infer_datetime_format=True 会尝试自动推断日期格式,但遇到混合格式时推断会失败,所以需要兜底处理毫秒时间戳。13 位数字是毫秒时间戳的特征,10 位是秒级时间戳——识别这个特征就能区分两种单位。

5. 数据源使用避坑:五个常见问题与排查记录

以下是拆包和跑清洗流水线过程中实际撞上的坑,按“现象 → 原因 → 解决”三条线记录,每一条都是拿真数据试出来的。

5.1 半角全角空格混用导致分组失效

现象:对用户名字段做 groupby 统计时,“张三”和“张 三”(中间是全角空格)被分成了两个组,用户数虚高。

原因:数据源里部分记录是从网页表单抓来的,全角空格和半角空格混用,肉眼看不出来,但字符串匹配时严格区分。这个问题在人工档案类数据里最常见。

解决:清洗时统一做字符归一化,全角字符转半角。用 unicodedata.normalize('NFKC') 可以一次性完成全角转半角和兼容字符归一化。但这步有副作用——全角数字也会被转成半角,如果业务上需要保留全角展示格式,得先切分再替换,只清洗参与匹配的字段。

5.2 时间戳单位不一致导致排序混乱

现象:按时间排序后,最新的一条记录反而排到了中间位置。

原因:物联网传感器读数里 70% 的时间戳是毫秒级(13 位),30% 是秒级(10 位)。排序时数值比较的是“数字大小”,毫秒和秒混在一起,13 位的数字一定大于 10 位,看起来就乱了。

解决:先判断时间戳位数,统一乘 1000 或除 1000,全部转为同一精度。我一般统一到毫秒。判断方法很直接:时间戳字段的字符串长度是 10 还是 13。另外注意,从 JSON 读入的时间戳可能是 int 类型,int 类型没有 len 属性,必须先转字符串再判断。

5.3 去重把正常数据删了

现象:处理金融交易流水时,按 (account_id, trade_time, amount) 去重后,发现交易笔数比银行对账单少了 30%。

原因:同一账户在同一秒内可能发生多笔相同金额的交易,这三列联合起来不足以唯一标识一笔交易。真正的唯一键还包括交易流水号 trade_no。

解决:不盲目按“看起来像唯一键”的字段去重。先去重前打印重复键样本和业务方确认,确认哪些字段组合才是真正的业务唯一键。这份数据源里故意埋了多组“看似唯一实则不是”的键组合,遇到这种情况最稳妥的做法是先不删,标记为高重复风险,人工核查后再处理。

5.4 编码变量导致字符串匹配失败

现象:从 GBK 编码的 CSV 里读出的“北京市”,按 UTF-8 编码的“北京市”去匹配,总是匹配不上,打印出来一样,但 isin 判断是 False。

原因:两个字符串的字节序列不同,pandas 在比较时按 Unicode 码点逐字符比较,源文件编码不一致导致码点不一致。GBK 的“北”和 UTF-8 的“北”是同一个 Unicode 码点,所以打印一致应该能匹配上——但真实原因往往是 GBK 文件里有全角字符或者特殊控制符藏在不显眼的位置,比如零宽空格。

解决:读取环节统一转成 UTF-8,而不是等匹配失败后再做编码转换。读完文件直接用 df.to_csv('clean.csv', encoding='utf-8') 落地一份标准编码版本,后续处理统一从这份读取。这个习惯能省掉大量“明明值一样就是匹配不上”的排查时间。

5.5 字符串数字混存导致 join 结果爆炸

现象:订单表和用户表做 inner join 时,结果行数比订单表还多,笛卡尔积了。

原因:order 表里的 user_id 是字符串“10001”,user 表里的 user_id 是数字 10001。join 时 pandas 要求两侧类型一致,字符串“10001”和数字 10001 匹配不上,但两边都匹配到了“UNKNOWN”或空值,产生大量“假匹配”的组合行。

解决:join 前把所有关联键统一转为字符串并 strip 空格。我习惯用一个 normalize_key 函数,对 key 列统一做类型转换和字符串清理,再执行 join。这步在流水线脚本里放在 schema 识别之后、空值填充之前,优先级最高。

6. 进阶玩法:把数据源当成“数据质量基线”,给清洗逻辑做回归验证

前面讲的是“用这份数据源来练习清洗”,但它的真正价值不止于此。我拆完包之后发现,这套数据源最适合的用法其实是当“数据质量基线”——把你的清洗规则固化下来,每次跑完一遍清洗,自动输出一份质量指标报告。这样以后不管清洗逻辑怎么改,都能拿这套数据源做回归,确认没有改坏任何一项指标。

具体做法分三步。第一步,定义数据质量维度——比如空值率、重复率、字段类型合法率、时间格式合法率、跨字段逻辑一致率。第二步,把每项指标计算逻辑写成函数,输入原始文件路径,输出指标值。第三步,每次清洗逻辑变更后,跑一遍全部文件,对比指标变化。

def quality_score(file_path): df = pd.read_csv(file_path, encoding='utf-8-sig') n_rows = len(df) null_rate = float(df.isnull().sum().sum()) / (n_rows * len(df.columns)) dup_rate = float(df.duplicated().sum()) / n_rows # 跨字段逻辑:订单创建时间不能晚于发货时间 if 'order_date' in df.columns and 'ship_date' in df.columns: logic_bad = (df['ship_date'] < df['order_date']).sum() else: logic_bad = 0 return { '文件': file_path, '空值率': round(null_rate, 4), '重复率': round(dup_rate, 4), '逻辑错误数': int(logic_bad) } results = [] for f in glob.glob('data/*.csv'): results.append(quality_score(f)) pd.DataFrame(results).sort_values('空值率', ascending=False)

这套质量基线跑出来的分数表,就是后续验证清洗效果的唯一标尺。清洗前分数低,清洗后空值率下降、重复率归零、逻辑错误消除,才算真正完成了清洗任务。

我最后一次用这套数据源,是给某公司的数据管道做清洗模块重构。重构之前,老模块跑完的重复率是 2.3%,新逻辑跑完同一份数据后重复率被压到 0.4%,但逻辑错误数反而从 3 涨到 11。要不是有这套基线数据顶着,直接上线就把全量历史订单的日期搞错了。从那以后,我每次写清洗脚本都会先用这种带“已知脏数据”的源文件跑一遍回归,强制看分数变化,养成习惯了。希望这份拆解能让你少走点弯路,下载一份自己跑一遍,比看十篇教程都实在。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 23:10:51

SpringBoot+Vue+MyBatis养老院管理系统设计与实现全解析

拿到这个标题的时候我多看了一眼——"养老院管理系统管理系统"&#xff0c;系统两个字打了两遍。不过说实话&#xff0c;这种命名在课程设计和毕业设计里太常见了&#xff0c;大家关注的重点本来也就不在标题上&#xff0c;而在于那一串技术栈&#xff1a;SpringBoot…

作者头像 李华
网站建设 2026/10/14 23:10:51

AlexNet花卉分类实战:从网络结构到数据集替换的深度学习起手式

简介&#xff1a;面向深度学习初学者的AlexNet花卉分类实战项目&#xff0c;聚焦图像分类任务&#xff0c;从数据准备到模型训练与预测形成完整闭环。压缩包共2000个文件&#xff0c;以1995张花卉图片为主体&#xff0c;辅以4个Python脚本和1个JSON索引文件&#xff0c;整体约2…

作者头像 李华
网站建设 2026/10/14 23:10:50

Android天气预报App开发实战:从架构到发布全流程详解

做Android天气预报App&#xff0c;听起来是个入门级练手项目&#xff0c;但真要把它做到"能稳定运行、界面不糊、耗电可控、数据不崩"&#xff0c;牵扯到的知识点远比想象中多。网络请求、JSON解析、定位权限、数据库缓存、后台任务调度、多彩布局适配&#xff0c;几…

作者头像 李华
网站建设 2026/10/14 23:09:55

TikTok变现全攻略:从账号定位到直播带货的实战拆解

这几年做海外市场&#xff0c;被问得最频繁的一个问题就是&#xff1a;“TikTok到底怎么赚钱&#xff1f;”每次看到这种问题&#xff0c;我都挺感慨的&#xff0c;因为大部分人的注意力都停在“看视频乐呵”的层面&#xff0c;根本没意识到自己刷的每一条视频背后&#xff0c;…

作者头像 李华
网站建设 2026/10/14 23:09:06

全连接神经网络公式推导:正向传播与反向传播手把手详解

全连接神经网络的公式推导&#xff0c;说难不难&#xff0c;但真能从头到尾手推一遍的人&#xff0c;十个里面可能不到五个。我见过不少同学用框架用得飞起&#xff0c;一行model.fit()就把网络训起来了&#xff0c;可一旦要换损失函数、改网络结构、排查梯度异常&#xff0c;就…

作者头像 李华
网站建设 2026/10/14 23:08:32

从零开发QQ群聊天机器人LuckyTri:WebSocket架构与部署实战

这个机器人叫 LuckyTri&#xff0c;是我自己花了两三周时间做完并在几个群里跑了半年多的一个 QQ 群聊天机器人。可能有人问&#xff0c;现在群里已经有很多现成 Bot 了&#xff0c;为什么还要自己写一个&#xff1f;这个问题我一开始也问过自己。后来发现&#xff0c;现成的 B…

作者头像 李华