用于自动化分析Excel数据文件,生成一份包含数据完整性报告的Word文档保存到当前工作目录下。其主要功能包括:
- 数据形状分析:输出数据集的样本数量和指标数量。
- 缺失值检查:识别数据中存在缺失值的指标,并输出缺失值的数量。报告中还详细说明了如何计算缺失值。
- 统计量分析:对每个指标计算并展示最大值、最小值、平均数、众数等统计量,并进行正态性检验(Shapiro-Wilk检验),判断数据是否符合正态分布。
- 异常值检查:使用Z-score方法和箱线图方法检测异常值,报告中包括异常值的数量、四分位数、四分位距(IQR)及异常值的范围。同时生成并插入箱线图,以帮助可视化异常值分布。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import zscore, mode, shapiro
from docx import Document
from docx.shared import Inches
import os
def analyze_excel_data(file_path):
# 读取Excel文件
df = pd.read_excel(file_path)
file_title, _ = os.path.splitext(os.path.basename(file_path))
file_name = f'{file_title} 数据完整性报告'
# 初始化Word文档
doc = Document()
doc.add_heading(file_name, 0)
# 数据的形状
num_samples, num_features = df.shape
shape_text = f'数据形状:{num_samples} 个样本,{num_features} 个指标。'
print(shape_text)
doc.add_paragraph(shape_text)
# 缺失值检查
missing_info = df.isnull().sum()
num_missing = (missing_info > 0).sum()
doc.add_heading('缺失值检查', level=1)
doc.add_paragraph(f'共有 {num_missing} 个指标存在缺失值。\n')
missing_text = '缺失值检查:\n'
for column, missing_count in missing_info.items():
if missing_count > 0:
missing_text += f'指标 {column}: {missing_count} 个缺失值。\n'
print(missing_text)
doc.add_paragraph(missing_text)
# 计算和添加统计量表格
doc.add_heading('指标统计量分析', level=1)
# Shapiro-Wilk检验说明
doc.add_paragraph(
'Shapiro-Wilk检验是一种用于检验数据是否符合正态分布的统计方法。'
'该检验的步骤和公式如下:\n'
'1. 计算样本的均值和标准差。\n'
'2. 计算样本的W统计量,该统计量依赖于样本数据的均值、标准差及样本的排列情况。\n'
'3. 根据W统计量和样本量查找Shapiro-Wilk检验表中对应的p值。\n'
'4. 如果p值小于显著性水平(通常为0.05),则拒绝原假设,即数据不符合正态分布;'
'如果p值大于显著性水平,则接受原假设,即数据符合正态分布。\n'
'公式如下:\n'
' W = (∑(a_i * X_i))² / (∑(X_i - X̄)²)\n'
'其中,a_i是Shapiro-Wilk检验中的权重系数,X_i是样本数据,X̄是样本均值。\n'
)
# 创建统计量表格
table = doc.add_table(rows=1, cols=6)
hdr_cells = table.rows[0].cells
hdr_cells[0].text = '指标'
hdr_cells[1].text = '最大值'
hdr_cells[2].text = '最小值'
hdr_cells[3].text = '平均数'
hdr_cells[4].text = '众数'
hdr_cells[5].text = '符合正态分布'
for column in df.columns:
if pd.api.types.is_numeric_dtype(df[column]):
max_value = df[column].max()
min_value = df[column].min()
mean_value = df[column].mean()
mode_value = mode(df[column].dropna())[0][0] # 众数
# 正态分布检验
stat, p_value = shapiro(df[column].dropna())
normal_distribution = '是' if p_value > 0.05 else '否'
row_cells = table.add_row().cells
row_cells[0].text = column
row_cells[1].text = f'{max_value:.2f}'
row_cells[2].text = f'{min_value:.2f}'
row_cells[3].text = f'{mean_value:.2f}'
row_cells[4].text = f'{mode_value:.2f}'
row_cells[5].text = normal_distribution
# 异常值检查
outlier_info = {}
for column in df.columns:
if pd.api.types.is_numeric_dtype(df[column]):
# 计算z-score
z_scores = zscore(df[column].dropna())
outliers = np.abs(z_scores) > 3 # 通常z-score超过3被视为异常值
num_outliers = np.sum(outliers)
if num_outliers > 0:
outlier_info[column] = num_outliers
num_outlier_columns = len(outlier_info)
doc.add_heading('异常值检查', level=1)
doc.add_paragraph(f'共有 {num_outlier_columns} 个指标存在异常值。\n')
doc.add_paragraph(
'异常值检查方法:\n'
'我们使用了 Z-score 方法来识别异常值。Z-score 计算公式为:\n'
' Z = (X - μ) / σ\n'
'其中,X 为观测值,μ 为均值,σ 为标准差。Z-score 超过 3 被视为异常值。\n'
'我们还使用了箱线图方法,通过计算四分位数(Q1、Q3)和四分位距(IQR),\n'
'来确定异常值范围。计算公式为:\n'
' 四分位距 (IQR) = Q3 - Q1\n'
' 异常值下限 = Q1 - 1.5 * IQR\n'
' 异常值上限 = Q3 + 1.5 * IQR\n'
'超出此范围的值被视为异常值。\n'
)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号'-'显示为方块的问题
for column in df.columns:
if pd.api.types.is_numeric_dtype(df[column]):
if column in outlier_info:
# 计算z-score
z_scores = zscore(df[column].dropna())
outliers = np.abs(z_scores) > 3 # 通常z-score超过3被视为异常值
num_outliers = np.sum(outliers)
# 计算箱线图所需的统计量
q1 = df[column].quantile(0.25)
q3 = df[column].quantile(0.75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
# 添加指标的异常值分析
doc.add_heading(f'指标 {column}', level=2)
doc.add_paragraph(
f' - 异常值个数: {num_outliers} 个\n'
f' - 第一四分位数 (Q1): {q1:.2f}\n'
f' - 第三四分位数 (Q3): {q3:.2f}\n'
f' - 四分位距 (IQR): {iqr:.2f}\n'
f' - 异常值范围: ({lower_bound:.2f}, {upper_bound:.2f})\n'
)
# 生成箱线图
plt.figure(figsize=(8, 6))
sns.boxplot(data=df, y=column)
plt.title(f'{column} 的箱线图')
plt.savefig(f'{column}_boxplot.png')
plt.close()
doc.add_paragraph(f'指标 {column} 的箱线图:')
doc.add_picture(f'{column}_boxplot.png', width=Inches(4))
# 删除生成的图片文件,避免占用磁盘空间
os.remove(f'{column}_boxplot.png')
# 保存Word文档
output_path = os.path.join(os.getcwd(), file_name + '.docx')
doc.save(output_path)
print(f'分析结果已保存至 {output_path}')
# 使用示例:analyze_excel_data('your_excel_file.xlsx')
analyze_excel_data('附件1.xlsx')