尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

无监督学习实战:无标签数据的预处理、聚类与业务解释

无监督学习实战:无标签数据的预处理、聚类与业务解释 我近几年做数据分析时碰到的项目大概有七成以上拿到的第一份数据都是没有标签的。所谓的“无标签”就是每一行数据只有一堆特征没有“正确答案”告诉你它属于哪一类。早期我对这类数据的态度很粗暴——要么硬套一个有监督模型效果一塌糊涂要么就只做做散点图把聚类当成画图工具用。直到后来做用户行为分析、日志文本归类这些实际项目我才慢慢意识到无标签数据不是“没有答案”而是“答案需要你自己去定义”。这篇文章是我“无标签的数据指南”系列的第一篇我会先聊清楚一个核心问题当你拿到一堆没有标签的数据应该从哪儿下手有哪些坑是必须提前避开的以及一条能直接落地的实操流程。适合刚接触数据分析、机器学习或者被无监督学习搞到头大的朋友。1. 无标签数据为什么值得被严肃对待1.1 业务场景比你想的多得多很多人在学校或者网课里学机器学习上来就是逻辑回归、决策树、卷积神经网络数据集全都给你标注好了。但等到真正进入项目你会发现现实世界的数据几乎都是“散装”的。举几个常见的场景。第一个是用户分层。公司后台一条用户记录包含了注册时长、登录频次、消费金额、商品浏览深度但没有人告诉你这个用户是高价值还是流失风险户。你需要自己从数据里找到模式把人群拆成几类再做差异化运营。第二个是日志聚类。服务端每天产生几千万条日志人工看不过来关键词规则又覆盖不全。这时候你把它变成特征向量做无监督聚类异常的那一小簇往往就是事故现场。第三个是文本归类。公司积累了大量工单、评论、对话记录没有打标却需要知道大家都在抱怨什么。关键词硬拆容易漏预训练模型成本又高这时候 TF-IDF 加聚类反而是性价比最高的解法。第四个是异常检测。用户操作行为、机器监控指标、银行流水它们没有“正常/异常”的标签但异常模式往往天然就长在数据密度分布里。用无监督方法去建模可以做到“你不知道要找什么但能把不对劲的捞出来”。这还只是最常见的几种。本质上“没有标签”才是数据的默认状态有标签反而是稀缺资源。如果你只能处理带标签的数据你的分析半径会被卡死在一小撮人工标注过的数据上。1.2 无监督比有监督更需要业务理解有监督学习里标签本身就是“标准答案”模型的任务只是找一条从特征到答案的函数。你的好坏主要由准确率、召回率这些指标来定义指标定了方向就定了。无监督学习不一样。它没有一个可对标的“正确答案”你选什么特征、用什么距离度量、聚成几类、怎么解释每一类每一步都是人来做决策。换句话说无监督学习更像“给数据立规矩”你立的规矩合不合理直接决定了结果的可用性。这也是我见过最多新手翻车的地方。他们拿到数据就标准化、就 KMeans、就画图中间没有任何业务校验。跑出来的簇看着很“数学”放到业务里却完全没法解释。所以在这篇文章里我会反复强调一个观点无标签数据分析的第一步是定目标不是跑算法。1.3 一套通用的处理思路可以先立起来无标签数据的方法论虽然不像有监督那么“自动”但它是有完整路径的。我自己跑过很多轮之后总结下来是五个环节明确业务诉求你是要做分层、找异常、还是做归类这个目标决定了后续每一步。数据清洗与预处理没有标签已经很难了数据里再带着脏值、重复值、缺失值结果基本不能看。特征工程与度量选择无标签数据没有“帮助模型”的说法你的特征表达一定要服务于你想发现的结构。算法与参数适配聚类、降维、密度估计各有各的适用边界不是无脑 KMeans。结果解释与验证聚类完不是结束你需要把每一簇拿出来看特征分布证明这个簇真的“有意义”。这套思路我会在后面的章节里拆开讲其中第二和第三步是最容易卡住的我会多花一点篇幅。2. 拿到数据之后的预处理决定了你后面所有的走向2.1 脏数据是无标签分析的头号杀手有监督学习里一个脏样本可能会被模型当成噪声自动忽略掉但无监督聚类对离群点非常敏感。比如你有一万条用户数据里面有两条来自爬虫的极端值KMeans 的聚类中心可能就被这两条硬生生拉偏你最终得到的簇边界跟真实业务结构差了十万八千里。我做一个电商用户分层项目时遇到过类似的事。特征里有一项是“历史订单金额”绝大多数用户在几千元以内但有几条数据是金额上百万的后来排查是测试账号标准化之后这几条一下子成了坐标系里的“孤岛”KMeans 直接为它们单开了两个簇。原本应该被划到高价值人群的真实用户反而被挤到边缘。所以预处理阶段至少要干以下几件事去重重复样本在聚类里相当于给某些点加权重会扭曲密度估计。去异常不是所有极端值都要删但你要先识别出来再决定是删除、截断还是单独处理。补缺失缺失值不能直接丢因为聚类算法大多不支持空值也不能盲目填充因为填充策略会引入主观偏差。检查量纲不同特征单位相差太大时必须做标准化或者归一化否则欧氏距离会被大数值特征完全主宰。注意删除异常值时务必把删掉的数据单独存一份。我之前因为图省事直接原地清理结果事后想追踪异常来源数据已经没了只能重新跑一遍接口拉数白白浪费时间。2.2 标准化不是可有可无而是必须在无标签场景里“距离”是一切的基础。而大部分距离度量对特征的尺度极其敏感。举个例子一个特征“注册天数”取值范围是 0 到 3650另一个特征“当月登录次数”取值范围是 0 到 30。如果你不标准化算欧氏距离时注册天数的差异会完全掩盖登录次数的差异聚类结果基本上就是“按注册天数撕成几堆”跟你的业务预期可能完全不同。标准化的方式我有几个常用选择Z-score 标准化公式是(x - mean) / std。适合数据近似正态分布的情况也是实践中默认选项。Min-Max 归一化公式是(x - min) / (max - min)。适合你知道特征上下界、且没有极端离群值的情况。RobustScaler用中位数和四分位距来缩放。当你的数据里不可避免存在离群值时这个比 Z-score 稳很多。从实操角度我不会推荐一种标准化打天下。如果你后面要做 PCAZ-score 通常是默认如果你要做 KMeans数据分布比较偏态的话RobustScaler 往往能避免被极端值带偏如果特征本身是“次数”这种长尾分布可以考虑先做对数变换再标准化压缩一下动态范围。2.3 特征筛选宁缺毋滥不是一句空话无标签场景下特征筛选比有监督还棘手。有监督你可以用特征重要性筛选无监督没有目标列很难客观判断哪些特征“有用”。我的经验是分三步走先剔除信息量为零的特征。比如某一列全部是同一个值或者某一列的缺失率超过 80%这种特征留着只会稀释有效信号。再剔除高度相关的特征。两个特征相关系数超过 0.9它们在距离计算中的贡献会被重复放大。比如“消费总金额”和“平均单笔金额×消费笔数”基本上是同一件事同时放进去等于给某个方向偷偷加了权重。最后是根据业务直觉做取舍。这一步最重要。你希望聚类发现的“结构”是什么就保留哪些维度。举个例子如果你的目标是区分“重度用户”和“轻度用户”那么“登录次数”“使用时长”这类强度特征是核心“地域”和“设备型号”如果跟这个目标无关留着反而会把人群切得更碎增加解释难度。我在实际操作中还有一个挺实用的技巧先跑一次聚类然后对每个簇看特征均值与全局均值的差异差异不大的特征说明它对这个簇的区分度很低可以考虑删掉重新跑一遍。这样循环两轮特征维度通常会明显收缩而且聚类结果会更干净。3. 度量无标签数据的距离藏在细节里的关键3.1 距离度量不是默认欧氏距离就完了很多人一说到距离潜意识里就是欧氏距离。这个惯性在低维、连续、标准化过的数据里没问题但一旦数据形态变化它就可能给出荒谬的结论。我举一个具体的反例。在文本聚类里如果用 bag-of-words 生成向量大部分维度是稀疏的 0/1 值欧氏距离会把“共现的词多”误判成“含义接近”但实际上文本里更合理的度量是余弦相似度——它只关心方向、不关心模长。之前我处理客服工单文本时两种度量跑出来的聚类结构差异巨大用余弦相似度能稳定分出“退款咨询”“物流投诉”“产品故障”这些主题欧氏距离几乎是一团浆糊。所以第一步是确认你的数据形态再选度量方式。常见的对应关系大概是数据形态推荐度量原因连续数值特征标准化后欧氏距离 / 曼哈顿距离几何直观计算快高维稀疏向量文本、one-hot余弦相似度不受向量长度影响用户/物品偏好的评分矩阵皮尔逊相关系数能抓住相对偏好类别型特征汉明距离 / 简单匹配系数直接比较取值是否一致3.2 类别特征怎么塞进距离计算无标签数据里经常混着类别型特征比如“用户等级普通/会员/超级会员”“设备类型iOS/Android”。这类特征不能直接当数值算距离但你也不想轻易丢掉它们。常用的处理方案有两个第一种是 one-hot 编码把每个类别拆成独立的 0/1 列。缺点很明显类别多的时候维度爆炸而且 one-hot 列之间的距离权重很难控制。第二种是目标编码的变体用量化替代类别。比如把“用户等级”映射成 0、1、2但这里有个前提类别之间确实存在等级递进关系。如果只是无序类别强行有序化反而会制造虚假的远近关系。我在经验里比较推荐先区分“有序类别”和“无序类别”。有序类别可以映射成数值无序类别再用 one-hot。如果你害怕维度爆炸还有一个折中方案先单独对这些类别特征做一次相似度哈希再把哈希特征拼到大特征集里。这个做法我在地域 用户属性混合的聚类项目里用过效果还可以缺点是解释性变差。3.3 标准化和度量要配套起来看这个点经常被忽略。有些人只标准化特征却不考虑度量是否匹配另一些人抓着一个余弦相似度不放手却忘了余弦对数值特征的“长度偏好”并不敏感。我自己定的配套规则是用 Z-score 标准化 欧氏距离默认组合适合大多数数值型聚类。用 Min-Max 归一化 曼哈顿距离如果特征之间有稀疏零值曼哈顿距离对“0 和 小值”的区分更自然。用词频向量 余弦相似度处理文本、稀疏计数特征时首选。注意高维数据里欧氏距离会趋近于“所有特征都差不多远”这是维度诅咒的一个表现。如果你觉得聚类结果里簇之间的距离都模模糊糊先不要怀疑算法很可能是维度太高了下一步应该做降维而不是调参数。4. 核心算法怎么选从 KMeans 到密度聚类边界在哪4.1 KMeans快但不是所有数据都适合KMeans 是绝大多数人的入门算法也是我实际项目里最常用的“第一枪”。它的核心逻辑很直白随机选 K 个中心点迭代分配样本到最近中心再更新中心位置。理论上它假设簇的形状是“凸的”“匀称的”而且每个簇的方差不能差太多。所以它适合的数据是样本量大、特征维度不高、簇大概呈球形、数据分布比较均匀。比如用户分层、商品分群这些场景下 KMeans 都能快速给出一版能用的基线结果。遇到下面这些情况KMeans 就要让位了簇的形状是长条形、嵌套环形KMeans 会把它们强行拧成几块“饼”数据里带着大量离群点KMeans 对离群点很敏感你不想预设簇数但 KMeans 必须给定 K。4.2 DBSCAN能发现任意形状但参数要命DBSCAN 是密度聚类的代表它不关心簇的形状只关心“密度相连”。核心参数就两个eps邻域半径和min_samples邻域内至少几个点才算核心点。这两个参数我调试过无数次最大的心得是eps的值必须结合业务语境来理解。它不是一个纯数学参数它代表的是“在特征空间里两步之间走多远还能算作邻居”。如果你的特征都标准化了eps取 0.5 和取 1.5 的区别很大前者会把簇切得很碎后者可能把一片都连成一个簇。我常用的调法是先画出 k-距离图把每个点到第 k 近的点的距离排序找到曲线中的“拐点”作为eps。这个方法不算严谨但能很快给你一个起点。然后再根据业务上对“簇粒度”的预期微调。min_samples一般取特征维度数量的两倍到三倍太小会把噪声点也算成簇太大会把真实的小众群体直接标成噪声。DBSCAN 最大的优点是它可以自动标出“不属于任何簇”的点。这个特性在异常检测场景里价值极高。用户行为如果偏离所有已知群体它不会强行塞进某个簇而是直接暴露出来这比 KMeans 硬性分堆合理得多。4.3 层次聚类小样本下的可视化之王层次聚类不常用于大数据集因为它的复杂度较高好几万样本跑起来就会明显变慢。但它有个不可替代的优点生成树状图之后你可以直观地看到“合并过程”能帮你在不同粒度下观察簇结构。我在两类场景下会主动用层次聚类一是样本量小几千以内二是我想探索数据到底应该分几类。它不像 KMeans 那样必须预先指定 K你可以先看树状图再决定在哪一层切几刀。心得层次聚类时距离度量可以选 ward离差平方和它倾向于合并出大小更均衡的簇效果在多数场景下比“最长距离”这种稳定。4.4 降维不是必选项但常常是救命项很多人把 PCA、t-SNE、UMAP 当成“可视化专用工具”其实它们在无标签数据分析里的价值远不止画图。当特征维度到了几十上百几乎所有聚类算法的距离质量都会退化。降维的核心价值是把你真正关心的结构压缩到少量维度里再做聚类和解释。PCA 是最稳定、最保守的降维方式适合维度较高且特征间存在线性相关的数据。t-SNE 擅长把高维流形展开但参数perplexity很敏感且结果不能反推只适合看局部结构。UMAP 是我目前体验下来在“速度 保持结构”之间平衡最好的但同样有超参数需要调。实际工作中我的做法是先上 PCA 看方差累计解释度如果前 20 个主成分能解释 80% 以上方差就直接在主成分上聚类如果数据里存在明显的非线性结构再考虑 UMAP 投影到二维/三维后聚类。需要注意UMAP 投影后再聚类得到的结果会有一定随机性至少要固定随机种子最好多次运行取一致结论。5. 一套能落地的实操流程以用户行为聚类为例5.1 案例背景与目标定义为了把前面的方法串起来我拿一个简化但真实感很强的案例来演示某 App 运营团队给了你一张表里面是 3 万条用户的行为汇总特征包括注册天数、近 30 天登录天数、近 30 天总时长、近 30 天登录次数、近 30 天加购次数、近 30 天支付金额。没有用户标签但运营想知道人群能不能分成几类各自有什么特征。第一步不要急着建模先把业务目标翻译成技术口径。这里的目标是“用户分层”隐含的期望是每一层用户的行为画像都能被运营看懂并且层级之间有可操作的差异。所以后面的特征、算法、结果解释都要围绕“可解释”来做。5.2 预处理与特征工程实操拿到表之后依次执行检查缺失率。支付金额为空的行如果占比不大比如 5% 以内用中位数填充如果占比很高说明支付金额这个特征对大批用户无效需要单独建模不能直接填充混淆结构。检查重复项。通过用户 ID 去重保留首次出现的记录。处理异常值。对支付金额、登录次数这些长尾特征做分位数检查超过 99.5% 分位的样本我们先看具体值能确认是刷单或者测试账号就直接剔除确认不了做截断处理。特征变换。登录次数、总时长、支付金额都偏态严重我先做 log1p 变换取 log(1x)压一压长尾再做 Z-score 标准化让每个特征在同一尺度上被距离计算公平对待。实操心得log1p 变换对“含 0 的次数类特征”几乎是必备操作。直接 log(0) 是负无穷但 log1p(0) 0可以保留“从未发生”的语义。5.3 降维与聚类参数选择特征只有 6 个维度不高这个规模下 PCA 不是必须的但我还是先看了相关矩阵发现“近 30 天登录天数”和“近 30 天登录次数”相关性接近 0.9属于重复信息。我选择删掉登录次数保留登录天数业务上更好解释再跑 PCA 看一眼前三个主成分的累计贡献。聚类选择 KMeans 作为基线但 K 需要定。我先试了手肘法对 K2 到 10 分别跑聚类记录簇内误差平方和SSE。绘制曲线后能看到 K4 附近下降速度明显放缓轮廓系数在 K4 时也达到一个局部高点最终选定 K4。这里要强调手肘法只是找“数学上的拐点”业务上的 K 还要看可解释性。我很多次做出来数学最优的 K 值在业务上却有一类簇的特征组合完全说不通最终还是结合业务预期做取舍。5.4 聚类结果与人群画像跑完 KMeans 之后我对每个簇做了特征均值和全局均值的对比刻画的逻辑很简单“这个簇在哪些特征上显著高/低”。假设结果是簇 A注册天数长、近 30 天登录天数和时长都很高、支付金额高占比 12%可以解释为“忠实高价值用户”。簇 B注册天数中等、登录次数较高、加购高但支付金额不高占比 18%这类是“活跃但犹豫”的用户运营可以主推优惠券转化。簇 C注册天数长、登录天数低、时长低、支付低占比 30%是明显“沉默流失”的人群。簇 D注册天数短、各行为指标都偏低占比 40%属于“新用户阶段”需要引导激活。这四类人能直接映射到运营动作说明聚类是有效的。如果某个簇的画像“什么都平均、不突出”通常意味着这个聚类结果太粗糙需要加特征或者调 K。5.5 验证稳定性和可复现性无监督聚类的结果很容易受随机种子影响。KMeans 初始中心是随机选的我习惯固定随机种子跑多次然后检查样本归属的稳定性。更严谨一点的做法是把 3 万样本切两份各跑一次聚类然后用某些指标对比两个子集上簇中心的距离越接近说明结构越稳。稳定性验证是很多人跳过的一步但它在真实项目里非常重要。决策层不会关心你的算法多花哨只会问“这个分类结果是不是可信”。你如果能拿两组独立样本跑出来聚类质心分布一致说服力会大很多。6. 常见问题与排查技巧实录6.1 K3 还是 K6参数选择的纠结几乎人人都会遇到K 值选择是聚类项目里被问得最多的问题没有之一。我的经验是不要迷信任何一个指标手肘法给你候选范围轮廓系数帮你排除明显离谱的值但最终要回到业务口径“如果分 3 类每一类你都能说出运营动作吗如果分 6 类有没有哪一类你根本不知道拿它怎么办”后者往往是关键信号。另外你要区分两个场景如果是探索性分析我就想看看数据大致什么样K 小一点更稳妥如果是生产级分群后续运营策略要基于此落地宁可 K 大一点去细分也不要 K 太小把不同诉求的人群混在一个组里。前者错了可以重来后者错了影响的是后续几个月的策略。6.2 特征越加越多聚类结果反而越乱这是个典型的“维度诅咒”问题。特征加到一定程度后样本间的距离差异会变得不明显聚类结构会被稀释掉。我自己的经验阈值是几十个特征的规模下如果聚类结果没有清晰的簇间界限先做特征筛选而不是继续堆特征。排查思路分三步先看是否有高度相关特征删同一组里的冗余项再看每个特征取值的区分度如果某一列在簇间均值几乎没有差异直接删最后重新跑聚类看轮廓系数有没有提升。维度减半但轮廓系数上升的情况我遇到太多次了。6.3 DBSCAN 调参时全是噪声一个簇都跑不出来这是密度聚类新人最容易崩溃的场景。每个样本都是噪声点通常说明eps设得太低或者数据标准化后分布太分散。我的排查顺序是先看数据的 k-距离图确定一个基本的eps区间。把eps调大到能出现簇为止再慢慢往下收缩。如果怎么调都只能得到一个超级大簇加一堆噪声大概率是数据里没有明显密度差异的 ASH 结构这时换 KMeans 或者层次聚类可能更合适。DBSCAN 对参数不敏感是对的但对参数的选择却非常敏感。所以不是所有数据都值得用密度聚类先确认你的数据里是否存在“密集区被稀疏区分开”的结构再上 DBSCAN。6.4 聚类结果无法解释怎么办说明某一个簇的样本在每条特征上都和全局均值差不多或者簇之间特征分布交错、没有清晰边界。这类情况我之前也苦恼过后来总结了一个顺序排查清单回看预处理标准化方式是否合适离群点是否清理干净缺失值填充是否引入了虚假模式回看特征工程是不是选了一些和业务目标无关的“垃圾特征”要不要删掉一部分再跑回看距离度量连续特征和类别特征混在一起时one-hot 列的权重是不是被放大了降低聚类数簇太多时某些簇天然就是“残余垃圾堆”样本来自多个小众群体。减小 K 往往能改善。如果这四步都试了还是解释不了那有可能是当前数据本身就不存在明显的群组结构硬聚类是挖不出东西的。这时候不要死磕算法改用异常检测思路可能更契合数据本质。6.5 标准化前后的聚类结果差一个世界我早期踩过最冤的坑就是这个。同一个数据集标准化前跑 KMeans得到“金额高就是第一簇”标准化后跑 KMeans得到“高频低额用户独立成簇”。两者对应的运营策略完全不同。并不是后者一定对但后者通常更合理因为它不再被大数值特征绑架。所以我建议大家在做任何聚类之前都先建立一个习惯跑两版一版标准化一版不标准化对比特征画像。如果差异巨大往往说明你的特征量纲在替你“做决定”这不是你想要的。7. 下一步从聚类到可用的落地产物无标签数据分析做到聚类结果之后后面还有不少路要走比如用标签传播或者其他方法把聚类结果转成监督学习的候选标签把聚类的簇标签迁移到新数据上做实时预测以及在每次更新数据后重新评估簇的漂移情况。这些内容我打算在系列后面的文章里展开讲。现在如果只让你记住这几件事我觉得就够了第一拿到无标签数据不要直接套算法先定义“你想要什么样的结构”。第二预处理和特征工程的权重大于算法调参的权重。第三任何聚类结果都要经过“业务可解释性”的检验否则它只是一个数学玩具。我自己的习惯是在项目文件夹里放一个prep.py把所有清洗、标准化、特征变换的逻辑固化成脚本每次数据更新直接重跑保证不同批次之间的处理口径一致。这个小习惯帮我避免了无数次“这个版本和上版本数据可比吗”的尴尬。希望这篇对你有用。下一篇我计划专门拆解无标签文本数据的处理流程这也是评论区有不少人在问的方向到时候见。
返回列表