cpp
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
file_path = "C:\\Users\\86138\\Desktop\\book_list-计算机-机器学习-linux-android-数据库-互联网.xlsx"
data = pd.read_excel(file_path)
need_data = data[['书名', '评分', '评价人数']].copy()
#为 data_cleaned 数据框添加一个新列 书名字数,使用.str.len() 算字符串长度
need_data['书名字数'] = need_data['书名'].str.len()
#删除 data_cleaned 数据框中包含缺失值的行,使用 .dropna() 方法
need_data = need_data.dropna()
# 将评分列转换为数值类型,处理错误值
need_data['评分'] = pd.to_numeric(need_data['评分'], errors='coerce')
# 将评价人数列转换为数值类型,处理错误值
need_data['评价人数'] = pd.to_numeric(need_data['评价人数'], errors='coerce')
# 再次删除包含缺失值或无效值的行
need_data = need_data.dropna()
# sns.set() 函数设置绘图风格为 whitegrid(白色网格),调色板为 pastel(柔和色调),字体缩放比例为 1.2。
# 使用 plt.figure(figsize=(9, 7)) 创建一个大小为 (9, 7) 的图形,用于容纳后续的子图。
sns.set(style="whitegrid", palette="pastel", font_scale=1.2)
plt.figure(figsize=(9, 7))
# 创建第一个子图:
# plt.subplot(3, 1, 1) 创建一个 3 行 1 列的子图,并将子图设为第一个。
# 使用 sns.histplot() 绘制 评价人数 的直方图,bins=20 将数据划分为 20 个直方图区间,kde=True 添加核密度估计曲线
# 使用 plt.title() 为子图设标题,plt.xlabel() 和 plt.ylabel() 设置 x 轴和 y 轴的标签。
# 发现:评论计数的分布:大多数书籍的评论数量相对较少,但少数书籍的评论数量非常高
plt.subplot(3, 1, 1)
sns.histplot(need_data['评价人数'], bins=20, kde=True, color='skyblue')
plt.title('Rating with book counts')
plt.xlabel('Rating')
plt.ylabel('Book')
# 创建第二个子图
# 书名长度的分布:书名通常在5到15个字符之间,还有一些较长的字符
plt.subplot(3, 1, 2)
sns.histplot(need_data['书名字数'], bins=15, kde=True, color='lightgreen')
plt.title('Distribution of Book Title Lengths')
plt.xlabel('Number of Characters in Title')
plt.ylabel('Frequency')
# 第三个子图
# 评级分布:评级通常聚集在较高的范围内,介于8到10之间。
plt.subplot(3, 1, 3)
sns.histplot(need_data['评分'], bins=10, kde=True, color='salmon')
plt.title('Distribution of Ratings')
plt.xlabel('Ratings')
plt.ylabel('Frequency')
# 调整子图布局,使它们紧凑排列,避免重叠。
# 使用 plt.show() 显示绘制的图形
plt.tight_layout()
plt.show()
# 打印出 data 数据框的前几行,以便查看数据集的结构,使用 .head() 方法。
print("数据的前几行:")
print(data.head())
# 创建一个新的图形,大小为 15x10,用于绘制饼图和折线图
plt.figure(figsize=(15, 10))
# 将 评分 列的数据分成不同的分组(bins),范围是 0-6、6-7、7-8、8-9、9-10,使用 pd.cut() 函数,并为每个分组分配标签。
# 使用 value_counts(sort=False) 统计每个分组的数量。
rating_bins = pd.cut(need_data['评分'], bins=[0, 7,8, 9, 10], labels=['0 - 7','7 - 8', '8 - 9', '9 - 10'])
rating_counts = rating_bins.value_counts(sort=False)
# 创建一个 2 行 1 列的子图布局,并将当前子图设置为第一个。
# 使用 rating_counts.plot.pie() 绘制饼图,autopct='%1.1f%%' 表示在饼图上显示百分比,colors=sns.color_palette('pastel') 使用柔和色调,startangle=140 表示起始角度。
# 设置饼图的标题,并将 y 轴标签设为空,以提高美观度
plt.subplot(2, 1, 1)
rating_counts.plot.pie(autopct='%1.1f%%', colors=sns.color_palette('pastel'), startangle=140)
plt.title('Rating Counts')
plt.ylabel('')
plt.subplot(2, 1, 2)
sorted_data = need_data.sort_values(by='评分')
plt.plot(sorted_data['评分'], sorted_data['评价人数'], marker='o', color='teal', label='Review Counts')
plt.title('Single book review counts')
plt.xlabel('Book counts')
plt.ylabel('Reviewer counts')
plt.grid(alpha=0.3)
plt.legend()
# Adjust layout and show plots
plt.tight_layout()
plt.show()
#按 评分 列对 data_cleaned 数据框进行分组,使用 groupby('评分'),并计算每个组中 评价人数 的总和,结果存储在 total_reviews_by_rating 中。
total_reviews_by_rating = need_data.groupby('评分')['评价人数'].sum()
# Plot the total review counts across ratings
plt.figure(figsize=(10, 6))
plt.plot(total_reviews_by_rating.index, total_reviews_by_rating.values, marker='o', color='teal', label='Total Reviews')
plt.title('Sum count of reviewers', fontsize=16)
plt.xlabel('Book rating', fontsize=12)
plt.ylabel('Reviewer counts', fontsize=12)
plt.grid(alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
整理后的代码
cpp
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
def load_and_preprocess_data(file_path):
"""
加载并预处理数据
:param file_path: Excel文件的路径
:return: 预处理后的数据
"""
data = pd.read_excel(file_path)
# 提取所需数据列
need_data = data[['书名', '评分', '评价人数']].copy()
# 计算书名字数
need_data['书名字数'] = need_data['书名'].str.len()
# 去除缺失值和处理数据类型
need_data = need_data.dropna(subset=['书名', '评分', '评价人数'])
need_data['评分'] = pd.to_numeric(need_data['评分'], errors='coerce')
need_data['评价人数'] = pd.to_numeric(need_data['评价人数'], errors='coerce')
need_data = need_data.dropna(subset=['评分', '评价人数'])
return need_data
def plot_histograms(need_data):
"""
绘制直方图和核密度估计图
:param need_data: 预处理后的数据
"""
sns.set(style="whitegrid", palette="pastel", font_scale=1.2)
fig, axs = plt.subplots(3, 1, figsize=(9, 7))
# 评价人数的分布
sns.histplot(need_data['评价人数'], bins=20, kde=True, color='skyblue', ax=axs[0])
axs[0].set_title('Distribution of Review Counts')
axs[0].set_xlabel('Review Counts')
axs[0].set_ylabel('Frequency')
# 书名字数的分布
sns.histplot(need_data['书名字数'], bins=15, kde=True, color='lightgreen', ax=axs[1])
axs[1].set_title('Distribution of Book Title Lengths')
axs[1].set_xlabel('Number of Characters in Title')
axs[1].set_ylabel('Frequency')
# 评分的分布
sns.histplot(need_data['评分'], bins=10, kde=True, color='salmon', ax=axs[2])
axs[2].set_title('Distribution of Ratings')
axs[2].set_xlabel('Ratings')
axs[2].set_ylabel('Frequency')
plt.tight_layout()
plt.show()
def plot_pie_and_line_charts(need_data):
"""
绘制饼图和折线图
:param need_data: 预处理后的数据
"""
plt.figure(figsize=(15, 20))
# 分组统计评分分布
rating_bins = pd.cut(need_data['评分'], bins=[0, 7, 8, 9, 10], labels=['0 - 7', '7 - 8', '8 - 9', '9 - 10'])
rating_counts = rating_bins.value_counts(sort=False)
# 饼图
ax1 = plt.subplot(2, 1, 1)
rating_counts.plot.pie(autopct='%1.1f%%', colors=sns.color_palette('pastel'), startangle=140)
ax1.set_title('Rating Counts')
ax1.set_ylabel('')
# 折线图
ax2 = plt.subplot(2, 1, 2)
sorted_data = need_data.sort_values(by='评分')
ax2.plot(sorted_data['评分'], sorted_data['评价人数'], marker='o', color='teal', label='Review Counts')
ax2.set_title('Single book review counts')
ax2.set_xlabel('Book counts')
ax2.set_ylabel('Reviewer counts')
ax2.grid(alpha=0.3)
ax2.legend()
plt.tight_layout()
plt.show()
def plot_total_review_counts(need_data):
"""
绘制总评论人数与评分的关系图
:param need_data: 预处理后的数据
"""
total_reviews_by_rating = need_data.groupby('评分')['评价人数'].sum()
plt.figure(figsize=(10, 6))
plt.plot(total_reviews_by_rating.index, total_reviews_by_rating.values, marker='o', color='teal', label='Total Reviews')
plt.title('Sum count of reviewers', fontsize=16)
plt.xlabel('Book rating', fontsize=12)
plt.ylabel('Reviewer counts', fontsize=12)
plt.grid(alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
if __name__ == "__main__":
file_path = "C:\\Users\\86138\\Desktop\\book_list-计算机-机器学习-linux-android-数据库-互联网.xlsx"
need_data = load_and_preprocess_data(file_path)
print("数据的前几行:")
print(need_data.head())
plot_histograms(need_data)
plot_pie_and_line_charts(need_data)
plot_total_review_counts(need_data)
- 第一个子图( plt.subplot(3, 1, 1) ):
- 图像类型:直方图和核密度估计图( sns.histplot )。
- 分析关系:
- 该图展示了 评价人数 的分布情况。
- 横轴表示 评价人数,纵轴表示 频率。
- 通过将 评价人数 数据划分为 20 个 bins 并绘制直方图,再加上核密度估计曲线,可以观察到书籍的评价人数的分布趋势。
- 发现:可以看到大多数书籍的评价人数相对较少,但有少数书籍的评价人数非常高,呈现长尾分布,这意味着少数热门书籍吸引了大量的评价,而大部分书籍的评价相对较少。
- 第二个子图( plt.subplot(3, 1, 2) ):
- 图像类型:直方图和核密度估计图( sns.histplot )。
- 分析关系:
- 该图展示了 书名字数 的分布情况。
- 横轴表示 书名字数,即书名的字符长度,纵轴表示 频率。
- 划分了 15 个 bins 并绘制直方图和核密度估计曲线。
- 从图中可以观察到书名长度的分布规律,通常在 5 到 15 个字符之间,但也存在一些较长书名的书籍,能让用户了解书籍命名时书名长度的大致范围和分布情况。
- 第三个子图( plt.subplot(3, 1, 3) ):
- 图像类型:直方图和核密度估计图( sns.histplot )。
- 分析关系:
- 该图展示了 评分 的分布情况。
- 横轴表示 评分,纵轴表示 频率。
- 划分了 10 个 bins 并绘制直方图和核密度估计曲线。
- 可以看出书籍的 评分 通常聚集在较高的范围内,一般介于 8 到 10 之间,能让用户了解书籍评分的整体分布趋势,了解用户对书籍的总体评价倾向。
第二个 plt.figure 中的两个子图:
- 第一个子图( plt.subplot(2, 1, 1) ):
- 图像类型:饼图( rating_counts.plot.pie )。
- 分析关系:
- 首先使用 pd.cut 将 评分 分成不同的范围: 0-6 、 6-7 、 7-8 、 8-9 、 9-10 ,并为这些范围分配了相应的标签。
- 该饼图展示了不同评分范围的书籍在整个数据集中所占的比例。
- 可以直观地看出不同评分范围的书籍的相对占比,使用 autopct='%1.1f%%' 显示每个扇形部分的百分比,帮助用户快速了解评分的分布结构。
- 第二个子图
- 图像类型:折线图( plt.plot )。
- 分析关系:
- 首先对 data_cleaned 按 评分 进行排序( data_cleaned.sort_values(by=' 评分 ') )。
- 该图展示了 评价人数 与 评分 的关系。
- 横轴是 评分,纵轴是 评价人数,使用 marker='o' 标记每个数据点。
- 可以看出不同评分的书籍对应的评价人数的趋势,可能反映出评分高低与评价人数多少之间的关系,例如评分高的书籍是否更受关注,评价人数更多。
第三个 plt.figure
- 图像类型:折线图( plt.plot )。
- 分析关系:
- 首先对 data_cleaned 按 评分 分组并计算每个组中 评价人数 的总和( data_cleaned.groupby(' 评分 ')[' 评价人数 '].sum() )。
- 该图展示了不同评分下的总评价人数的关系。
- 横轴是 Book rating ,纵轴是 Reviewer counts 。
- 可以看出不同评分的书籍的总评价人数,例如可以发现哪个评分范围的书籍吸引了最多的总评价,帮助用户分析不同评分对评价人数总和的影响,以及不同评分书籍的受欢迎程度(从评价人数总和的角度)。