import pymysql
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
# 设置中文字体支持
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 设置图片清晰度
plt.rcParams['figure.dpi'] = 100
def connect_mysql():
# 数据库连接配置
config = {
'host': 'localhost',
'port': 3307,
'user': 'root',
'password': '123456',
'database': 'ksh'
}
connection = None
try:
connection = pymysql.connect(**config)
print('数据库连接成功')
return connection
except pymysql.Error as e:
print(f'数据库连接出错: {e}')
return None
def clean_data(df):
# 1、缺失值处理
isnull_count = df.isnull().sum().sum()
if isnull_count > 0:
df = df.dropna(how='any')
print('已删除缺失值的行')
else:
print("数据中不存在缺失值")
# 2、检查并删除重复行
duplicate_rows = df.duplicated()
duplicate_count = duplicate_rows.sum()
if duplicate_count > 0:
df = df.drop_duplicates()
print('已删除重复行')
else:
print('数据集中不存在重复行')
# 3、数据类型转换
df["total_bill"] = df["total_bill"].astype("float64")
df["tip"] = df["tip"].astype("float64")
df["size"] = df["size"].astype("Int64")
return df
def analyse_data(df):
#数据分析
# 1、按 sex 分组计算 total_bill 的总值
total_total = df.groupby('sex')['total_bill'].sum().reset_index(name='总消费')
# 2、按 sex 分组计算 tip、total_bill 的均值
total_ave = df.groupby('sex')['total_bill'].mean().round(2).reset_index(name='总消费均值')
tip_ave = df.groupby('sex')['tip'].mean().round(2).reset_index(name='小费打赏均值')
# 3、按照 total_bill 的不同区间对数据进行分组,并计算每个区间的总消费
bins = [float('-inf'), 10, 20, 30, float('inf')]
labels = ['< 10', '10 - 20', '20 - 30', '> 30']
df['bill_group'] = pd.cut(df['total_bill'], bins=bins, labels=labels)
group_total = df.groupby('bill_group')['total_bill'].sum().reset_index(name='总消费')
# 4、按 sex 分组计算 smoker 人数总计
is_smoker = df[df['smoker'] == 'Yes'].groupby('sex')['smoker'].count().reset_index(name='吸烟人数')
not_smoker = df[df['smoker'] == 'No'].groupby('sex')['smoker'].count().reset_index(name='不吸烟人数')
# 可视化图形
# 1、不同性别的总消费————饼图
plt.figure(figsize=(6, 4))
colors = ['pink','skyblue']
plt.pie(total_total['总消费'], labels=total_total['sex'], autopct='%1.1f%%', startangle=90, colors=colors)
plt.title('不同性别总消费占比')
plt.show()
# 2、不同性别总消费和小费打赏情况————柱状图
merged_data1 = pd.merge(tip_ave, total_ave, on='sex')
plt.figure(figsize=(6, 4))
bar_width = 0.2
index = range(len(merged_data1['sex']))
plt.bar(index, merged_data1['小费打赏均值'], bar_width, label='小费打赏均值', color='pink')
plt.bar([i + bar_width for i in index], merged_data1['总消费均值'], bar_width, label='总消费均值', color='skyblue')
plt.xticks([i + bar_width / 2 for i in index], merged_data1['sex'])
plt.title('不同性别总消费和小费打赏情况')
plt.xlabel('性别')
plt.ylabel('金额')
plt.legend()
plt.show()
# 3、不同消费区间可视化————条形图
plt.barh(group_total['bill_group'], group_total['总消费'], color='pink')
plt.title('不同消费区间的总消费')
plt.ylabel('消费区间')
plt.xlabel('总消费')
plt.show()
# 4、用餐人数————小提琴图
plt.figure(figsize=(8, 6))
sns.violinplot(y='size', data=df, hue=None, palette='Set2', legend=False)
plt.title('用餐人数分布小提琴图')
plt.show()
# 5、性别与是否吸烟的关系————热力图
merged_data2 = pd.merge(is_smoker, not_smoker, on='sex')
merged_data2 = merged_data2.set_index('sex')
merged_data = merged_data2[['吸烟人数', '不吸烟人数']]
plt.figure(figsize=(8, 6))
sns.heatmap(merged_data2, annot=True, fmt='d', cmap='YlGnBu')
plt.title('性别与是否吸烟的关系')
plt.show()
# 6、小费比例与聚餐人数的关系————点图
plt.figure(figsize=(8, 6))
sns.pointplot(x='size', y='tip', data=df, errorbar=('ci', 95))
plt.title('小费比例与聚餐人数的关系')
plt.xlabel('聚餐人数')
plt.ylabel('平均小费比例(%)')
plt.show()
# 7、总消费 vs 小费————散点图
plt.figure(figsize=(8, 6))
colors = ['#FF8C00', '#00008C']
sns.scatterplot(x='total_bill', y='tip', data=df, hue='smoker', palette=colors, size='size')
plt.title('总消费 vs 小费')
plt.xlabel('总消费金额')
plt.ylabel('小费金额')
plt.show()
# 8、 总消费金额的时间趋势————折线图
grouped_data = df.groupby('day')['total_bill'].sum().reset_index(name='日均消费')
plt.figure(figsize=(8, 6))
plt.plot(grouped_data['day'], grouped_data['日均消费'], marker='o')
plt.title('按星期的总消费折线图')
plt.xlabel('星期')
plt.ylabel('总消费')
plt.show()
# 9、不同性别在一周内每天的总消费————条形图
grouped = df.groupby(['sex', 'day'])['total_bill'].sum().unstack()
ax = grouped.plot(kind='bar')
plt.title('不同性别在一周内每天的总消费')
plt.xlabel('性别')
plt.xticks(rotation=45)
plt.ylabel('总消费')
plt.legend(title='星期')
plt.show()
# 10、不同用餐时段的用餐人数分布————直方图
sns.histplot(data=df, x='size', hue='time', multiple='stack')
plt.title('不同用餐时段的用餐人数分布直方图')
plt.xlabel('用餐人数')
plt.xticks(rotation=10)
plt.ylabel('频次')
plt.show()
if __name__ == "__main__":
connection = connect_mysql()
if connection:
try:
with connection.cursor() as cursor:
sql = "SELECT * FROM tips"
cursor.execute(sql)
results = cursor.fetchall()
df = pd.DataFrame.from_records(results[1:], columns=results[0])
df = clean_data(df)
analyse_data(df)
except pymysql.Error as e:
print(f'数据库查询出错: {e}')
finally:
connection.close()
print('数据库连接已关闭')完善代码,将绘制的图可视化以动态图显示在页面上