# %%--- [python] cell-f74e05782eef # properties: # run_on_load: true # top_hidden: true # ---%% print("开始初始化数据分析和可视化的运行环境,请稍候……") import micropip await micropip.install("/pypi/openpyxl-3.1.5-py2.py3-none-any.whl") await micropip.install("/pypi/pyfonts-0.0.2-py3-none-any.whl") import pandas as pd import pyodide from pyfonts import load_font # 文件的URL file_url = '/assets/fonts/NotoSansSC-Regular.ttf' # 请将此URL替换为实际文件的URL # 本地保存路径 local_file_path = '/NotoSansSC-Regular.ttf' # 下载文件并保存到本地 try: response = await pyodide.http.pyfetch(file_url) # Return the response body as a bytes object image_data = await response.bytes() with open(local_file_path, 'wb') as f: f.write(image_data) print(f"中文字体已成功下载并保存为: {local_file_path}") except Exception as e: print(f"下载文件时出错: {e}") font = load_font(font_path="/NotoSansSC-Regular.ttf") print("数据分析和可视化的运行环境已经就绪。可以进行第1步了。") # %% [markdown] cell-5e351e7966a3 ## 🕐请从本地上传一个用电商记插件采集的淘宝搜索2025新版结果(含综合排序和销量排序)的Excel文件。[下载示例](https://www.dianshangji.cn/u/user5344/cfiles/browse/index?fid=3) # %%--- [html] cell-a5b79fdf3c10 # properties: # run_on_load: true # top_hidden: true # ---%% <input class="btn btn-primary" type="file" id="fileInput"/> # %%--- [javascript] cell-d28877a258f5 # properties: # run_on_load: true # top_hidden: true # ---%% const fileInput = document.getElementById('fileInput'); fileInput.addEventListener('change', async function(ev){ const file = fileInput.files[0]; if (!file) { alert("Please select a file first."); return; } // 读取文件为 ArrayBuffer const arrayBuffer = await file.arrayBuffer(); // 将 ArrayBuffer 转换为 Uint8Array const uint8Array = new Uint8Array(arrayBuffer); pyodide.FS.writeFile('/file1.xlsx', uint8Array); }); # %% [markdown] cell-d4de1bcd39b2 ## 🕑数据清洗与预处理 在进行数据分析之前,首先需要对采集到的数据进行清洗和预处理。数据清洗的过程包括去除缺失值、异常值处理、格式标准化等步骤。由于淘宝平台的数据可能存在一定的噪声(如商品标题的重复、价格的极端值等),我们需要对数据进行过滤,确保后续分析的准确性。由于在电商平台上,部分商品的销量和付款人数较少,可能无法代表整体市场趋势,因此我们在数据清洗阶段对数据进行了筛选,去除了销量数值超过**10000**的商品。 # %% [python] cell-50bbd749f8a1 import re print("开始读取内存中的Excel文件……") # 读取Excel文件,跳过前两行(即从第三行开始读取),只保留“商品ID”、“价格”和“月销量”两个字段 excel_file_path = '/file1.xlsx' # 分别读取名为“综合”和“销量”的工作表 df_zonghe = pd.read_excel(excel_file_path, skiprows=2, usecols=['商品ID','价格', '月销量'], sheet_name='综合') df_xiaoliang = pd.read_excel(excel_file_path, skiprows=2, usecols=['商品ID','价格', '月销量'], sheet_name='销量') # 打印前几行数据以确认读取正确 print("综合表前几行:") print(df_zonghe.head()) print("销量表前几行:") print(df_xiaoliang.head()) def processdata(df): # 代码片段1 # 定义一个函数来处理“月销量”字段 def clean_month_sales(sales_str): if pd.isna(sales_str): return None sales_str = str(sales_str).strip() if "本月行业热销" in sales_str: return 1000 elif "万+" in sales_str: match = re.search(r'(\d+)', sales_str) if match: return int(match.group(1)) * 10000 elif "+人" in sales_str: match = re.search(r'(\d+)', sales_str) if match: return int(match.group(1)) try: return int(sales_str) except ValueError: return None # 应用函数到“月销量”列 df['月销量'] = df['月销量'].apply(clean_month_sales) # 代码片段2 # 筛选出“价格”小于等于1000元的记录 df = df[df['价格'] <= 1000] print("筛选出“价格”小于等于1000元的记录") # 筛选出“月销量”大于等于0,小于等于100000的记录 df = df[df['月销量'] >= 0] df = df[df['月销量'] <= 10000] print("筛选出“月销量”小于等于10000的记录") # 代码片段3 # 假设 df 是已经加载的数据 # 检查商品ID是否有重复记录 if df['商品ID'].duplicated().any(): print("存在重复的商品ID记录,正在去除重复条目...") # 去除重复的商品ID条目,只保留第一次出现的记录 df = df.drop_duplicates(subset=['商品ID'], keep='first') else: print("没有重复的商品ID记录。") # 打印前5条记录以检查结果 print(df.head(5)) print("有效记录总数:", len(df)) return df df_zonghe = processdata(df_zonghe) df_xiaoliang = processdata(df_xiaoliang) # %% [markdown] cell-3e50bf8d15a1 ### 读取表格数据 这两行代码是使用Pandas库来读取Excel文件,并从文件中提取特定的列和数据。下面是详细的解释: #### 1. `df_zonghe = pd.read_excel(excel_file_path, skiprows=2, usecols=['商品ID','价格', '月销量'], sheet_name='综合')` - **`pd.read_excel()`**:这是Pandas的一个函数,用来读取Excel文件中的数据。`excel_file_path`是Excel文件的路径。 - **`skiprows=2`**:这个参数指定在读取数据时跳过前两行。这通常用于跳过Excel文件中的表头信息,或者有时数据从第三行开始的情况。 - **`usecols=['商品ID','价格', '月销量']`**:这个参数指定了要读取的列名。只有这三列的数据会被读取,其他列会被忽略。这里我们读取的是: - **商品ID**:商品的唯一标识符。 - **价格**:商品的价格。 - **月销量**:商品在一个月内的销量。 - **`sheet_name='综合'`**:这个参数指定了要读取的Excel表单的名称。在这个例子中,读取的是名为“综合”的表单。 - **返回的结果**:这一行代码会读取Excel文件中的“综合”工作表,并将包含**商品ID**、**价格**、**月销量**这三列数据的内容存储在`df_zonghe`这个DataFrame中。 #### 2. `df_xiaoliang = pd.read_excel(excel_file_path, skiprows=2, usecols=['商品ID','价格', '月销量'], sheet_name='销量')` 这一行代码的解释与上面的代码类似,只是读取的是名为“销量”的表单。 - **`sheet_name='销量'`**:这次指定了要读取的工作表名称是“销量”,所以数据将来自Excel文件中名为“销量”的表单。 - **返回的结果**:这一行代码会读取“销量”工作表的数据,同样是**商品ID**、**价格**、**月销量**这三列数据,并将其存储在`df_xiaoliang`这个DataFrame中。 #### 总结 这两行代码的作用是: - 第一行从Excel文件中读取“综合”表单中的**商品ID**、**价格**、**月销量**三列数据,并将其存储在`df_zonghe`中。 - 第二行从Excel文件中读取“销量”表单中的**商品ID**、**价格**、**月销量**三列数据,并将其存储在`df_xiaoliang`中。 `skiprows=2`确保跳过前两行,`usecols`只选择了我们关心的三列数据,这样可以更有效地处理和分析数据。 ### 代码片段1 这段代码定义了一个函数 `clean_month_sales`,用于处理 `pandas` DataFrame 中的“月销量”字段。然后,使用 `apply` 方法将这个函数应用到 DataFrame 的 `月销量` 列,以对每个元素进行处理。下面是代码的详细解析: ### 1. **函数** `clean_month_sales` 定义: ``` def clean_month_sales(sales_str): if pd.isna(sales_str): return None ``` * `sales_str` 是函数的输入参数,表示“月销量”字段的单个值。 * `pd.isna(sales_str)` 用于检查该值是否为缺失值(`NaN`)。如果是 `NaN`,函数返回 `None`,表示该值不能被处理。 ### 2. **去除字符串前后空白:** ``` sales_str = str(sales_str).strip() ``` * `str(sales_str)`:将 `sales_str` 转换为字符串类型,以防原始值不是字符串类型(如数字、日期等)。 * `strip()`:去除字符串的前后空白字符,以便后续匹配和处理。 ### 3. **处理包含“本月行业热销”字符串的情况:** ``` if "本月行业热销" in sales_str: return 1000 ``` * 如果 `sales_str` 中包含 “本月行业热销”,函数直接返回 1000,表示销量为 1000。 ### 4. **处理包含“万+”字符串的情况:** ``` elif "万+" in sales_str: match = re.search(r'(\d+)', sales_str) if match: return int(match.group(1)) * 10000 ``` * 如果 `sales_str` 中包含 “万+”,表示销量以“万”为单位。 * 使用 `re.search(r'(\d+)', sales_str)` 通过正则表达式匹配字符串中的数字部分。`(\d+)` 匹配一个或多个数字。 * `match.group(1)` 返回匹配到的数字部分(作为字符串),并将其转换为整数。然后,将这个整数乘以 10000,表示实际销量的值(例如,如果字符串是 “2万+”,则返回 `20000`)。 ### 5. **处理包含“+人”字符串的情况:** ``` elif "+人" in sales_str: match = re.search(r'(\d+)', sales_str) if match: return int(match.group(1)) ``` * 如果 `sales_str` 中包含 “+人”,表示销量为一些人购买了该商品。 * 同样,使用正则表达式 `re.search(r'(\d+)', sales_str)` 来匹配数字部分,并将其转换为整数。 * 返回匹配到的数字,表示实际销量。 ### 6. **尝试将字符串转换为整数:** ``` try: return int(sales_str) except ValueError: return None ``` * 如果以上三种情况都没有匹配到,最后尝试将 `sales_str` 直接转换为整数。 * 如果转换成功,则返回该整数值,表示销量的数值。 * 如果 `sales_str` 无法转换为整数(例如包含非数字字符),则捕获 `ValueError` 异常并返回 `None`,表示该值无法处理。 ### 7. **应用函数到 DataFrame 的“月销量”列:** ``` df['月销量'] = df['月销量'].apply(clean_month_sales) ``` * `df['月销量']` 是 `pandas` DataFrame 中的“月销量”列。 * 使用 `apply(clean_month_sales)` 将 `clean_month_sales` 函数应用到 `月销量` 列中的每个元素。 * 这会逐个处理 `月销量` 列的所有值,基于前面定义的规则来清洗和转换这些值。 ### 总结: 这段代码的作用是根据不同的规则来处理“月销量”字段的数据,规范化这些数据,使它们统一为整数形式。具体处理方式包括: * 对于“本月行业热销”直接设定为 1000; * 对于含有“万+”的,转换为以万为单位的实际数值; * 对于含有“+人收货”的,提取数字并作为销量; * 对于其他情况,直接将字符串转换为整数; * 如果无法转换为整数,则返回 `None`。 最终,这个函数被应用到 `df['月销量']` 列中,清洗并处理了该列的所有数据。 ### 代码片段2 1. `df['价格'] <= 1000` 会生成一个布尔值 Series,表示 `价格` 列中每个元素是否小于等于 1000。 2. `df = df[df['月销量'] >= 0]`会筛选出销量大于等于0的所有元素。 3. 使用 `df[...]` 语法,将这个布尔 Series 作为索引过滤出符合条件的记录。 ### 代码片段3 1. `df['商品ID'].duplicated().any()`:检查 `商品ID` 列是否有重复记录,`duplicated()` 返回一个布尔 Series,表示每一行是否为重复项,`any()` 检查是否有 `True`(即存在重复记录)。 2. `df.drop_duplicates(subset=['商品ID'], keep='first')`:去除 `商品ID` 列中的重复项,`keep='first'` 表示保留第一次出现的记录,删除后续重复的记录。 这样,代码会检查是否有重复的 `商品ID`,如果有,就去除重复记录并保留每个 `商品ID` 的第一条记录。 # %% [markdown] cell-ff91033e7acc ## 🕒价格区间直方图 # %% [python] cell-70f67d1cde93 import matplotlib.pyplot as plt await micropip.install("seaborn") import seaborn as sns def drawbarchart_price(name, df): # 假设 df 已经是一个包含商品ID、价格和月销量字段的 DataFrame # 选择“价格”字段来绘制价格分布图 plt.figure(figsize=(10, 6)) # 使用 seaborn 绘制价格的分布图 sns.histplot(df['价格'], kde=True, bins=30, color='blue') # 添加标题和标签 plt.title(name + '商品价格分布图', fontsize=16, font=font) plt.xlabel('价格', fontsize=12, font=font) plt.ylabel('频次', fontsize=12, font=font) # 显示图形 plt.show() # 绘制综合排序搜索数据的价格区间直方图 drawbarchart_price('综合排序', df_zonghe) # 绘制销量排序搜索数据的价格区间直方图 drawbarchart_price('销量排序', df_xiaoliang) # %%--- [markdown] cell-983a4edf8ee8 # properties: # top_hidden: true # ---%% ### 1. 导入必要的库 ``` import matplotlib.pyplot as plt await micropip.install("seaborn") import seaborn as sns ``` * `matplotlib.pyplot`: 用于绘制基本的图形,如线图、散点图、直方图等。它提供了很多自定义选项来控制图形的外观。 * `seaborn`: 基于`matplotlib`的一个高级可视化库,提供了更漂亮和更方便的绘图功能。`seaborn`与`matplotlib`兼容,并且能够创建复杂的统计图表。下面附录中详细讲解如何在交互式文档中安装seaborn库。 ### 2. 设置图表的大小 ``` plt.figure(figsize=(10, 6)) ``` * `plt.figure(figsize=(10, 6))`:指定图表的尺寸。`figsize`的参数是一个元组,表示图形的宽度和高度(单位是英寸)。例如,`figsize=(10, 6)`意味着图形的宽度是10英寸,高度是6英寸。 ### 3. 绘制价格分布图 ``` sns.histplot(df['价格'], kde=True, bins=30, color='blue') ``` 这个是`seaborn`库中的核心绘图函数之一——`histplot()`。它专门用于绘制直方图,提供了比`matplotlib`更高级的功能和更简洁的语法。 #### 解释每个参数: * `df['价格']`: * 这是我们数据框`df`中的`价格`字段。`seaborn.histplot()`需要一个数值型数据(例如,价格数据)来绘制直方图。 * `kde=True`: * `kde`表示“Kernel Density Estimate”(核密度估计),它是通过平滑曲线显示数据的分布。 * 核密度估计(KDE)是一种通过平滑数据点来估算连续变量分布的技术。它生成的是一个平滑的曲线,用来展示数据的整体分布趋势,而不是像直方图那样显示离散的条形。 * `kde=True`启用核密度估计,默认情况下它绘制的是与直方图重叠的平滑曲线。 * 如果你只想显示直方图,而不想显示KDE平滑曲线,可以设置`kde=False`。 * `bins=30`: * `bins`参数控制直方图中分箱(或区间)的数量。每个箱子对应一个区间,数据根据价格的值被分配到这些区间中。 * `bins=30`表示将价格范围分成30个区间。你可以调整这个参数来使直方图的分辨率更高或更低。 * 通常,`bins`的值会根据数据的大小、分布等进行调整。较小的`bins`可能会导致数据过于粗略,而较大的`bins`可能会过于细致。 * `color='blue'`: * `color`指定直方图的颜色。这里选择的是`blue`(蓝色)。你可以根据需要选择其他颜色,例如 `'red'`, `'green'` 或者使用颜色代码(如`#FF5733`)。 ### 4. 设置图表的标题和标签 ``` plt.title('商品价格分布图', fontsize=16) plt.xlabel('价格', fontsize=12) plt.ylabel('频次', fontsize=12) ``` * `plt.title('商品价格分布图', fontsize=16)`: 设置图表的标题,`fontsize=16`设置字体的大小为16。 * `plt.xlabel('价格', fontsize=12)`: 设置X轴的标签为“价格”,字体大小为12。 * `plt.ylabel('频次', fontsize=12)`: 设置Y轴的标签为“频次”,字体大小为12。 这些标签和标题使得图表更易于理解和呈现,尤其是当你展示给其他人时,它们有助于说明图表的含义。 ### 5. 显示图形 ``` plt.show() ``` * `plt.show()`:这个命令用于显示当前图形。它是`matplotlib`的标准方法,启动后会弹出图形窗口或将图形嵌入到Jupyter Notebook等环境中。 ### 总结: 这段代码的作用是生成一个显示商品价格分布的直方图,同时叠加一个平滑的KDE曲线(用于展示价格的分布趋势),并且设置了图表的标题、轴标签和图形大小。通过调整`bins`、`kde`等参数,你可以控制图表的细节和外观。 ### `seaborn.histplot()`常用参数: * `data`: 输入的数据,可以是一个DataFrame或Series。 * `kde`: 布尔值,是否启用KDE平滑曲线。默认`False`。 * `bins`: 控制直方图箱数目,数据的“分箱”数。也可以传递一个数组来自定义每个箱的边界。 * `color`: 设置条形的颜色。 * `hue`: 用于按类别进行颜色分组的字段(如果数据包含多个类别的话)。 * `stat`: 直方图的统计类型,默认是`'count'`,可以改为`'density'`表示频率密度。 如果你对`seaborn`或`matplotlib`有更多的疑问,欢迎继续提问! # %% [markdown] cell-10c8e96a2446 ## 🕓销量分布直方图 # %% [python] cell-f4ff7a08a942 def drawbarchart_sales(name, df): # 假设 df 已经是一个包含商品ID、价格和月销量字段的 DataFrame # 选择“价格”字段来绘制价格分布图 plt.figure(figsize=(10, 6)) # 使用 seaborn 绘制月销量的分布图 sns.histplot(df['月销量'], kde=True, bins=30, color='blue') # 添加标题和标签 plt.title(name + '商品销量分布图', fontsize=16, font=font) plt.xlabel('月销量', fontsize=12, font=font) plt.ylabel('频次', fontsize=12, font=font) # 显示图形 plt.show() # 绘制综合排序搜索数据的价格区间直方图 drawbarchart_sales('综合排序', df_zonghe) # 绘制销量排序搜索数据的价格区间直方图 drawbarchart_sales('销量排序', df_xiaoliang)