资讯中心

电影网站用户性别预测:Hadoop MapReduce Hive 朴素贝叶斯完整实战

📅 2026/9/26 17:43:10
电影网站用户性别预测:Hadoop MapReduce Hive 朴素贝叶斯完整实战
简介这是一份面向大数据技术类专业师生的 Hadoop 教案围绕“电影网站用户性别预测”项目展开适合在 Hadoop 大数据开发基础课程中作为第 6 章案例教学使用。教案先讲解 KNN 算法原理与实现步骤再重点演示如何用 MapReduce 编程实现 KNN 分类器并介绍准确率、召回率、F1-score 等评价指标帮助学习者理解分布式计算下的分类建模流程。内容涵盖教学目标、引导性/探究性/拓展性问题、理论教学与实验教学过程设计、教材与参考资料等可直接用于课堂备课、实验指导或学生自学。资源为 1 个 pdf 文件整体仅 24KB已有 1078 人学习/下载虽然体积小巧但结构完整包含数据预处理、训练集/验证集/测试集划分、KNN 分类实现与模型评价等实验步骤并针对 MapReduce 连接多份数据、参数设置、单机版与分布式实现对比等难点给出了问题引导便于教师围绕项目组织深入讨论。1. 电影网站用户性别预测这个教案到底让你练什么“电影网站用户性别预测”这类项目案例看起来是一道算法题实际上更接近一道数据工程题。训练数据不是现成的表格而是散落在 HDFS 上的行为日志字段有缺失、格式不统一、体量又大单机 Excel 或 MySQL 根本扛不住完整流程。这份教案的价值在于把 HDFS 存储、MapReduce 离线归并、Hive 特征加工、朴素贝叶斯训练预测串成一条完整链路——这正是入门 Hadoop 大数据开发时最该练的路径。适合正在学 Hadoop 基础、要交课程设计或者备战大数据应用开发技能大赛的人。跟着做一遍你会对“数据从哪来、怎么存、怎么算、怎么用”产生完整体感而不是停留在命令抄写层面。2. 先看清这个案例的数据源头与 Hadoop 处理路径2.1 电影网站用户数据长什么样行为日志与性别标签从哪来教案里的电影网站数据最常见的是按三个数据集组织。第一类是行为日志一行记录表示某个用户在某时刻对某部电影做了一次操作操作类型可能是浏览、评分、收藏第二类是用户注册信息包含 user_id、注册时间、年龄以及关键的 gender 字段第三类是电影维度表包含 movie_id、标题、类型类型往往还是“动作/喜剧/科幻”这样的管道符分隔文本。gender 在这里就是标签但它的用法要拆开看。已知性别的用户构成训练集未知性别用户是被预测对象。如果教案没单独给未知用户表常见做法是把已知用户按 8:2 切分80% 训练、20% 验证用验证集模拟“预测新用户”的流程。这样一轮下来你既练了数据处理也练了模型评估。字段层面有两个高频坑后面清洗阶段会直接撞上。behavior 在原始日志里经常大小写混着来Browse、browse、BROWSE 同时出现score 只在评分行为下才有值浏览行为里是空字符串。这些脏点决定了 MapReduce 的 Mapper 里必须做 trim、toLowerCase、判空三步少一步都会带脏数据进特征表。2.2 为什么是 Hadoop 而不是一台 MySQL量级与链路选择先看数据体量。一个中等规模的电影网站单月行为日志到 5000 万条不算夸张。这种量级丢给单机 MySQL 做 group by索引设计不好就是分钟级响应甚至直接把临时表撑爆。换成 Hadoop几十台节点把文件切成块并行处理才是这类统计的正常姿势。即使只是在课程设计的伪分布式单机上跑你也能完整看到“文件切分、Map 并行、Shuffle、Reduce 归并”的过程这是单机 SQL 给不了的。教案的主线链路通常是固定的HDFS 先承接原始日志MapReduce 做第一层清洗和归并Hive 做需要多表关联的特征加工最后把特征表交给分类逻辑做性别预测。这个顺序不是拍脑袋定的而是按计算成本排的。最重的全量扫描放在 MapReduce因为它对脏数据容忍度高、逻辑直观需要 join 的聚合放在 Hive因为一条 SQL 顶得上两三个 MR Job。伪分布式和真实集群在这个链路上没有本质区别差别只在参数和资源分配。学基础阶段伪分布式搭建是性价比最高的路径这也是大量“hadoop 伪分布式搭建”、“从零开始安装 hadoop”教程都拿它当起点的原因。2.3 环境选型伪分布式、Docker 镜像还是课程设计低配方案常见环境有三类课程设计和技能大赛里各有拥趸。伪分布式单机一套 Linux 虚拟机就能跑配置最少适合第一次把 HDFS、YARN、Hive 全部拉起来验证链路的人多节点集群三台虚拟机起步能演示数据块多副本和跨节点调度但对硬件和排障能力要求高Docker 镜像用现成的 hadoop docker 镜像拉起容器环境干净、重置方便缺点是网络和端口映射会带来额外心智负担。如果是交课程设计我一般建议伪分布式加 Hive 的组合。原因很实际一份教案要演示的存储、计算、查询环节伪分布全部覆盖答辩时老师问“集群怎么扩展”你再讲多节点方案也不迟。要是想演示高可用再引入 Hadoop 与 Zookeeper 整合实战把 NameNode 的 Active/Standby 切换讲清楚那属于加分项不是基础项。Windows 下用 IDEA 搭 Hadoop 开发环境的做法这两年很流行因为写 MapReduce 代码方便。但要有个心理准备本地 IDE 里跑通逻辑和提交到 Linux 伪分布集群上跑通中间隔着 classpath、jar 依赖、HDFS 权限三道坎。教案多数场景不需要把 IDE 和集群打通本地写代码、打包上传、服务器运行反而是最不折腾的路径。3. 跑通最小数据流从原始日志上传到用户特征表生成3.1 先把原始数据装进 HDFS目录规划与常用命令开始写 MapReduce 前先规划 HDFS 目录。踩过坑的人都知道目录乱是后面所有 Permission denied 和路径写错的第一来源。我习惯按“原始层、加工层、结果层”分三层# 原始层行为日志、用户信息、电影维度只读不覆盖 hdfs dfs -mkdir -p /user/hadoop/movielens/raw/logs hdfs dfs -mkdir -p /user/hadoop/movielens/raw/users hdfs dfs -mkdir -p /user/hadoop/movielens/raw/movies # 加工层MapReduce 和 Hive 的中间结果 hdfs dfs -mkdir -p /user/hadoop/movielens/warehouse # 上传本地数据 hdfs dfs -put ./logs/part-*.txt /user/hadoop/movielens/raw/logs/ hdfs dfs -put ./users/users.csv /user/hadoop/movielens/raw/users/ hdfs dfs -put ./movies/movies.dat /user/hadoop/movielens/raw/movies/参数说明-mkdir -p支持递归创建不存在父目录时一次建好避免一层层建-put的源路径支持通配符多个日志分片一次上传目标目录一定要先建好再上传否则文件名会被当成目录名的一部分后面找文件时对不上。上传后先用hdfs dfs -text抽查前几行而不是直接开始写 MR。-text能同时识别纯文本和压缩格式对日志排查看内容最方便比-cat适用范围更广。这一步花两分钟能省掉后面好几个小时的诡异问题排查。提示上传前确认文件是无 BOM 的 UTF-8。带 BOM 的文件第一行第一个字段会多出一个不可见字符MapReduce 解析时会把整条记录当作脏行。3.2 MapReduce 第一次聚合统计每个用户的评分行为第一个 MR 的目标很单一从行为日志里筛出评分记录按用户和电影归并输出“这个用户对这部电影评了几次、总分多少”。这一步把日志从“流水”变成“结构化事实”。// UserMovieScore.java // 输入一行user_id movie_id behavior score timestamp字段用 \t 分隔 // 只保留评分行为按 (user_id, movie_id) 聚合评分次数和总分 import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import java.io.IOException; public class UserMovieScore { public static class ScoreMapper extends MapperObject, Text, Text, Text { private Text outKey new Text(); private Text outValue new Text(); Override protected void map(Object key, Text value, Context context) throws IOException, InterruptedException { String[] fields value.toString().split(\t); if (fields.length 5) { return; // 字段数不够直接丢弃比抛异常省事 } String behavior fields[2].trim().toLowerCase(); if (!rate.equals(behavior)) { return; // 只保留评分行为浏览和收藏不参与评分特征 } String userId fields[0].trim(); String movieId fields[1].trim(); String score fields[3].trim(); if (userId.isEmpty() || movieId.isEmpty() || score.isEmpty()) { return; // 空字段清洗避免后续 Integer 解析炸掉 } outKey.set(userId \t movieId); outValue.set(score); context.write(outKey, outValue); } } public static class ScoreReducer extends ReducerText, Text, Text, Text { Override protected void reduce(Text key, IterableText values, Context context) throws IOException, InterruptedException { int cnt 0; int sum 0; for (Text val : values) { cnt; sum Integer.parseInt(val.toString()); } // 输出 user_id、movie_id、评分次数、总分 // 平均分交给 Hive 算避免 Java 整数除法丢精度 String[] parts key.toString().split(\t); context.write(new Text(parts[0] \t parts[1]), new Text(cnt \t sum)); } } public static void main(String[] args) throws Exception { Configuration conf new Configuration(); Job job Job.getInstance(conf, UserMovieScore); job.setJarByClass(UserMovieScore.class); job.setMapperClass(ScoreMapper.class); job.setReducerClass(ScoreReducer.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(Text.class); FileInputFormat.addInputPath(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1); } }编译并提交到伪分布集群mkdir -p classes javac -classpath $(hadoop classpath) -d classes UserMovieScore.java jar cf usermoviescore.jar -C classes . hadoop jar usermoviescore.jar UserMovieScore \ /user/hadoop/movielens/raw/logs \ /user/hadoop/movielens/warehouse/user_movie_score参数说明$(hadoop classpath)会把 Hadoop 生态的全部依赖 jar 拼出来交给 javac 做编译 classpath不要用老教程里hadoop com.sun.tools.javac.Main的方式Hadoop 3.x 经常在这里翻车输出目录/user/hadoop/movielens/warehouse/user_movie_score不能预先存在MapReduce 会自己创建存在会直接报错跑完用hdfs dfs -text /user/hadoop/movielens/warehouse/user_movie_score/part-r-00000 | head抽查输出。这个 MR 的 Reducer 故意只输出次数和总分不在 Java 里算平均分。原因很实际sum / cnt在 Java 里是整数除法3.8 分会变成 3特征精度直接丢光。把小数计算留给 Hive是后面写 SQL 时更自然的做法。如果不想写 Java也可以用 Hadoop Streaming 配 Python 脚本实现同样的逻辑但对课程设计来说手写一个完整 MR 类更能体现对框架的理解。3.3 用 Hive 做特征表一次 JOIN 替代第二个 MRMR 把日志归并成了“用户-电影-评分次数”的明细接下来要造特征。特征需要关联电影类型和用户性别这个 join 逻辑再写一个 MR 会非常啰嗦Hive 一条 SQL 就能做掉这也是教案把第二层加工放在 Hive 的原因。CREATE DATABASE IF NOT EXISTS movie_etl; USE movie_etl; -- 原始行为日志用外部表指向 HDFS避免 LOAD DATA 把文件移走 CREATE EXTERNAL TABLE IF NOT EXISTS raw_logs ( user_id INT, movie_id INT, behavior STRING, score DOUBLE, ts BIGINT ) ROW FORMAT DELIMITED FIELDS TERMINATED BY \t STORED AS TEXTFILE LOCATION /user/hadoop/movielens/raw/logs; CREATE EXTERNAL TABLE IF NOT EXISTS movie_dim ( movie_id INT, title STRING, genres STRING ) ROW FORMAT DELIMITED FIELDS TERMINATED BY \t LOCATION /user/hadoop/movielens/raw/movies; CREATE EXTERNAL TABLE IF NOT EXISTS raw_users ( user_id INT, age INT, gender STRING, register_ts BIGINT ) ROW FORMAT DELIMITED FIELDS TERMINATED BY \t LOCATION /user/hadoop/movielens/raw/users; -- 用户特征表评分次数、平均分、动作片数量、夜间活跃度 CREATE TABLE IF NOT EXISTS user_features AS SELECT l.user_id, COUNT(l.movie_id) AS rate_cnt, ROUND(SUM(l.score) / COUNT(l.score), 2) AS avg_score, SUM(CASE WHEN m.genres LIKE %Action% THEN 1 ELSE 0 END) AS act_cnt, SUM(CASE WHEN CAST(FROM_UNIXTIME(l.ts, HH) AS INT) BETWEEN 22 AND 23 OR CAST(FROM_UNIXTIME(l.ts, HH) AS INT) BETWEEN 0 AND 5 THEN 1 ELSE 0 END) AS night_cnt FROM raw_logs l JOIN movie_dim m ON l.movie_id m.movie_id GROUP BY l.user_id;参数说明CREATE EXTERNAL TABLE配合LOCATION指向原始 HDFS 目录这样 Hive 只读文件、不移动文件如果图省事用LOAD DATA INPATH文件会被挪进 Hive 仓库目录后续 MR 再读原路径就找不到了。ROUND(SUM(l.score) / COUNT(l.score), 2)用的是浮点除法正好接住前面 MR 里没有算的平均分。genres LIKE %Action%是偷懒写法真实项目里类型字段常用Action|Comedy管道分隔更规范的做法是用LATERAL VIEW explode拆行再统计教案阶段先跑通优先。这一步完成后user_features表里每一行就是一个用户的行为画像性别字段还没进来。到这时候原始日志已经完成了从流水到结构化特征的转变接下来的性别预测全部以这张表为输入。4. 性别预测怎么做特征、朴素贝叶斯与兜底规则4.1 特征构造看过什么、什么时候看、评分多少性别预测的特征不是越多越好而是越能解释越好。教案阶段的模型要用 Hive 和脚本落地不可能上深度网络所以特征要选那种“直觉得到验证”的维度。下面这张表是典型的 MovieLens 风格数据集中常用的几个特征计算口径完全基于上一章生成的 user_features 表。特征计算口径业务直觉rate_cnt该用户评分过的电影数量活跃程度辅助特征avg_score平均评分样本中女性平均分略高但易受片单影响act_cnt评分的电影中 Action 类型数量动作片对男性吸引力更强night_ratio22:00-05:00 评分次数 / 总评分次数男性夜间活跃占比更高comedy_cnt喜剧/爱情片数量这类题材女性评分占比更高这些“业务直觉”不能拍脑袋要拿数据验证。教案里通常会让学员做单特征分布对比分别统计男性和女性在某个特征上的均值、分位数差异不明显的特征直接砍掉。这个验证在 Hive 里一条 SQL 就能看SELECT gender, AVG(act_cnt) AS avg_action, AVG(night_ratio) AS avg_night_ratio, AVG(avg_score) AS avg_score FROM user_features uf JOIN raw_users u ON uf.user_id u.user_id GROUP BY gender;如果男性和女性的 avg_action 差距不到 0.5说明动作片数量这个特征区分度很弱后面建模型时可以考虑去掉或换分桶口径。这个“先验证再入模”的习惯比堆十个特征重要得多。4.2 朴素贝叶斯的训练与预测全部用 Hive 和脚本落地朴素贝叶斯在这个教案里的优势是简单、可解释、不需要额外装库。做法是先对连续特征分桶把动作片数量、夜间占比、平均评分变成离散档位再统计每个档位在男性和女性中的条件概率。预测时把新用户的档位拿出来分别计算男性和女性后验概率谁大判谁。分桶和概率统计用 Hive SQL 完成USE movie_etl; -- 特征分桶视图连续值变离散值朴素贝叶斯按频次算概率 CREATE OR REPLACE VIEW user_features_bucket AS SELECT uf.user_id, u.gender, CASE WHEN uf.act_cnt 5 THEN action_heavy WHEN uf.act_cnt 1 THEN action_mid ELSE action_none END AS action_bucket, CASE WHEN uf.night_ratio 0.6 THEN night_high ELSE night_low END AS night_bucket, CASE WHEN uf.avg_score 4.0 THEN score_high WHEN uf.avg_score 3.0 THEN score_mid ELSE score_low END AS score_bucket FROM user_features uf JOIN raw_users u ON uf.user_id u.user_id WHERE u.gender IS NOT NULL;-- 先验概率男性 / 女性占比 SELECT gender, COUNT(*) AS cnt FROM user_features_bucket GROUP BY gender; -- 条件概率不同动作片偏好下的性别分布 SELECT gender, action_bucket, COUNT(*) AS cnt FROM user_features_bucket GROUP BY gender, action_bucket;统计出来的概率表非常小几十行文本而已完全可以作为模型文件存下来。在分布式环境里预测时把这个小模型文件放进 Hadoop 分布式缓存每个 Map 任务读一份到内存对新用户逐行打分。下面是 Hadoop Streaming 里常用的 Python 打分逻辑#!/usr/bin/env python3 # predict_gender.py # 输入user_id action_bucket night_bucket score_bucket\t 分隔 # 输出user_id 预测性别 import sys import math probs {} # (gender, feature, value) - 条件概率 def load_model(path): with open(path) as f: for line in f: gender, feature, value, p line.strip().split(\t) probs[(gender, feature, value)] float(p) def predict(features): best_gender male best_score float(-inf) for gender in (male, female): score 0.0 for feature, value in features.items(): # 拉普拉斯平滑查不到的档位给极小概率防止 log(0) score math.log(probs.get((gender, feature, value), 1e-6)) if score best_score: best_gender, best_score gender, score return best_gender if __name__ __main__: load_model(gender_model.txt) # 实际放在 Hadoop 缓存里 for line in sys.stdin: uid, action, night, score line.strip().split(\t) feats {action: action, night: night, score: score} print(f{uid}\t{predict(feats)})参数说明math.log连加等价于概率连乘避免多个小概率相乘变成 0是朴素贝叶斯实现的常见细节拉普拉斯平滑的1e-6是兜底值训练集里某个性别没出现过的档位预测时不至于直接判死这个脚本当成 Streaming Mapper 提交时模型文件要用-files gender_model.txt分发到每个节点。概率连乘后比较男女后验概率输出概率大的那一方。模型本身可解释某个用户被判定为男性可能是 action_heavy 加 night_high 两票同时压过来而不是一个黑匣子给了个分数这正是一个教案该有的效果。4.3 不依赖算法库的规则 Baseline先定一个及格线很多学员第一次跑通贝叶斯模型看到准确率 0.65 就觉得很成功这个判断其实缺一个参照物。参照物就是规则打分也叫 Baseline。规则不需要任何概率统计直接按业务直觉设几条判断分支hive -e SELECT user_id, CASE WHEN act_cnt 5 AND night_ratio 0.6 THEN male WHEN avg_score 4.0 AND comedy_cnt 3 THEN female ELSE unknown END AS pred FROM user_features;这条规则的分支逻辑来自 4.1 的特征直觉动作片多且夜间活跃判男性平均分高且喜剧片多判女性。它不聪明但能帮你回答一个问题花力气写的朴素贝叶斯到底比拍脑袋规则强多少。如果模型准确率只比规则高 2 个百分点说明特征没选好或者分桶口径有问题优先回去调特征而不是调模型。规则打分的另一个用途是处理模型判不出来的情况。真实用户里总有人行为模式反直觉男性用户专看爱情片女性用户专看动作片。贝叶斯硬要二选一规则可以老实输出 unknown这类样本留给后续人工标注或二次处理。课程设计答辩时能讲清楚“什么时候模型不可信”比“模型准确率多高”更能说明你理解了业务边界。5. 伪分布式环境跑这个教案的排障手记5 个高频翻车点5.1 NameNode 起不来格式化两次造成的 clusterID 不一致伪分布式最劝退的一幕是start-dfs.sh之后jps看不到 NameNode 进程去看logs/hadoop-*.log里面躺着一句Incompatible clusterIDs。原因是之前已经格式化过一次后来改了配置或者手滑又执行了一次hdfs namenode -formatNameNode 和 DataNode 各自生成了新的 clusterID两面对不上。解决方法是彻底重置这也是伪分布式环境特有的后悔药。先停掉所有进程清空 name 和 data 目录只格式化一次stop-dfs.sh rm -rf /usr/local/hadoop/tmp/dfs/name rm -rf /usr/local/hadoop/tmp/dfs/data hdfs namenode -format start-dfs.sh注意清空目录前确认你的核心站点配置里dfs.namenode.name.dir和dfs.datanode.data.dir指向的就是这两个路径别清错目录。这个操作会丢掉 HDFS 里的全部数据所以只适合伪分布重置真集群里格式化是灾难级操作千万别养成习惯。5.2 作业卡在 ACCEPTED 不调度YARN 内存参数没对齐提交的 jar 跑起来后yarn application -list显示状态一直是 ACCEPTEDapplication 就是不转 RUNNING日志也看不到。这是伪分布最常见的资源调度问题虚拟机内存只有 2GB而 Hadoop 默认的yarn.nodemanager.resource.memory-mb按大集群规格配置容器根本申请不到足够内存。打开$HADOOP_HOME/etc/hadoop/yarn-site.xml把这四个参数对齐到小内存机器property nameyarn.nodemanager.resource.memory-mb/name value2048/value /property property nameyarn.scheduler.minimum-allocation-mb/name value512/value /property property nameyarn.scheduler.maximum-allocation-mb/name value2048/value /property property nameyarn.nodemanager.vmem-pmem-ratio-enabled/name valuefalse/value /property改完重启 YARN。另外mapred-site.xml里的mapreduce.map.memory.mb和mapreduce.reduce.memory.mb别配置超过 1024否则一个作业吃掉全部容器资源其他作业全部排队。这类问题排查时先看yarn application -list的进度状态再翻 Container 日志比瞎改参数高效得多。5.3 Hive 查 gender 全是 NULL分隔符和空值定义两个坑Hive 建表没问题但SELECT gender返回一列 NULL其他字段正常。第一反应是查原始文件的分隔符是否和建表语句一致。最常见的情况是原始文件用空格分隔建表写了FIELDS TERMINATED BY \t导致整列错位解析。排查时用一条命令看文件的真实分隔符和行尾hdfs dfs -text /user/hadoop/movielens/raw/users/part-* | head -5 | cat -Acat -A会把\t显示成^I行尾显示成$一眼就能看出文件里到底是 tab 还是空格。确认后要么改建表语句要么先清洗一次文件。另一个空值陷阱是数据里空字符串和 Hive 的 NULL 不是一回事。如果文件里写的是空字符串Hive 默认把它当成空串而不是 NULL可以在建表语句后追加TBLPROPERTIES (serialization.null.format)把空字符串统一解释成 NULL后面WHERE gender IS NOT NULL这类过滤才靠得住。5.4 某个 Reducer 卡在 99%数据倾斜与加盐解法现象很典型整个作业进度 98%其中一个 Reducer 长时间卡在 99%其他 Reducer 早就跑完。这是数据倾斜——按性别维度 join 或者 group by 时男性用户占比远高于女性某个 key 对应的数据量是其他 key 的几倍别的节点闲死它一个节点忙死。Hive 场景最简单的处理是开倾斜优化SET hive.groupby.skewindatatrue;这个参数会把 group by 拆成两阶段聚合先打散再汇总能缓解大部分倾斜。如果是自己写的 Reduce 端 join就要手动加盐把 key 拼一个随机后缀拆到多个 Reducer 先算局部结果再按真实 key 做二次聚合。加盐方案比调参数多点几行代码但在 MR 层面体现的是真实的大数据问题解决能力答辩时拿出来是很加分的讲了。5.5 hdfs dfs -put 报 Permission deniedHDFS 目录属主与用户组问题上传数据时终端报错Permission denied: userroot, accessWRITE, inode/user:hdfs:supergroup。原因是当前登录用户不是 hdfs 超级组HDFS 根目录默认只让 hdfs 用户写其他用户进不去。这在课程设计里很常见因为大家图省事经常直接用 root 跑 hadoop 命令。解决方法是创建对应用户的 home 目录并授权sudo -u hdfs hdfs dfs -mkdir -p /user/hadoop sudo -u hdfs hdfs dfs -chown -R hadoop:hadoop /user/hadoop然后切回 hadoop 用户重新上传。要注意的是用 root 跑 Hadoop 命令在真实生产环境是大忌但在自己的伪分布虚机上很多人会这么干。如果教案全部用 root 操作最简单的方式是统一把目录 chown 给 root一劳永逸如果要规范一点就单独建 hadoop 用户所有命令都切到 hadoop 下执行。权限问题本身不难难在很多人看到supergroup字样就懵了其实它就是“HDFS 超级用户组”的意思把当前用户加进去或把目录归属改掉问题就没了。6. 把教案从能跑练到能答辩验证方法、评估指标与三个改进方向先讲验证。性别预测不能只看“预测出来了”要看预测得准不准。把已知性别用户按 8:2 切分20% 当测试集拿训练好的概率模型去打分然后把预测结果与真实性别对齐SELECT SUM(CASE WHEN p.gender r.gender THEN 1 ELSE 0 END) / COUNT(*) AS accuracy, SUM(CASE WHEN p.gender male AND r.gender male THEN 1 ELSE 0 END) / NULLIF(SUM(CASE WHEN r.gender male THEN 1 ELSE 0 END), 0) AS recall_male FROM predict_result p JOIN raw_users r ON p.user_id r.user_id;评估指标最少看三列整体准确率、男性召回率、女性召回率。性别分布天然不平衡只盯准确率会被多数类带偏如果男性占 70%全预测男性准确率也有 70%但这显然没意义。所以还要对比规则 Baseline贝叶斯模型准确率必须明显高过规则分才算真正有效。模型准确率男性召回率女性召回率规则 Baseline0.630.780.44朴素贝叶斯0.710.800.58改进方向有三个按投入产出比排序。第一是加入时间衰减因子让最近半年的行为权重高于一年前这本教案只用了全量统计时间维度的信息没吃透第二是评分行为加权收藏和购买行为的信号强度高于浏览目前 MR 阶段就把非评分行为丢掉了这个丢法值得商榷第三是特征做交叉把 action_heavy 和 night_high 拼成一个复合特征往往比两个独立特征更能捕捉行为模式。我当年带课程设计时最常翻车的不是模型而是数据没对齐两个表的 user_id 类型不一致、文件分隔符看错都能让辛辛苦苦写的作业一夜归零。谁先把 HDFS 上的文件摸清楚谁就赢了一半。这份教案的完整链路走通后Hadoop 大数据开发的地基就算打牢了后面再接触 Spark、Flink 都会轻松很多。希望帮到你。本文还有配套的精品资源点击获取

看完文章,想为自己的企业也做一次专业网站诊断?

尧图顾问免费为您评估现有网站,并给出建站/改版建议与报价方案。

免费获取方案