
简介面向数据分析初学者与从业者这份以智能手机价格数据集为对象的实操案例完整演示了从数据清洗、整理、探索到可视化的分析流程。数据以CSV格式存储涵盖品牌、型号、屏幕尺寸、处理器速度、内存、存储容量、摄像头规格、发布日期与价格等字段可借助Excel、SPSS或Python进行多维度探索分析。压缩包共3个文件包含原始CSV数据集、可交互查看的HTML可视化报告、记录完整分析步骤的IPython Notebook代码整体仅1.07MB轻量易下目前已有189人浏览学习。通过运行附带的Jupyter代码读者能生成价格分布、品牌价格对比、性能与价格关系等图表直观揭示智能手机价格与品牌、配置等因素的关联同时掌握数据预处理与可视化表达的核心技能既辅助企业优化定价策略也为消费者选购提供参考。1. 从一个案例包看懂智能手机价格数据能分析出什么搜到「智能手机价格数据集可视化分析数据集代码.rar」这种压缩包时很多人的第一反应是解压、跑代码、看图。但真正让这个案例有价值的地方不是画几张图而是回答一个具体问题为什么同一时期的智能手机价格区间能差出好几倍数据集里通常包含 RAM、电池容量、屏幕像素、摄像头参数、机身重量等硬件指标以及一个代表价格档位的标签列。可视化分析要做的事情就是把这些硬件指标和价格档位之间的关系用图表展现出来——哪项指标对价格影响最大哪些指标之间有强相关性哪些指标看似重要实则区分度很低。这篇文章按最常见的 Python Pandas Matplotlib/Seaborn 路线把整套分析流程拆开讲数据读入与清洗、价格分布可视化、特征相关性分析、区分度验证最后落在可复现的代码写法上。适合刚接触数据分析项目、想拿现成数据集练手或者准备把它改写成简历项目的开发者。2. 数据集结构认知与 pandas 读入清洗先摸清价格档位怎么来的2.1 压缩包里常见的文件结构与字段命名这个案例包通常包含一个 CSV 或 Excel 格式的手机规格表外加一份 Jupyter Notebook 或.py脚本。数据集的使用方式是pd.read_csv()直接读入但在读入之前需要先确认字段含义因为这类数据集没有标准字典不同来源的命名略有差异。比较常见的列有battery_power毫安时、blue是否支持蓝牙、clock_speed主频 GHz、dual_sim是否双卡、fc前置摄像头像素、four_g、int_memory内部存储 GB、m_dep厚度、mobile_wt重量、n_cores核心数、pc主摄像头像素、px_height/px_width分辨率、ram内存 MB、sc_h/sc_w屏幕尺寸、talk_time续航、three_g、touch_screen、wifi以及目标列price_range取值一般为 0、1、2、3分别对应低成本、中成本、高成本、极高成本四档。import pandas as pd df pd.read_csv(smartphone_price.csv, encodingutf-8) print(df.shape) print(df.dtypes) print(df[price_range].value_counts().sort_index())df.shape看行数和列数dtypes检查每个字段的类型是否合理。price_range的value_counts()用来确认四档样本量是否均衡——如果某一档只有几十条后续画箱线图时该组的统计意义会打折扣。这种字段检查是可视化之前最容易被跳过的环节但恰恰决定了后续图表的可信度。2.2 缺失值、重复行与异常值的处理策略这类公开数据集通常已经做过基本清理但并不能因此跳过检查。缺失值处理上数值型字段可以先用isna().sum()统计缺失数量如果缺失占比低于 5%常见做法是用中位数填充因为手机硬件参数往往存在偏态分布均值会被极端值拉偏。重复行用df.duplicated().sum()检查有重复直接drop_duplicates()去掉。# 缺失值统计 missing df.isna().sum() print(missing[missing 0]) # 中位数填充 for col in [battery_power, ram, px_height]: if df[col].isna().any(): df[col] df[col].fillna(df[col].median()) # 去重 df df.drop_duplicates().reset_index(dropTrue) # 异常值检查看价格档位中 ram 的最小/最大值 print(df.groupby(price_range)[ram].agg([min, max, median]))注意reset_index(dropTrue)的作用去重后索引会出现空洞不重置的话后续iloc或按索引合并时容易踩坑。异常值不用急着删先看分组统计——比如高价格档出现 RAM 极低的情况可能是真实低配高价机型也可能是数据录入错误。这类个案建议单独拿出来观察而不是直接剔除保留异常值有时反而能发现更有意思的业务问题。2.3 把价格档位从标签转化为可解释的分组price_range是整数标签可视化时需要把它映射成可读的字符串分组方便图例和标题展示。映射关系可以根据数据集自带的说明文档确认如果没有说明常见的对应关系是0 对应「低端」1 对应「中端」2 对应「高端」3 对应「旗舰」。需要注意这个映射只是语义化不改变原始数据的数值千万不要把它转成category类型后参与数值运算。price_map {0: low, 1: mid, 2: high, 3: flagship} df[price_label] df[price_range].map(price_map) # 按组统计常用硬件指标的中位数 group_summary df.groupby(price_label)[ [ram, battery_power, px_height, mobile_wt] ].median().round(0) print(group_summary)分组统计表格是可视化的前置参考如果不同价格档位的 RAM 中位数差异明显说明该字段与价格高度相关值得重点画图如果差异不大则要考虑它是否有交互作用——比如ram与int_memory组合起来才能体现机型定位。groupby中传入列表来选择多个列返回的是一个新的 DataFrame使用round(0)是为了让打印结果更清爽实际运算不受影响。3. 价格分布可视化的三张核心图直方图、箱线图与相关性热力图3.1 用直方图看连续字段的整体分布形态第一类图表是单变量分布图观察 RAM、电池容量、屏幕分辨率等字段的分布形态。使用matplotlib的hist或seaborn的histplot都可以。偏态分布很常见电池容量和 RAM 往往集中在几个标准档位比如 2000mAh、3000mAh、4000mAh对应不同价位段的公版方案。import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei, Arial Unicode MS] plt.rcParams[axes.unicode_minus] False fig, axes plt.subplots(1, 2, figsize(14, 5)) sns.histplot(df, xram, bins30, kdeTrue, axaxes[0], color#4C72B0) axes[0].set_title(RAM 分布直方图, fontsize14) axes[0].axvline(df[ram].median(), colorred, linestyle--, label中位数) sns.histplot(df, xbattery_power, bins30, kdeTrue, axaxes[1], color#DD8452) axes[1].set_title(电池容量分布直方图, fontsize14) axes[1].axvline(df[battery_power].median(), colorred, linestyle--, label中位数) plt.tight_layout() plt.savefig(dist_hists.png, dpi150) plt.show()bins30控制分组数量数据集样本量在 1000 到 2000 条时30 个 bin 能保留细节又不会太碎。kdeTrue叠加核密度曲线帮助判断分布是否双峰——如果 RAM 分布出现双峰往往意味着数据集中混入了明显的高端和低端两批机型。axvline画中位数参考线用来跟均值对比判断是否右偏。中文字体设置是必须做的否则坐标轴标题会显示成方块Linux 环境如果没装 SimHei需要换成系统支持的中文字体或者直接用英文标签。3.2 箱线图对比不同价格档位的字段差异第二类图表是分组箱线图这是验证某个硬件指标对价格区分度的最直接方式。看ram和price_label的关系如果四个箱体位置依次抬高且重叠很少说明 RAM 是一个强区分特征如果箱体重叠严重说明该特征不足以单独解释价格差异。fig, axes plt.subplots(1, 2, figsize(14, 5)) order [low, mid, high, flagship] sns.boxplot(datadf, xprice_label, yram, orderorder, axaxes[0], paletteBlues, showfliersFalse) axes[0].set_title(各价格档位 RAM 对比箱线图) sns.boxplot(datadf, xprice_label, ybattery_power, orderorder, axaxes[1], paletteGreens, showfliersTrue) axes[1].set_title(各价格档位电池容量对比箱线图) plt.tight_layout() plt.savefig(box_group_compare.png, dpi150) plt.show()order参数显式指定箱子顺序否则 seaborn 会按字母序排列成图后解读起来会乱。showfliersFalse表示不显示离群点适合 RAM 这种本身分布集中、偶有极端值的字段电池容量那幅图保留离群点是为了观察是否存在低端机配大电池这种反直觉个案。箱线图的信息密度很高箱子位置看中位数差异箱体宽度看四分位距须的长度看尾部分布。中途如果发现某个价格档位的箱子明显比别的高且窄说明该档位内部配置趋同定价策略上更依赖品牌而非硬件。3.3 相关性热力图识别字段间的共线关系第三类图表是相关性热力图用于识别硬件指标之间的线性相关性。价格档位与 RAM 的相关性普遍最高通常能到 0.9 以上而px_height与px_width之间存在天然强相关因为分辨率由两者共同决定。num_cols [battery_power, ram, px_height, px_width, int_memory, mobile_wt, n_cores, price_range] corr df[num_cols].corr() plt.figure(figsize(10, 8)) sns.heatmap(corr, annotTrue, fmt.2f, cmapRdBu_r, center0, squareTrue, masknp.triu(np.ones_like(corr, dtypebool), k1)) plt.title(硬件参数与价格档位相关性热力图) plt.tight_layout() plt.savefig(corr_heatmap.png, dpi150) plt.show()annotTrue显示数值fmt.2f保留两位小数。mask参数隐藏上三角避免重复展示。center0表示颜色映射以 0 为中点正相关显示为红色系负相关为蓝色系视觉上更直观。解读热力图的关键不是找最大数而是看结构如果ram和int_memory相关系数也很高后续做回归或分类模型时要考虑多重共线性问题。热力图本身不做因果判断它只告诉你「哪些变量倾向于一起变化」但在这个数据集里它已经足以支撑结论——RAM 是与价格档位线性关系最强的硬件指标。4. 特征区分度检验散点矩阵与分组统计交叉验证4.1 用散点矩阵观察多变量交互与价格档位边界相关性热力图只能描述两两线性关系当需要同时看三个以上变量时seaborn.pairplot是更直接的工具。把ram、battery_power、px_height和price_label同时放进散点矩阵每个子图按价格档位着色能直观看到不同档位在二维平面上是否可分。sample_df df.sample(n200, random_state42) sns.pairplot( sample_df, vars[ram, battery_power, px_height], hueprice_label, hue_order[low, mid, high, flagship], paletteSet1, diag_kindkde, plot_kws{alpha: 0.6, s: 15}, ) plt.savefig(pairplot_sampled.png, dpi150) plt.show()sample(n200, random_state42)不是必须的但如果原始数据有 2000 条散点矩阵会画出几十万个点PDF 或 PNG 渲染时文件体积大、开图慢抽样后读图体验更好。random_state42固定随机种子保证每次运行抽到的样本一致这是复现性的基本要求。diag_kindkde让对角线显示密度曲线而不是直方图曲线重叠部分越少说明该特征对价格档位的区分能力越强。看图时重点观察同类颜色的点是否聚在一起、不同颜色之间是否边界清晰——RAM 字段通常能看到明显的横向分层而battery_power的点会混在一起说明仅凭电池容量很难判断价格。4.2 分组统计验证可视化结论数值不能只靠眼睛散点矩阵和箱线图给出的是视觉证据视觉结论还需要数值交叉验证。计算每个价格档位下各字段的均值、标准差并使用百分位数判断重叠程度是验证「某个特征对价格有区分度」的常用方法。verification ( df.groupby(price_label)[ram] .agg([count, mean, median, std, lambda x: x.quantile(0.25), lambda x: x.quantile(0.75)]) .round(0) ) verification.columns [数量, 均值, 中位数, 标准差, P25, P75] print(verification) # 检查相邻档位的 P75 与 P25 是否重叠 for i in range(3): low_tier [low, mid, high, flagship][i] high_tier [low, mid, high, flagship][i 1] overlap min(verification.loc[high_tier, P75], verification.loc[low_tier, P75]) - max( verification.loc[high_tier, P25], verification.loc[low_tier, P25]) print(f{low_tier} 与 {high_tier}: 四分位距重叠量 {overlap:.0f})这段代码的意义在于把「看图觉得有区分度」转成「数值上不重叠」。四分位重叠量为负数时说明两个价格档位之间至少有 75% 的样本在 RAM 上完全分开这是一个非常强的验证信号。lambda x: x.quantile(0.25)是自定义聚合函数的写法pandas 的agg接受可调用对象所以这种匿名函数可以直接传入。如果后续要写进报告可以把输出数值放在箱线图下方作为图注。4.3 可视化大屏思路对这份案例的意义热词里频繁出现「可视化大屏」但这份价格数据集不太适合直接做大屏原因是它没有时间维度和地理维度缺少大屏最常用的两个叙事轴。如果想把案例往大屏方向扩展需要自己构造维度比如把price_range映射为不同色阶用卡片展示各档位占比用雷达图对比旗舰机与低端机的多维度均值差距。这种改造成本不高但能让项目展示界面更有视觉冲击力。常规做法是用plotly生成交互式图表再用flask或streamlit包一层网页服务。「企业级数据可视化」通常强调的不只是美观而是信息层级——先看总量再看分组最后看异常值这个顺序不要打乱。5. 复现一份完整分析报告输出配置、随机种子与常见卡点5.1 图表输出的统一样式与高清保存参数分析做完后图表往往要放进报告或幻灯片。统一样式能省去大量后期处理时间推荐在脚本开头设置全局绘图参数plt.rcParams.update({ figure.dpi: 120, savefig.dpi: 200, font.size: 11, axes.spines.top: False, axes.spines.right: False, })savefig.dpi200适合 16:9 幻灯片插图文字边缘清晰但文件体积可控。figure.dpi120控制屏幕显示时的默认分辨率分析过程中缩放窗口不会糊。去掉上边框和右边框是现代的图表风格比默认的全边框更干净。如果图表数量超过六张建议按功能分文件保存fig/dist_hists.png、fig/box_compare.png、fig/corr_heatmap.png、fig/pairplot.png目录在代码里用os.makedirs(fig, exist_okTrue)自动创建。5.2 操作时最常见的三个报错与对应解法第一类报错是UnicodeDecodeError: utf-8 codec cant decode byte。原因是压缩包里的 CSV 可能是 GBK 或 Latin-1 编码读入时指定encodinggbk或encodinglatin-1即可。第二类报错是 seaborn 的palette传入了无效值新版 seaborn 对调色板名称校验更严格统一使用paletteBlues这种注册名最稳妥。第三类报错在df[price_range].value_counts()阶段不明显而是在画热力图时由于列名包含中文导致matplotlib字体告警处理方式只有一种把plt.rcParams[font.sans-serif]设置为已安装的中文字体然后执行plt.rcParams[axes.unicode_minus] False。5.3 复现时务必固定三处随机数这个案例的代码里包含随机元素时必须固定随机种子才能保证别人的运行结果与你看过的一致。三处最容易遗漏的随机源是df.sample()抽样、train_test_split划分训练集、模型初始化参数。即便当前代码里没有建模环节只要后续加了分类器或聚类随机种子的差异就会导致图表中的散点分布不同。建议在脚本入口统一设置import numpy as np np.random.seed(42) random_state 42代码写完后用python script.py完整跑一遍确认输出目录下生成的图片与print结果一致。在 Jupyter Notebook 里逐格运行通过的代码不代表脚本化后还能跑通——最常见的问题是plt.show()阻塞或%matplotlib inline失效。笔记转脚本时把plt.show()替换为plt.savefig()并加plt.close()就能避免保存了大量相似图片却不小心关掉当前窗口的问题。本文还有配套的精品资源点击获取