二手车交易数据分析与可视化:从清洗到交互看板的完整实践
简介二手车交易数据分析与可视化系统是一份面向数据分析学习者与前端开发者的综合实战资源。项目整合网络爬虫、前后端分离架构、MySQL数据库存储以及Pandas/NumPy数据分析流程最终通过Echarts、Plotly等交互式图表呈现二手车价格、里程与市场趋势帮助用户快速读懂交易数据规律并辅助购车决策。资源压缩包共104个文件约1.63MB主要包含31个Python脚本、16个HTML页面、16个JavaScript文件、4个CSS样式、5个XML配置、3个JSON数据以及1个SQL建库脚本和2个批处理启动文件覆盖从数据采集、清洗分析到可视化展示的完整链路。已有297人学习。下载后可直接获得完整项目源码、数据库初始化脚本、依赖清单与项目说明箱线图等分析页面开箱即用适合课程设计、毕业设计或数据分析实战项目参考便于二次开发与功能扩展。1. 二手车交易数据分析与可视化先回答三个问题再动手拿到这套二手车交易数据分析与可视化系统我没有急着解压跑脚本而是先问了三个问题车价到底由哪些字段决定、哪类车保值率最高、不同城市差价有多大。这套资源把答案拆成数据文件、清洗脚本、分析模块和图表模板四块覆盖从原始 CSV 到可视化看板的完整链路。它的定位不是教学 Demo而是一套能换数据复用的分析管线。适合两类人想用真实交易数据练手的数据分析师新人以及需要给收车、定价做参考的从业者。只要会基础的 Pandas 就能跟上不需要额外装重型平台。2. 拆包看结构一套二手车分析系统的标准四件套解压一个资源包最忌讳的是双击主脚本直接跑。我一般先把目录树打出来分清哪些是输入、哪些是处理脚本、哪些是输出目录再决定从哪一步开始验证。这套系统沿用数据分析项目最常见的四段式结构data 目录放原始交易记录和参考价表clean 目录放清洗脚本analysis 目录放聚合与绘图代码output 目录放运行后生成的图表。如果压缩包里只有一堆 .py 和 .csv 混在一起自己先按这个结构归类后面改参数会省很多事。常见的文件布局如下表所示路径类型内容说明data/raw_trade.csv数据集二手车主表含车辆型号、登记日期、里程、排量、变速箱、车况等级、成交价、所在城市data/ref_price.csv数据集同款车型参考价表用于计算保值率clean/data_clean.py脚本清洗主流程输出清洗后的宽表analysis/analysis.py脚本按品牌、车龄、城市做聚合统计analysis/visualization.py脚本绘图输出 HTML 图表到 output/output/输出目录脚本运行后生成的图表文件提示如果看到 data_clean_new.py、data_clean_v2.py 这类同功能脚本以修改时间最新的为准旧版本归档到 backup 目录别在主流程里混着 import。两份脚本各改一半导致结果对不上是这类资源最常见的翻车现场。2.1 先读字段再动手数据字典与常见脏值不管压缩包里有没有附带 README我拿到数据后的第一步永远是把它读进来看一眼 shape 和 dtypes而不是直接开始写聚合。原始表通常是 CSV 或 Excel 导出的文本编码、分隔符、空值表达都可能和你默认的不一样。import pandas as pd df pd.read_csv( data/raw_trade.csv, encodingutf-8, na_values[暂无, 面议, 未知, ], parse_dates[登记日期] ) print(行列数, df.shape) print(df.dtypes) print(df.head(3).T)代码说明na_values 把「暂无」「面议」「未知」这类文本型缺失值直接声明成 NaN避免后面聚合时被当成一个独立分类parse_dates 把登记日期从字符串转成 datetime 类型后面按年、按季度聚合才方便。head(3).T 转置打印是为了在一屏内同时看全所有字段的样例值字段多的时候比 head(3) 直观。dtypes 输出里凡是 object 类型的列基本都是需要清洗的字段。常见脏值包括成交价写成「12.5万」甚至「面议」里程写成「3.2万公里」排量写成「1.5L」或「1.5T」登记日期混着「2024/1/1」「20240101」「2024-01-01」三种格式。下面这张表是我按这个资源最常见的字段口径整理的不同压缩包字段名会略有出入但语义基本一致。字段类型单位/取值常见脏值处理建议车辆ID字符串唯一标识重复记录drop_duplicates车辆型号字符串品牌车系大小写混杂统一大写登记日期datetime年月日三种日期格式parse_dates表显里程数值/字符串万公里空、0.01、调表值to_numeric 后过滤排量字符串L1.5L/1.5T正则提取数字变速箱字符串手动/自动/手自一体空缺失单独标记车况等级字符串A/A/B/C空、新映射成评分成交价字符串/数值万元面议、暂无清洗成 float所在城市字符串城市名带括号后缀归一映射字段口径不统一的后果往往不是报错而是悄悄产出错误图表。比如成交价如果保留「面议」两个字groupby 时会被当成字符串拼接画出的条形图莫名多出一根很高的柱子——这类问题排查起来很费时间。2.2 字段之间的隐性关系先定业务口径再定清洗顺序单独看每一列容易忽略字段之间的约束关系。这套数据里至少有三组关系值得在清洗前确认。第一车辆型号、登记日期和成交价三者能推导出车龄与保值率车龄出现负数或超过 30 年多半是登记日期有未来日期或商用车混入乘用车表第二表显里程与车龄不应严重背离一辆 3 年车龄的车显示 40 万公里要么是运营车辆要么是录入错误第三所在城市与成交价的分位数可以形成一个基本的异常检测区间城市 A 的均价常年高于城市 B如果某行城市 B 出现城市 A 水平的成交价先查是不是城市字段写错了。验证这些关系的快速做法是直接用 describe 看数值分布而不是只看 headdf[登记年份] df[登记日期].dt.year df[车龄] df[登记年份].apply(lambda y: 2025 - y) print(df[车龄].describe()) print(df[表显里程].describe()) print(df[成交价].describe())说明这里把 2025 当作数据快照年份实际使用时应该以资源里 README 标注的采集时间为准。describe 输出的 min、max 和 25%、75% 分位数能一眼暴露极端值成交价最小值如果是 0说明混入了定金记录表显里程最大值如果是 999说明原表把缺失值填成了 999。看到这些异常值再进清洗环节后面每一步才有明确的处理目标。还有个常见的踩坑点有人在读入时用 data_clean.py 里的逻辑先做了一遍处理再跑到这里来核对结果发现原始数据里根本没有那些异常值。为了避免这种误判读原始 CSV 和跑清洗脚本要分开验证我习惯单独开一个 notebook 文件只负责把原始数据 read 进来做探索不碰任何清洗逻辑。3. 把脏数据洗成分析宽表清洗顺序与四个关键参数数据清洗的目标不是把表变得越干净越好而是让每一列都能被后续聚合逻辑直接消费。以这份二手车交易表为例清洗要做三件事去重与类型转换解决缺失值处理异常值。顺序也重要先转类型再补缺失最后过滤异常这样每一步都基于上一步的结果报错和结果漂移都好定位。3.1 三步清洗框架去重、转类型、统一单位清洗脚本一般有三段。第一步按车辆 ID 去重保留第一条记录第二步把里程、价格这类字段转成数值类型转换时用 errorscoerce 把无法解析的值置成 NaN而不是让脚本直接报错中断第三步把成交价里常见的「万」「逗号」去掉统一单位。import pandas as pd import numpy as np def clean_trade_data(path): df pd.read_csv( path, encodingutf-8, na_values[暂无, 面议, 未知, ] ) # 第一步去重同一台车多次挂牌只保留首次记录 df df.drop_duplicates(subset[车辆ID], keepfirst) # 第二步里程、排量转数值解析失败的全部置为 NaN df[表显里程] pd.to_numeric(df[表显里程], errorscoerce) df[排量数值] df[排量].astype(str).str.extract(r(\d\.\d)).astype(float) # 第三步成交价去单位、去千分位统一成 float df[成交价] ( df[成交价] .astype(str) .str.replace(万, , regexFalse) .str.replace(,, , regexFalse) .astype(float) ) return df clean_df clean_trade_data(data/raw_trade.csv) print(clean_df.shape)参数说明drop_duplicates 的 subset 必须指定到车辆 ID全表去重可能会把不同挂牌记录误删keepfirst 保留第一行如果你更信任后录入的修正记录可以改成 keeplast。str.extract 用正则 (\d.\d) 抓排量数字能匹配「1.5L」「1.5T」这类写法匹配不到的变 NaN。read_csv 里的 na_values 是提前量把「面议」「暂无」这类文本在读取阶段就标成缺失比清洗到一半再 replace 更安全。这段函数写完之后先用 shape 看还剩多少行。如果行数比预期少太多别急着往下走先回到读取参数检查 na_values 是否误伤了真实值——比如有人把「未知」也当作缺失值而业务里「未知」是一种有效车况反馈。3.2 缺失值分三档能补的不删不能补的标记缺失值一刀切删除是最省事也最容易翻车的做法。我一般把缺失分成三档来处置。第一档是成交价缺失直接删行因为价格是本分析的主键任何填充都会扭曲结论第二档是表显里程缺失用同车龄中位数填充而不是全局中位数原因是一辆 3 年车和一辆 15 年车的里程分布完全不同全局填充会把低车龄样本的里程整体拉高第三档是车况等级缺失不填充数值单独归到「未知」级别参与聚合但不算入评分。# 同车龄里程中位数填充transform 保证返回与原表相同长度的序列 mileage_med clean_df.groupby(车龄)[表显里程].transform(median) clean_df[表显里程] clean_df[表显里程].fillna(mileage_med) # 车况等级缺失归入“未知”不作为缺失值参与后续过滤 clean_df[车况等级] clean_df[车况等级].fillna(未知) # 成交价或车辆型号缺失直接删行 clean_df clean_df.dropna(subset[成交价, 车辆型号])逻辑说明groupby(车龄) 先把数据按年份分组transform(median) 会把每个分组的中位数广播回原始行再 fillna 只填充缺失部分不改变已有值。这里车龄字段来自 2.2 节的计算结果如果还没算需要在清洗函数前补一行 df[车龄] 2025 - df[登记日期].dt.year。参数说明dropna 的 subset 参数只针对成交价和车辆型号两列判断避免把其他列的小缺失一起放大成整行删除。拆开写还有一个好处后续如果业务口径变化想保留「车辆型号缺失」的样本只需从 subset 里去掉一个字段名。3.3 异常值过滤分位数截断比标准差更抗长尾成交价分布是典型的长尾分布少数几十万甚至上百万的豪车会把均值拉得毫无业务意义。用均值 ± 3 倍标准差做异常值过滤会把右侧的正常豪车当成异常删掉。常见做法是用分位数截断取 1% 和 99% 分位数作为上下界结合业务阈值二次过滤。# 价格截断1% 到 99% 分位数 low, high clean_df[成交价].quantile([0.01, 0.99]) clean_df clean_df[ (clean_df[成交价] low) (clean_df[成交价] high) ] # 里程阈值燃油车常见区间为 0.1 万到 60 万公里 clean_df clean_df[clean_df[表显里程].between(0.1, 60)] # 车龄阈值0 到 20 年超过视为商用车或录入错误 clean_df clean_df[(clean_df[车龄] 0) (clean_df[车龄] 20)]参数说明quantile([0.01, 0.99]) 返回一个 Series分别赋值给 low 和 high。between(0.1, 60) 的上下界是业务经验值新能源车和商用车的阈值不同我一般把这类参数抽成配置文件的关键字参数比如 max_mileage60、max_age20换数据源时只改函数签名不碰主体逻辑。0.1 这个下限是为了去掉「0.01 万公里」这类新车数据里常见的录入异常。分位数截断的代价是左右两侧各削掉 1% 的真实样本对有 3 万条记录的数据集来说损失可以接受。如果样本量很小几千条把分位数改成 0.5% 和 99.5% 更稳妥。这个参数没有绝对的对建议先画分布直方图再定。3.4 衍生字段车龄段、车况分与价位段一次生成清洗的最后一步是生成分析阶段直接使用的衍生字段。车龄段按业务习惯切分车况等级映射成数值评分价位段用于后续对比分析。把它们全部放进一个函数里避免分析脚本里到处重复 cut 逻辑。# 车龄与车龄段区间右开5年以内包含第5年 clean_df[车龄] 2025 - clean_df[登记日期].dt.year bins [0, 5, 10, 15, 20, 100] labels [5年以内, 5-10年, 10-15年, 15-20年, 20年以上] clean_df[车龄段] pd.cut( clean_df[车龄], binsbins, labelslabels, rightFalse ) # 车况评分映射A 最优未知等级不参与评分 score_map {A: 5.0, A: 4.0, B: 3.0, C: 2.0, 未知: np.nan} clean_df[车况分] clean_df[车况等级].map(score_map) # 价位段用于分价位看不同区间的车龄和保值表现 price_bins [0, 3, 8, 15, 30, 100] price_labels [3万以下, 3-8万, 8-15万, 15-30万, 30万以上] clean_df[价位段] pd.cut( clean_df[成交价], binsprice_bins, labelsprice_labels, rightFalse )参数说明pd.cut 的 rightFalse 表示左闭右开区间[0, 5) 会把车龄 5 年的车分进「5年以内」符合业务直觉默认的 rightTrue 则把 5 分进「5-10年」很多第一次写的人会在这一步栽跟头。bins 和 labels 的长度必须一致多了少了都会抛 ValueError。价位段的切分边界可以根据资源里的实际价格分布调整3 万和 8 万是二手车行业里比较常见的心理价位分界。衍生字段生成后清洗宽表就算完成了。把它 to_csv 存成中间文件后续 analysis 和 visualization 都从这份中间表读这样每次改动清洗逻辑只需要重跑清洗脚本不用连带分析脚本一起折腾。4. 从聚合到图表四个分析维度与出图参数清洗宽表就绪后剩下的任务是回答开篇的三个问题价格由什么决定、哪类车保值、城市差价多大。可视化在这套系统里不只是画图而是帮助确认聚合口径是否正确。我习惯先出一个价格分布直方图再看分组聚合结果最后才配置图表样式。4.1 价格分布直方图与长尾判断第一步用直方图看成交价分布。如果直方图右侧拖着一条长尾说明均值会被极值拉高后续所有按价格聚合的字段都应该优先使用中位数而不是均值。import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False clean_df[成交价].hist(bins50, edgecolorwhite) plt.xlabel(成交价万元) plt.ylabel(交易记录数) plt.title(成交价分布直方图) plt.savefig(output/price_distribution.png, dpi150)参数说明bins50 把价格切成 50 个区间区间太粗看不出长尾太细会出现大量空柱子50 对多数二手车价格区间是个稳妥起点。edgecolorwhite 给柱子加白边避免相邻柱子在深色背景下糊成一片。保存图片时 dpi150用于报告打印足够如果只是网页展示 dpi96 文件更小。代码里的字体设置是个硬前提。matplotlib 默认字体不含中文字符不设置的话标题和轴标签都会变成方块。SimHei 在多数 Windows 环境可用macOS 上换成 PingFang SCLinux 一般用 Noto Sans CJK SC常见做法是写一个带候选列表的字体探测函数。4.2 品牌成交价排行中位数排序与横向条形图品牌榜是报告里最常出现的图。聚合时用 groupby 按品牌分组价格聚合函数用 median 而不是 mean然后排序取前 15 名。这里有个容易忽略的细节样本量太少的品牌中位数也不可信需要先做一个最小样本量过滤。from pyecharts import options as opts from pyecharts.charts import Bar # 按品牌算成交价中位数并要求品牌样本数不少于 30 brand_stats clean_df.groupby(品牌)[成交价].agg([median, count]) brand_stats brand_stats[brand_stats[count] 30] brand_stats brand_stats[median].sort_values().tail(15) bar Bar(init_optsopts.InitOpts(width900px, height520px)) bar.add_xaxis(brand_stats.index.tolist()) bar.add_yaxis( 成交价中位数万元, brand_stats.round(2).tolist(), label_optsopts.LabelOpts(positionright) ) bar.set_global_opts( title_optsopts.TitleOpts(title各品牌成交价中位数排行), xaxis_optsopts.AxisOpts(name品牌), yaxis_optsopts.AxisOpts(name成交价中位数万元) ) bar.reversal_axis() bar.render(output/brand_price.html)逻辑说明agg([median, count]) 一次性算出两个统计量先按 count 过滤掉样本少于 30 的品牌再对中位数排序取尾部 15 名。tail(15) 取的是中位数最高的一侧配合 reversal_axis 把条形图横过来品牌名就能完整显示在图左侧。pyecharts 渲染后是 HTML 文件浏览器直接打开即可交互查看柱子的数值明细。参数说明LabelOpts(positionright) 把数值标签放在柱子右端横向条形图里比默认的顶部标签更清晰InitOpts 的 width、height 影响输出画布尺寸默认 900px 宽在宽屏笔记本和投影上都合适如果嵌入网页的窄栏改小宽度并配上 formatter 隐藏长尾品牌名。4.3 车龄与价格联动折线图与样本量下限车龄和成交价的关系是二手车分析里最经典的一条曲线。聚合口径同样是中位数但车龄两端样本量天然偏少会出现曲线尾部突然翘起或掉落的假象。我一般只画 0 到 20 年区间并在生成前统计每个车龄的样本量。from pyecharts.charts import Line # 按车龄分组计算中位数和样本量 age_stats clean_df.groupby(车龄)[成交价].agg([median, count]) age_stats age_stats[(age_stats.index 0) (age_stats.index 20)] age_stats age_stats[age_stats[count] 20] line Line() line.add_xaxis([str(x) for x in age_stats.index.tolist()]) line.add_yaxis( 成交价中位数万元, age_stats[median].round(2).tolist(), is_smoothTrue, symbol_size6 ) line.set_global_opts( title_optsopts.TitleOpts(title车龄与成交价中位数关系), xaxis_optsopts.AxisOpts(name车龄年), yaxis_optsopts.AxisOpts(name成交价中位数万元) ) line.render(output/age_price.html)参数说明age_stats[count] 20 是个比较保守的样本量下限车龄 15 年以后样本量一般会跌到两位数以下这时候折线值波动剧烈画出来容易误导。is_smoothTrue 用平滑曲线代替折线视觉上更符合价格随车龄衰减的预期但记住平滑只是插值不改变原始数据点。add_xaxis 里把整数车龄转成字符串是为了避免 x 轴被 pyecharts 自动当成连续数值轴后在 0 和 20 之间插入非整数刻度。4.4 城市差价分组中位数与最小样本筛选城市对比用表格比用图更实用因为城市数量通常不多表格能同时展示中位数、样本量和市场热度。这张城市差价表可以直接贴在报告里比柱状图信息密度高。city_stats clean_df.groupby(所在城市)[成交价].agg([median, count]) city_stats city_stats[city_stats[count] 50] city_stats city_stats.sort_values(median, ascendingFalse) city_stats[median] city_stats[median].round(2) print(city_stats)逻辑说明按城市分组后先过滤样本量少于 50 的城市避免因为一条百万级豪车记录把某个小样本城市顶到榜首。sort_values 按中位数降序方便直接读出价格高地。这里演示的是控制台输出如果要给报告用to_excel 或 to_csv 导出即可表格本身不需要太多样式。常见的问题是城市名不统一比如「城市A」和「城市A(城区)」被当成两个组导致样本被拆散。我在清洗阶段会用一张别名映射表统一城市名先把常见后缀去掉再做聚合。这张映射表单独维护成一个 CSV业务人员也能直接改。4.5 三年保值率口径成交价与参考价的比值保值率是二手车分析里最被看重也最容易算错的指标。常见口径是三年车龄成交价中位数除以新车参考价参考价从 data/ref_price.csv 读取。计算时先按车辆型号 merge再筛选车龄 2 到 4 年的样本最后按品牌取比值的中位数。ref pd.read_csv(data/ref_price.csv, encodingutf-8) merged clean_df.merge(ref, on车辆型号, howleft) used_3y merged[merged[车龄].between(2, 4)] # 按品牌计算保值率样本数不足 10 的品牌不参与排名 retention ( used_3y.groupby(品牌) .apply(lambda x: (x[成交价] / x[参考价]).median(), include_groupsFalse) .sort_values(ascendingFalse) ) retention retention[retention.index.isin( used_3y.groupby(品牌).size()[lambda s: s 10].index )] print(retention.head(10))参数说明merge 的 howleft 以主表为准参考价缺失的车辆型号会留下 NaN后续计算会自动排除。车龄 between(2, 4) 选的是上了两年牌、平均 3 年左右的在售车这是行业里比较通用的“准三年”口径。apply 里计算的是比值的中位数比均值更稳。include_groupsFalse 是 pandas 2.x 的写法老版本如果报错去掉这个参数即可。最后补一个说明如果某品牌只有 3 台车比值算出来是 0.95 还是 0.6 都说明不了问题所以样本数下限 10 是必要的。如果你手里的数据量更大可以把下限提高到 20。5. 避坑与常见问题五条真实翻车记录写这一章之前我把这套资源和类似项目里最容易绊倒人的问题做了次盘点。每个问题都是先看到现象再追原因最后才找到解决路径按这个顺序写遇到类似情况可以直接对照排查。在逐个问题展开前先说一个通用排查习惯清洗脚本跑完先打印缺失率汇总和行数变化再去看图表这两个信息能定位 80% 的问题。def missing_report(df): miss df.isna().mean().round(4) return miss[miss 0].sort_values(ascendingFalse) print(missing_report(clean_df))说明isna().mean() 算每列缺失比例只打印有缺失的列避免输出刷屏。行数变化用 shape 前后对比出现单列缺失率超过 30% 就要警觉。5.1 清洗后数据少了四成问题出在缺失值一刀切现象跑完清洗脚本行数从 3 万掉到 1.8 万少了四成报告完全不敢用。原因清洗脚本里直接 dropna()不带任何参数把「面议」价格、缺失里程、缺失车况等级的行全部删掉了。实际上「面议」虽然不能直接当价格用但很多面议车在参考价表里有对应车型可以补一个参考价之后再保留。解决先统计每列缺失率再按缺失类型分档处置。成交价缺失才删行里程缺失用同车龄中位数填充车况等级缺失单独标记为「未知」。我在清洗函数里加了一个缺失率打印跑完先看输出行数掉得异常就回头查参数。5.2 图例中文变方块罪魁祸首是默认字体现象标题、轴标签正常但品牌名全部变成小方块图没法交付。原因matplotlib 默认字体不含中文字形Linux 服务器上尤其常见本机 Windows 跑得好好的脚本一部署到服务器就乱码。解决把字体配置放到绘图脚本的最前面写成带候选列表的探测函数先试 SimHei再试 PingFang SC、Noto Sans CJK SC找到可用字体再画图。另外别忘设置 axes.unicode_minusFalse否则负号也会显示成方块。5.3 品牌均价普遍偏高均值被豪车拉出幻觉现象某品牌的成交价均价冲到 28 万业务同事说不可能这个品牌主流车型集中在 8 到 12 万。原因几十台百万级豪车样本把均值的分子拉大了而中位数对这种长尾分布非常稳健。解决把价格聚合口径从 mean 改成 median。如果业务方坚持要均值用 scipy.stats.trim_mean 删掉上下 5% 的极值再求均值并在报告脚注里写明口径。从那以后我再写价格聚合第一反应就是 median不再默认 mean。5.4 车龄出现负数登记日期里有未来日期现象车龄列最小值为 -2折线图左端凭空多出一段下跌。原因原始表登记日期混入了录入错误的未来日期比如 2026-01-03当前年份是 2025算出来就是 -1。解决在清洗阶段过滤登记日期大于当前日期的行同时把当前年份抽成常量 CURRENT_YEAR 2025避免在清洗脚本和分析脚本里各写各的年份。常量统一维护明年再用这份数据只改一个数字。5.5 城市聚合被拆散同城不同名悄悄分流现象城市榜里「城市A」和「城市A(城区)」同时出现样本被拆成两个组中位数排名完全变形。原因源数据录入不规范同一个城市在不同系统导出时带了括号后缀或别名。解决维护一张城市别名映射表先用 str.replace 去掉常见后缀再用 map 统一城市名。映射表单独存 CSV而不是写在清洗代码里业务人员要加别名时不用碰代码。这五条每条都真实对应一个参数或一段逻辑排查时建议按出现的频率排序处理先看行数变化再看字体和图表异常最后查聚合口径。多数情况下问题根源就藏在这五类里。6. 进阶用法把静态图表升级成交互式筛选看板前面的图表各自独立放到报告里没问题但要探索「5 年以内、3 到 8 万价位、城市A」这类组合条件就得反复改参数重跑脚本。进阶做法是把出图逻辑封装成函数用 pyecharts 的 Tab 把不同筛选条件的图拼在一个 HTML 页面里方便自己排查也方便业务方自助看数。from pyecharts.charts import Tab def build_price_bar(min_price, max_price, max_age): subset clean_df[ (clean_df[成交价] min_price) (clean_df[成交价] max_price) (clean_df[车龄] max_age) ] stats subset.groupby(品牌)[成交价].median().sort_values(ascendingFalse).head(10) bar Bar(init_optsopts.InitOpts(width900px, height520px)) bar.add_xaxis(stats.index.tolist()) bar.add_yaxis(成交价中位数万元, stats.round(2).tolist()) bar.set_global_opts(title_optsopts.TitleOpts(titlef{min_price}-{max_price}万、{max_age}年内)) return bar tab Tab() tab.add(build_price_bar(1, 30, 5), 5年以内) tab.add(build_price_bar(1, 30, 10), 10年以内) tab.add(build_price_bar(3, 15, 10), 3-15万、10年内) tab.render(output/dashboard.html)参数说明build_price_bar 的三个入参直接对应筛选条件换数据源或换分析维度时只改调用处不改函数体。Tab 会把三张图分别放到 HTML 页面的三个标签页里点击切换即可对比。这个函数写法同样适用于 Line、Scatter后续加图表类型只需要新增一个 build 函数保持同一套入参风格。验证交互看板是否可靠我一般做三步。第一步随机抽 20 条清洗后的记录与原始表人工核对成交价、里程和车龄的换算第二步用 pivot_table 做交叉验证比如按车龄段和变速箱两个维度看成交价中位数确认结果和单维度聚合没有明显冲突第三步和业务常识对拍车龄越大价格越低、里程越高价格越低、事故车折价明显如果趋势反转优先回头查字段单位和清洗阈值而不是怀疑业务判断。折叠看板完成后这份资源就算真正跑通了。从那以后我每次拆新的数据集都强制走一遍字段字典、缺失率热力图、分位数截断三步再做任何聚合和可视化。这套顺序帮我少踩了太多坑也让我确信先洗数据再谈分析先定口径再出图。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

