资讯动态

R语言msleep数据集分析:从缺失值处理到回归建模

发布时间:2026/10/21 5:07:04 来源:尧图企业网站定制
做数据分析的人练手作品集或者复习 R 语法的时候迟早会碰到一套与哺乳动物睡眠相关的公开数据。最近我把 R 语言里这套经常被叫成 sleep 数据集的哺乳动物睡眠记录完整跑了一遍从数据检查、缺失值处理、可视化一路做到相关分析和回归建模。整套流程做下来之后我有个很直接的感受这套数据只有 83 行 11 列量级不大但既有数值变量也有分类变量既有完整记录也有缺失值几乎涵盖了一次基础数据分析要走的全部环节很适合刚学完 R 基础语法、想拿真实数据做综合练习的人。这篇文章就把我的完整思路、踩过的坑和可用代码整理出来给后续想拿它做作品集或练手的人一个参考。1. 数据集底细sleep 里到底有什么以及它和 msleep 的关系先解决一个最容易让人困惑的问题。很多网课和博客把这个数据集写成 sleep 数据集你如果在 RStudio 里直接敲data(sleep)调出来的其实是另一份经典数据——关于两种药物对学生睡眠影响的配对实验数据一共才 10 行和哺乳动物睡眠没有关系。真正包含哺乳动物睡眠记录的数据集在 R 生态里通常是通过ggplot2包加载的msleep因为变量名里大量出现 sleep圈内口语里就习惯叫它 sleep 数据集。为了避免读者跑代码时卡在第一步我这篇文章统一使用msleep作为数据对象名但全文内容对应的就是标题里说的那套哺乳动物睡眠时间数据。library(ggplot2) data(msleep)加载之后先确认数据结构这一步别看它简单很多人会跳过结果后面画图报错半天找不到原因。dim(msleep) # 83 11 names(msleep) # 列名列表 str(msleep) # 每一列的类型和取值情况 summary(msleep) # 数值变量的五数概括和缺失量1.1 每一列到底是什么能回答什么问题msleep收集了 83 种哺乳动物的睡眠和相关生态指标。把变量拆开看大致可以分成三类标识信息、睡眠信息、身体与生态信息。变量名含义类型分析作用name物种常用名字符标识用于查具体物种genus属名字符分类学信息vore食性字符型分类变量可分组比较有缺失order所属目字符高级分类可用于分组聚合conservation保护状态分类变量可分析但缺失较多sleep_total每天睡眠总时长小时数值核心响应变量sleep_rem快速眼动睡眠时长小时数值睡眠质量指标缺失较多sleep_cycle单个睡眠周期长度小时数值睡眠结构指标缺失较多awake每天清醒时长小时数值与 sleep_total 互补brainwt脑重千克数值身体特征之一bodywt体重千克数值身体特征之一我在分析时最关心的是sleep_total它是整个分析的响应变量brainwt和bodywt是考察体型越大是否睡得越少这个经典问题的主要自变量vore则是用来做分组比较的分类变量比如食虫动物和植食动物在睡眠模式上有没有系统性差异。sleep_rem和sleep_cycle虽然信息量很大但缺失偏多使用时要格外留意样本量。1.2 为什么这套数据值得专门写一轮分析这套数据最有价值的地方在于它不是一张冷冰冰的随机数表而是带有真实生态学背景的观测数据。你可以问出有实际意义的问题比如吃肉的是不是普遍比吃草睡得少脑容量大的动物会不会牺牲睡眠时间而不是只为了跑一个回归而凑变量。这种数据背后有故事的特质让最后写出的分析报告更像一个完整的小项目而不是课堂作业。当然它也是典型的观察数据不是随机对照实验的结果所以无论分析出什么模式都只能描述相关性不能直接说食性导致了睡眠差异。这一点我会在后面的建模解读里反复强调也是用人单位或者导师看作品集时最容易追问的地方。2. 缺失值处理加载数据之后先别急着画图很多人拿到数据的第一反应是直接summary()然后开始画图但其实最容易埋坑的是缺失值。我这次在预处理阶段就把缺失情况全部列了一遍后面的分析才没有反复被报错打断。missing_counts - apply(is.na(msleep), 2, sum) missing_counts[missing_counts 0]在我当前加载的版本里vore缺失 7 条conservation缺失 29 条sleep_rem缺失 22 条sleep_cycle缺失 30 条。这个缺失量级对只有 83 行的数据集来说相当可观。2.1 缺失值的处理策略不能无脑drop_na这里是我这次分析里最重要的实操经验之一不要一上来就drop_na()否则会吃大亏。如果直接用na.omit(msleep)删掉所有含缺失的行数据集会从 83 行掉到大约 30 行左右你后面建模、画分面图、做分组比较时样本量都不够看。正确做法是根据当前环节需要的变量来决定数据保留范围画sleep_total分布图时只需要这一列非缺失所有物种基本都能用上。按vore分组比较睡眠时长时只要vore和sleep_total同时非缺失就行。做完整回归建模时才需要保证进入模型的全部变量非缺失这时样本量会明显缩减要在结果解读里明确写出实际样本量。这样按需裁剪的处理方式既能保留尽可能多的信息也贴合真实工作中的分析习惯。我处理缺失值时用了这样的代码library(dplyr) msleep_clean_vore - msleep %% filter(!is.na(vore), !is.na(sleep_total)) msleep_model - msleep %% filter(!is.na(vore), !is.na(sleep_total), !is.na(brainwt), !is.na(bodywt))2.2 变量类型转换与派生变量vore和conservation看起来是字符型但如果要在回归里当因子使用最好显式转换成factor。我还顺手创建了两个对数变换变量log_brainwt和log_bodywt原因是体重和脑重数据量级差异太大小到几克的鼩鼱大到几吨的鲸类不取对数时散点图基本挤在左下角看不出任何趋势。msleep - msleep %% mutate( vore factor(vore), conservation factor(conservation), log_brainwt log10(brainwt), log_bodywt log10(bodywt) )这一步做的逻辑在后面可视化章节会体现得更清楚。对数变换不是为了炫技而是让跨数量级的数据能在同一张图里公平地展示线性关系。3. 探索性可视化先让数据自己说话数据规整好之后不要急着建模。先用三张图从不同角度把变量关系摸个底这个顺序基本适用于所有数据分析项目。3.1 睡眠总时长的分布形态ggplot(msleep, aes(x sleep_total)) geom_histogram(bins 12, fill steelblue, color white, alpha 0.9) labs(title 哺乳动物每日睡眠总时长分布, x 睡眠总时长小时, y 物种数量)从分布来看大多数物种每天睡 5 到 14 个小时峰值大概落在 8 到 11 小时这个区间右侧拖着一条较长的尾巴少数物种像某些蝙蝠可以睡到 19 小时以上而长颈鹿、大象则只需要睡 2 到 4 小时。这种轻度偏态的分布提醒我后面如果做线性回归模型对极端值的敏感度需要留意。3.2 不同食性下的睡眠差异ggplot(msleep_clean_vore, aes(x vore, y sleep_total, fill vore)) geom_boxplot(outlier.colour firebrick, outlier.size 1.5, alpha 0.7) labs(title 不同食性哺乳动物的睡眠时长对比, x 食性, y 睡眠总时长小时) theme(legend.position none)这张图信息量很大。直观来看食虫动物的睡眠时间较长中间水平大概在 15 小时上下植食动物睡眠时间相对较短中位数在 10 小时以下杂食动物和肉食动物居中。这个模式在生态学上是有解释空间的食虫动物吃的昆虫能量密度低可能需要更多时间消化和休息而植食动物要花大量时间觅食同时还要警惕捕食者睡眠时间自然被压缩。不过要提醒一句箱线图只是描述性观察组间差异是否显著还需要后面用方差分析或者回归来控制其他变量。而且各组样本量很不平衡食虫动物只有 8 种左右植食动物却有二十多种解读时要谨慎。3.3 体型与睡眠的关系对数变换的效果ggplot(msleep, aes(x log_bodywt, y sleep_total, color vore)) geom_point(size 2.5, alpha 0.8) geom_smooth(method lm, se FALSE, color gray40, linewidth 0.7) scale_color_viridis_d() labs(title 体重与睡眠总时长的关系对数坐标, x log10(体重kg), y 睡眠总时长小时, color 食性)这是整轮分析里最值得看的一张图。没有对数变换之前体重从 0.005 kg 到 6000 kg 跨度巨大绝大多数点挤在原点附近根本分不清趋势。取对数之后负相关趋势立刻显现出来体型越大的哺乳动物睡眠总时长越短。这个结论和主流睡眠研究的方向完全一致。另外我在图上还发现了一个值得单独拿出来看的点大熊猫的睡眠时间接近 14 小时但它的体重超过 100 kg明显偏离了整体趋势属于一个高体重却高睡眠的特殊物种。这种离群点不用急着删标注出来反而能体现你在做分析时的细心程度。4. 相关分析把数值变量之间的关系量化可视化帮我们建立了直观印象接下来用相关分析把这些关系量化。这一步不仅能验证眼睛看到的趋势还能发现一些容易被忽略的变量组合。4.1 计算相关系数时要小心缺失值num_vars - c(sleep_total, sleep_rem, sleep_cycle, brainwt, bodywt, awake) cor_mat - cor(msleep[num_vars], method spearman, use complete.obs) round(cor_mat, 2)我选择spearman而不是pearson原因是前面已经确认bodywt和brainwt的分布严重偏态虽然手动做了对数变换但spearman基于秩次计算对离群值更稳健更适合初步的探索性阶段。如果你想对比两种方法的差异可以同时算一次pearson你会发现数值有差别但方向基本一致。4.2 相关矩阵的可视化library(corrplot) corrplot(cor_mat, method color, addCoef.col black, tl.col black, tl.cex 0.8, number.cex 0.7, diag FALSE)相关矩阵里最值得注意的几个关系sleep_total与sleep_rem呈明显正相关说明总睡眠时间长的物种快速眼动睡眠通常也比较长。sleep_total与brainwt、bodywt呈负相关和散点图看到的趋势吻合。sleep_total与awake几乎完全负相关这个很好理解一天就 24 小时清醒和睡眠天然互补。这里有一个建模阶段极其重要的提醒awake和sleep_total存在完全线性冗余关系明确一点说就是sleep_total awake 24。如果做回归时不小心同时放进这两个变量模型会直接出现多重共线性问题系数估计完全失真。我在第一次跑模型时就踩过这个坑后面单独讲。4.3 相关分析阶段就该留意的样本量问题使用use complete.obs计算相关矩阵时R 会只保留所有变量都非缺失的样本。对于sleep_cycle这种缺失量很大的变量它参与计算时实际样本量会缩水到一半左右相关估计的稳定性会下降。所以我在相关分析阶段就决定sleep_cycle只做探索性参考不放进最终的回归模型。这个取舍在分析报告里也要写清楚体现的是你对数据质量的认识。5. 回归建模与诊断量化睡眠总时长受什么因素影响相关分析只能给出两两之间的关系但要同时控制多个变量、判断各自的独立贡献还是得走回归模型。这一节我会展示一套完整的建模流程包括模型设定、多重共线性检查、简化和诊断。5.1 第一版模型把核心自变量都放进去考虑到awake的完全冗余问题第一版模型用log_bodywt、log_brainwt和vore作为自变量mod1 - lm(sleep_total ~ log_bodywt log_brainwt vore, data msleep_model) summary(mod1)模型输出里你会看到log_brainwt或log_bodywt中至少有一个系数显著为负而vore的三个哑变量可能都不显著。这个结果本身有很强的解读空间食性差异在睡眠上的表现很大程度可能由体型差异所解释一旦把体型放进来食性就不再有额外解释力。但先别急着下结论因为我注意到log_brainwt和log_bodywt这两个变量很可能存在共线性问题。脑重和体重在生物演化上是强相关的——大的动物通常脑也更大同一个模型里放两个高度相关的变量会让系数估计变得不稳定。5.2 用 VIF 检验多重共线性library(car) vif(mod1)VIF 的通用判断标准是超过 10 就说明共线性问题明显超过 5 就要警惕。我这轮跑出来的两个对数体型变量 VIF 都超过了 10这正是我担心的结果。两个变量在模型里互相抢功劳虽然整体拟合没问题但单个变量的系数含义变得不可靠。解决思路有三个只保留一个体型变量。如果研究重点是身体大小如何影响睡眠保留体重即可。如果研究重点是脑容量在控制体重后是否还有独立影响可以采用相对脑重这样的复合指标也就是brainwt / bodywt。用更复杂的正则化方法或主成分回归但对这个体量的练习项目来说没有必要。我这次采用第一个思路按研究问题选了log_bodywt重新构建模型mod2 - lm(sleep_total ~ log_bodywt vore, data msleep_model) summary(mod2)5.3 模型结果怎么向非技术读者解释mod2的核心结论可以这样表述在控制食性之后体重每提高一个数量级睡眠总时长平均显著缩短。而vore各组的系数在控制体重后基本不再显著说明先前箱线图里看到的食性差异很大程度上是因为不同食性的物种体型本身不同——食虫动物普遍小巧植食动物普遍庞大。这里我要特意强调一个写作层面的细节模型结果写进报告时应该用通俗语言讲清楚每提高一个数量级睡眠缩短多少小时而不是只丢一个 p 值。我在解释mod2时会把系数换算成实际量纲比如体重从 1 kg 增加到 10 kg预测睡眠时长大约减少多少小时这样读者有直观感受。5.4 诊断图与扩展思路plot(mod2)诊断图主要看两个残差与拟合值图、Q-Q 图。sleep_total本身有轻度偏态所以残差图可能会呈现一定的喇叭形态Q-Q 图在尾部也可能偏离正态线。作为基线模型可以接受但如果想让结果更漂亮可以尝试对sleep_total做对数变换后再建模或者考虑使用稳健回归。另外这个数据集后续还能做很多扩展按order作为随机效应做混合模型、用sleep_rem和sleep_cycle做多变量分析、用聚类算法把 83 个物种按睡眠模式分组甚至用随机森林做变量重要性排序。如果是要拿这个项目去面试或者交作业我建议至少往其中一个方向深入一步而不是停在线性回归。最后分享几点实操体会这套数据我完整跑下来最深的体会是拿到一份不太起眼的小数据集耐心把缺失值、变量关系、模型诊断都走一遍能学到的东西比单纯背语法多得多。做分析时一定要带着具体问题去跑代码比如体型和睡眠到底什么关系食性能不能解释睡眠差异而不是机械地逐行执行命令否则很容易画完图就不知道下一步该干什么。另外还有一个小技巧msleep里有个别物种和常见印象很不一样比如大熊猫睡得多、大象睡得少这些具体物种在画图时如果被标记出来会让你的分析报告很有记忆点。你可以用filter(msleep, name Panda)这类代码找出它们的确切数值在报告里作为典型案例讨论。如果你打算把它整理成作品集项目建议报告结构按问题定义—数据清洗—探索可视化—统计分析—结论与局限来组织这套结构本身就是一个很标准的数据分析工作流比贴一堆代码截图要有说服力得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