简介:面向数据分析初学者、消费电子市场研究者及智能手机行业从业者的智能手机价格可视化分析资料包,聚焦品牌、型号、屏幕尺寸、处理器速度、内存大小、存储容量、摄像头规格、发布日期、价格等核心字段,通过真实数据集揭示价格与配置、品牌之间的深层关联。压缩包内共3个文件:csv格式原始数据集、ipynb交互式分析代码和html结果展示页,整体仅1.07MB,轻量易用,既可直接用Excel、SPSS打开观察数据,也可在Jupyter Notebook中运行代码复现分析全过程。代码覆盖数据清洗、数据整理、数据探索与可视化等关键环节,能够生成价格分布图、品牌价格对比图、性能与价格关系图等,直观呈现影响智能手机定价的主要因素。目前已有189人学习/下载,对于企业制定市场策略、确定产品定价,以及消费者挑选高性价比机型,都具有切实的数据参考价值。
1. 智能手机价格数据集可视化分析:配置数字和定价之间藏着哪些信息
智能手机价格数据集是数据分析教学里很典型的一份表格数据:每行是一部手机,列是电池容量、内存、摄像头像素、屏幕分辨率、重量等硬件参数,最后一列把手机划成 0 到 3 四个价格等级。很多人拿到它直接去做分类建模,却跳过了可视化分析这一步。恰恰是这一步能回答一个关键问题:这个数据集里,到底是什么在决定手机的价格。配置数字和最终定价之间不是一笔直账——大电池不一定对应高价位,双卡和 4G 功能在低价机里反而出现得更频繁。把表格用 pandas 读进来,再用 matplotlib 和 seaborn 画几张图,就能在建模前把特征与价格的关系摸清楚。这个案例适合学过 Python 基础、想练数据清洗和可视化图表的人,跑通一遍之后,换任何一张新的业务表格都能复制同样的分析路径。
2. 数据准备:读取智能手机价格数据集并完成字段清洗
拿到“数据集 + 代码”这种组合的压缩包,解压后通常会看到三个部分:一个存放表格文件的 data 目录、一两个 .ipynb 或 .py 的代码文件、以及数据说明文档。我一般不会直接打开代码跑,而是先自己读一遍数据。因为看别人写的可视化代码,远不如自己从 DataFrame 开始走一遍清洗流程,能记住的字段含义更多,后面调图也更有底气。
2.1 解压 .rar 后先理清数据集字段:20 个硬件指标里哪些能用于定价分析
公开渠道常见的智能手机价格数据集一般是 CSV 格式,2000 行左右,每行一部手机,列名全部是英文缩写。字段之间差异很大,有的直接决定价格等级,有的几乎不影响。下面这张表列出了分析时要重点关注的字段,便于后续看图时能快速对应上硬件含义。
| 字段名 | 含义 | 对定价分析的作用 |
|---|---|---|
| battery_power | 电池总容量(mAh) | 续航配置,常用于判断硬件成本 |
| ram | 运行内存(MB) | 与价格等级相关性通常最高的指标 |
| int_memory | 内置存储(GB) | 存储配置,影响中高端定位 |
| px_height / px_width | 屏幕分辨率像素 | 反映屏幕素质,按两个方向分别记录 |
| mobile_wt | 手机重量(g) | 材质与机身体验的间接信号 |
| n_cores | CPU 核心数 | 处理器档位的一维近似 |
| fc / pc | 前置 / 主摄像头像素 | 影像能力,营销重点参数 |
| price_range | 价格等级 0 低 1 中 2 高 3 极高 | 本次分析的目标变量 |
读取这类 CSV 时不需要做额外转换,pandas 能直接解析。但列名是缩写,字段单位也不统一,所以读进来第一件事不是画图,而是把列看完、把缺失和类型确认掉。
2.2 用 pandas 读取 CSV 并检查缺失、类型与重复值
这里用 pandas 完成读取,encoding参数要按文件实际编码调整,常见的是utf-8或gbk。如果你的文件是 Excel 另存的 CSV,列尾可能带着不可见空格,忽略这一步后面按列名筛选时会莫名报错。
import pandas as pd df = pd.read_csv('train.csv', encoding='utf-8') print(df.shape) print(df.info()) print(df.isnull().sum()) df.columns = [c.strip().lower() for c in df.columns] df = df.drop_duplicates().reset_index(drop=True)shape能快速看出规模,info()输出每列的非空数量与数据类型,isnull().sum()定位缺失位置。strip().lower()是为了统一列名格式,避免Price_Range和price_range这种大小写不一致导致后面取值失败。drop_duplicates在这类公开数据集中通常不会删掉多少行,但重复样本一旦混进相关性分析,会让某些特征与价格的相关系数被轻微放大。清洗后的数据就可以进入描述统计阶段了。
print(df.describe().T)describe()默认输出均值、标准差、分位数,转置后按字段排列。看这一张表能快速发现两个问题:一是字段量纲差异巨大,ram动辄上千 MB,而n_cores只有个位数,后面画热力图前需要统一处理;二是某些字段的标准差很小,说明数据分布集中,后续分组对比时它的区分度会偏弱。
2.3 构造 price_label:把 0-3 的价格等级映射成可读标签
原数据里的price_range是离散字符,0、1、2、3 四个档位。直接用数字画图,图例上会出现“0 1 2 3”,看图的同事还得回忆哪个数字对应哪个档位。我会在分析前生成一个可读标签列,不改动原始列,只在可视化时作为分组依据。
df['price_label'] = df['price_range'].map({ 0: '低价', 1: '中价', 2: '高价', 3: '极高' }) print(df.groupby('price_label')['price_range'].count())map是 pandas 里做字典映射最直接的方式,比replace少一层复制。分组计数用来确认四档样本量是否均衡,样本量太少的组在后续箱线图里会缺乏说服力。如果某一档只有几十行,后面分析它的均值差异时要特别标注“样本量小,结论仅供参考”。字段准备好之后,就可以进入正式的图表绘制环节。
3. 单变量与多变量可视化:价格分布与特征关系的图表拆解
python 数据分析与可视化到这个阶段,核心已经不再是 API 调用,而是“每张图想回答什么问题”。建议按这个顺序推进:先看目标变量分布,建立对数据集的整体印象;再看单个特征在不同价格等级下的差异;最后才用散点和热力图找特征之间的关系。这样每张可视化图表的结论都能衔接到下一张图的设计上。
3.1 价格区间计数与电池容量直方图:先看分布再谈关系
第一张图拆成两个子图:左边用countplot画价格等级的样本数量,右边用histplot画电池容量分布。价格等级计数的意义在于确认类别平衡;电池容量直方图则是典型的单变量分布观察,看它是否符合常识预期,比如是否集中在 1000-2000 mAh 附近。
import matplotlib.pyplot as plt import seaborn as sns plt.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'SimHei'] plt.rcParams['axes.unicode_minus'] = False fig, axes = plt.subplots(1, 2, figsize=(12, 4)) sns.countplot(data=df, x='price_range', ax=axes[0]) axes[0].set_title('各价格等级样本量') sns.histplot(data=df, x='battery_power', bins=30, kde=True, ax=axes[1]) axes[1].set_title('电池容量分布') plt.tight_layout() plt.show()bins=30控制直方图的分桶数量,kde=True叠加一条核密度曲线,用于观察分布是单峰还是双峰。tight_layout()防止两个子图的标题和坐标轴互相挤压。这个数据集的电池容量分布通常比较均匀地落在 500-2000 mAh 区间,没有明显的双峰结构,这说明单看电池容量无法把手机分成高价和低价两拨,后面需要用分组图进一步观察。
3.2 箱线图对比不同价格等级的 RAM 与内存:等级差异是否肉眼可见
箱线图是可视化分析里对比分组差异最稳的图形,它同时展示中位数、四分位距和离群点。把 RAM 和内置存储分别按price_range分组画出来,能直接看出高价组和低价组的中位数是否拉开了距离。
fig, axes = plt.subplots(1, 2, figsize=(12, 4)) sns.boxplot(data=df, x='price_range', y='ram', ax=axes[0]) axes[0].set_title('不同价格等级的 RAM 分布') sns.boxplot(data=df, x='price_range', y='int_memory', ax=axes[1]) axes[1].set_title('不同价格等级的内置存储分布') plt.tight_layout() plt.show()看箱线图的重点不是看有没有重叠,而是看中位数线的移动方向。如果price_range从 0 到 3 的过程中,RAM 箱体的整体位置逐级抬升,说明这个特征对价格等级有稳定的正向区分度。这个数据集里 RAM 通常是区分度最高的特征,四个箱体几乎不重叠,而内置存储的箱体之间交叉明显,区分能力弱很多。两张图放在一起,自然引出下一个问题:除了 RAM,还有哪些特征与价格等级同步变化?
3.3 散点图与相关性热力图:寻找与价格等级同步变化的特征
散点图适合看两个连续特征之间的联合分布,相关性热力图则把所有特征两两之间的关系压缩进一张矩阵图。这里把屏幕分辨率的两个方向参数放在散点图里,用hue区分价格等级,能直观展示不同档位在屏幕配置上的落点区域。
fig, axes = plt.subplots(1, 2, figsize=(14, 5)) sns.scatterplot(data=df, x='px_height', y='px_width', hue='price_range', alpha=0.5, ax=axes[0]) axes[0].set_title('屏幕分辨率与价格等级') corr = df.select_dtypes(include='number').corr(numeric_only=True) sns.heatmap(corr, cmap='RdBu_r', center=0, vmin=-1, vmax=1, square=True, cbar_kws={'shrink': 0.8}, ax=axes[1]) axes[1].set_title('特征相关性热力图') plt.tight_layout() plt.show()alpha=0.5降低点的透明度,密集区域的颜色深浅就能反映样本密度,避免点与点互相遮盖。cmap='RdBu_r'让正相关显示为红色、负相关显示为蓝色,center=0强制白色对应相关系数 0。select_dtypes(include='number')自动排除对象型列,防止price_label这种文本列混入计算。热力图里信息量最大的是最后一行或最后一列:每个特征与price_range的相关系数。颜色越红,说明该特征与价格等级的正相关性越强。到这一步,已经能初筛出三到四个关键特征,下一步做分组量化验证。
4. 分组与相关性剖析:找出影响智能手机定价的关键指标
可视化图表给人的是直观印象,但印象要靠数字验证。这一章把上一步筛选出的特征拿来做分组聚合、相关系数排序和交叉表验证,回答一个明确的业务问题:哪些硬件指标真正推高了价格等级。所有操作都基于 pandas 的聚合与统计函数,不需要引入新的库。
4.1 按价格等级分组聚合:均值差异量化关键特征
分组聚合的意义在于把箱线图里的“视觉差异”转换成“数值差异”。对 RAM、电池容量、屏幕分辨率、重量等特征按price_range分组求均值,看它们随等级提升是否单调递增。
group_cols = ['ram', 'battery_power', 'px_height', 'mobile_wt', 'int_memory'] grouped = df.groupby('price_range')[group_cols].mean().round(1) print(grouped.T)groupby('price_range')把数据按目标变量分成四个子集,.mean()计算各特征的均值,.round(1)控制小数位,.T转置后特征变成行、价格等级变成列,更容易逐行观察递增趋势。表格中如果某个特征从低价到极高价的均值始终往上走,它就是定价的核心驱动特征;如果出现先升后降或来回波动,说明它和价格等级不是线性关系。我一般在分析记录里把单调递增的特征打上标记,后续做分类模型的特征筛选时优先保留。
4.2 用相关系数排序定位 Top 指标,并验证 RAM 的主导地位
分组均值看的是趋势方向,相关系数则给出一个可排序的强弱度量。计算每个数值特征与price_range的相关系数,然后按绝对值从大到小排序,是筛选特征最常用的做法。
corr_target = ( df.select_dtypes(include='number') .corr(numeric_only=True)['price_range'] .drop('price_range') .sort_values(ascending=False) ) print(corr_target.head(10))corr(numeric_only=True)计算整个数值矩阵,取['price_range']这一列后,用drop去掉自身,再按降序排列。排序结果里排在第一位的基本可以确定是ram,相关系数通常接近 0.9,远高于第二名。这里要提醒一个容易误读的点:相关系数衡量的是线性相关强度,相关系数高不代表因果关系。RAM 高和价格等级高同步出现,原因可能是厂商在定价时把内存当作分档标尺,也可能只是这份数据生成时采用了这样的规则。可视化分析阶段只需如实描述“RAM 是与价格等级同步性最强的单个指标”,不需要下因果结论。
4.3 交叉表验证非数值特征:蓝牙、双卡和 4G 是否真的影响定价
这个数据集里除了连续数值列,还有几个取值为 0 或 1 的布尔类特征,比如蓝牙、双卡、4G、Wifi。这类特征进不了普通的相关性矩阵,但通过交叉表加normalize参数,可以看各价格等级中“支持某项功能”的占比差异。
cross = pd.crosstab(df['price_range'], df['four_g'], normalize='index') print(cross.round(3)) cross2 = pd.crosstab(df['price_range'], df['dual_sim'], normalize='index') print(cross2.round(3))pd.crosstab默认输出频数,normalize='index'把每一行的数值归一化成该价格等级内的比例,.round(3)让小数位更易读。four_g这个特征在生成数据时使用逻辑回归的方式做了关联采样,因此在低价区间支持 4G 的比例更低。真实业务里,4G、双卡这类功能往往是入门机的标配,反而可能出现在低价位段,所以不要把这套结论直接迁移到真实手机销售数据上。交叉表验证的通用价值在于:布尔特征也可以进入可视化分析流程,并且能用与连续特征不同的展示方式独立得出结论。
5. 图表落地与报告输出:把可视化结果变成可交付的分析产物
分析做完,代码里画了一堆图,真正要交付时却经常卡在三个细节:中文乱码、多图排版挤在一起、报告发出去别人无法复现。这一章把最后一步补齐,让分析结果从 Jupyter Notebook 里走出来,变成一份能直接发给同事的 HTML 文件。
5.1 统一中文字体与图表风格,避免可视化图表乱码与默认样式
matplotlib 默认字体不支持中文,直接设标题会出现方框。解决方法是统一设置字体族,并确保axes.unicode_minus关闭,否则负号在中文环境下会显示成方块。
import matplotlib matplotlib.rcParams['font.sans-serif'] = [ 'Noto Sans CJK SC', 'SimHei', 'Arial Unicode MS' ] matplotlib.rcParams['axes.unicode_minus'] = False提示:Windows 上通常能直接命中
SimHei,macOS 用Arial Unicode MS,Linux 服务器上需要先确认是否安装了Noto Sans CJK SC。字体设置应放在脚本开头,所有绘图代码之前。
把字体配置和sns.set_style('whitegrid')一起放进去,整套图表的风格就统一了,后续不用每张图重复设置标题字体大小和网格样式。
5.2 用 subplots 把四张核心图拼成一张结论大图
散落在多张图里的结论,拼接成一张大图才有叙事感。这里把价格分布、RAM 箱线图、分组均值折线、相关性 Top 特征四张图组合到subplots里,统一尺寸后导出 PNG。
fig, axes = plt.subplots(2, 2, figsize=(14, 10)) sns.countplot(data=df, x='price_range', ax=axes[0, 0]) sns.boxplot(data=df, x='price_range', y='ram', ax=axes[0, 1]) sns.lineplot(data=df.groupby('price_range')['battery_power'].mean(), marker='o', ax=axes[1, 0]) sns.barplot(data=df, x='price_range', y='ram', estimator='median', ax=axes[1, 1]) fig.suptitle('智能手机价格数据集可视化分析结论图', fontsize=16) fig.tight_layout(rect=[0, 0, 1, 0.96]) fig.savefig('phone_report.png', dpi=150, bbox_inches='tight')figsize=(14, 10)保证导出后每个子图都清晰可读,dpi=150满足打印和屏幕分享两种场景,bbox_inches='tight'去掉多余留白。tight_layout(rect=...)给suptitle让出顶部空间,避免大标题被裁剪掉。拼图的价值不在于展示更多图表,而是让看图的人按顺序读一遍:样本分布均匀、RAM 随价格等级递增、电池容量整体同步上升、RAM 中位数分级明显,四张图形成一个完整论证链条。
5.3 一键输出 HTML 分析报告:让代码跑完直接出交付物
拿到结论图之后,最后一步是把图片嵌入一个自包含的 HTML 文件,用base64把 PNG 转成内嵌数据。这样交付的只有一个 .html 文件,不依赖图片路径,打开就能看。
import base64 with open('phone_report.png', 'rb') as f: img_b64 = base64.b64encode(f.read()).decode() summary_table = df.groupby('price_label')[['ram', 'battery_power']].mean().round(1).to_html() html = f""" <html><head><meta charset="utf-8"> <title>智能手机价格数据集可视化分析报告</title></head> <body> <h1>价格等级特征差异</h1> {summary_table} <h2>核心结论图</h2> <img src="data:image/png;base64,{img_b64}" style="width:100%;max-width:960px;"> </body></html> """ with open('report.html', 'w', encoding='utf-8') as f: f.write(html)b64encode(f.read()).decode()把二进制图片转成字符串,嵌入src的data:image/png;base64,...前缀,浏览器就能直接渲染。to_html()把 pandas 的 DataFrame 转成表格标签,中间不需要手写一行 HTML 结构。这份report.html可以脱离 Jupyter 环境单独打开,也方便直接放进日报附件。
本文还有配套的精品资源,点击获取