LOL数据集与YOLOv8实战:从格式转换到小目标检测避坑指南

LOL数据集与YOLOv8实战:从格式转换到小目标检测避坑指南

简介:面向LOL英雄联盟角色检测任务,数据集包含3000张对局截图,提供Pascal VOC与YOLO两种标注格式,覆盖己方小兵、敌方小兵、己方防御塔、敌方防御塔、LUX、VAYNE共6类目标,总计24665个标注框,适合训练YOLO系…

2026/10/11 2:25:01 阅读更多 →
API测试的数据管理:从分类、隔离到清理的系统化实践

API测试的数据管理:从分类、隔离到清理的系统化实践

对不少做API测试的人来说,工作里最磨人的其实不是怎么写脚本,而是“用什么数据去跑脚本”。我参与过好几个接口自动化测试项目,真正让用例反复失败、需要半夜爬起来重跑、甚至让测试结果被质疑的,十有八九都跟测试数据有关。明明接…

2026/10/11 2:25:01 阅读更多 →
Python深度学习CNN水果识别系统实战:从数据集到部署全流程

Python深度学习CNN水果识别系统实战:从数据集到部署全流程

简介:这份资源是面向计算机相关专业学生与项目实战学习者的深度学习实战项目,以Python结合CNN卷积神经网络实现水果图像识别,可直接用于毕业设计、期末大作业或课程实践,难度适中,适合具备一定Python与机器学习基础、希…

2026/10/11 2:25:01 阅读更多 →

最新新闻

宽温磁环电感-40℃到150℃温冲后EMC失效的机理与验证流程

宽温磁环电感-40℃到150℃温冲后EMC失效的机理与验证流程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 3:08:24 阅读更多 →
BGP选路实战:四大属性调优实验与验证方法

BGP选路实战:四大属性调优实验与验证方法

相信点开这篇文章的朋友,八成都是被BGP那十几条选路规则折磨过的。我在刚接触BGP的时候也是一样,拿着文档死记硬背“优先选Weight、然后Local Preference、然后AS路径短……”可一到实际设备上,show完路由表就懵了——明明配置了MED&#xff…

2026/10/11 3:08:24 阅读更多 →
车内视角行人识别数据集与YOLOv8训练实战指南

车内视角行人识别数据集与YOLOv8训练实战指南

简介:车内视角行人识别数据集是一份面向目标检测与深度学习从业者的专用数据资源,基于BDD100K筛选并保留行人类别,图片数量共6470张,适合用于YOLO系列、Faster RCNN、SSD等模型的训练与评估。压缩包体积约421.52MB,包含…

2026/10/11 3:08:24 阅读更多 →
基于CNN的Landsat遥感影像地物分类实战与避坑指南

基于CNN的Landsat遥感影像地物分类实战与避坑指南

简介:面向遥感地物分类应用场景,该资源提供基于卷积神经网络的Landsat影像地物分类Python源码与项目说明,适合遥感科学与技术、地理信息科学、计算机视觉等专业方向学生用于课程设计、毕业设计或科研入门。压缩包内共10个文件,包含…

2026/10/11 3:08:24 阅读更多 →
iText7高清PNG转PDF:DPI设置、无损编码与Alpha通道保留指南

iText7高清PNG转PDF:DPI设置、无损编码与Alpha通道保留指南

简介:本资源是一份面向Java开发者的iText图片转PDF实战教程,聚焦解决将PNG等图像高质量生成PDF的常见需求,适用于需要文档导出、报告生成或打印适配的后端开发与工具类项目。压缩包共11个文件,含2个核心jar包(含iText.…

2026/10/11 3:08:24 阅读更多 →
Keil C51 9.61安装配置与LED点灯:51单片机入门完整教程

Keil C51 9.61安装配置与LED点灯:51单片机入门完整教程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 3:07:23 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →