引言:为什么调查问卷数据分析如此重要?

调查问卷是收集用户反馈、市场洞察和学术研究数据的最常用工具之一。然而,收集到的原始数据往往杂乱无章,包含错误、缺失值和不一致的格式。数据处理是将这些原始数据转化为可分析、可解释信息的关键步骤。如果处理不当,即使是最精心设计的问卷也无法产生有价值的结论。

对于新手来说,数据分析可能看起来令人生畏,但通过掌握核心技巧并避免常见错误,你可以快速上手并产生可靠的结果。本指南将带你了解从数据清理到分析的完整流程,使用Python和Pandas作为主要工具,因为它们是数据科学领域最流行且功能强大的库。

第一部分:数据准备与导入

1.1 理解你的数据结构

在开始任何分析之前,首先需要理解你的数据。通常,问卷数据以CSV或Excel格式存储,每一行代表一个受访者,每一列代表一个问题或变量。

核心技巧:始终先查看数据的前几行和基本信息,这能帮助你快速发现明显的问题。

import pandas as pd

# 加载数据
df = pd.read_csv('survey_data.csv')

# 查看前5行
print("数据前5行:")
print(df.head())

# 查看数据基本信息
print("\n数据基本信息:")
print(df.info())

# 查看数值列的统计摘要
print("\n数值列统计摘要:")
print(df.describe())

解释

  • df.head() 显示数据的前5行,让你快速了解列名和数据格式。
  • df.info() 显示每列的数据类型和非空值数量,帮助你发现缺失值。
  • df.describe() 提供数值列的统计摘要(计数、均值、标准差等),帮助你发现异常值。

1.2 常见错误:忽略数据编码问题

错误描述:当数据包含非英文字符(如中文、特殊符号)时,如果编码不正确,会导致乱码。

解决方法:在读取数据时指定正确的编码格式(通常是UTF-8或GBK)。

# 指定编码读取数据
df = pd.read_csv('survey_data.csv', encoding='utf-8')
# 如果UTF-8失败,尝试GBK(常见于中文Windows系统生成的CSV)
# df = pd.read_csv('survey_data.csv', encoding='gbk')

第二部分:数据清理的核心技巧

数据清理是数据分析中最耗时但也是最重要的步骤。高质量的数据是准确分析的前提。

2.1 处理缺失值

缺失值是问卷数据中最常见的问题。处理缺失值的方法取决于数据的性质和分析目标。

核心技巧:首先识别缺失值的模式,再决定如何处理。

# 检查每列的缺失值数量
missing_values = df.isnull().sum()
print("每列缺失值数量:")
print(missing_values[missing_values > 0])

# 可视化缺失值分布(可选,需要matplotlib)
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
df.isnull().mean().plot(kind='bar')
plt.title('每列缺失值比例')
plt.ylabel('缺失比例')
plt.show()

处理缺失值的策略

  1. 删除:如果缺失值比例很小(如%),且是随机缺失,可以删除这些行。
  2. 填充:对于数值列,可以用均值、中位数填充;对于分类列,可以用众数或“未知”填充。
  3. 插值:对于时间序列数据,可以使用前后值插值。
# 策略1:删除缺失值所在的行
df_cleaned = df.dropna()

# 策略2:用均值填充数值列的缺失值
df['age'] = df['age'].fillna(df['age'].mean())

# 策略3:用众数填充分类列的缺失值
df['gender'] = df['gender'].fillna(df['gender'].mode()[0])

# 策略4:用“未知”填充分类列的缺失值
df['feedback'] = df['feedback'].fillna('未知')

2.2 处理异常值

异常值(Outliers)是那些明显偏离其他数据点的值,可能是录入错误或真实但极端的值。

核心技巧:使用统计方法(如IQR法)或可视化方法(如箱线图)来识别异常值。

# 使用IQR法识别数值列的异常值
def detect_outliers_iqr(series):
    Q1 = series.quantile(0.25)
    Q3 = series.quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    return (series < lower_bound) | (series > upper_bound)

# 检查年龄列的异常值
age_outliers = detect_outliers_iqr(df['age'])
print("年龄异常值数量:", age_outliers.sum())
print("异常值样本:")
print(df[age_outliers][['age', 'gender', 'feedback']])

处理异常值

  • 修正:如果异常值是录入错误(如年龄为200岁),修正为合理值或设为缺失值。
  • 保留:如果异常值是真实的(如收入极高),可以保留但进行分组分析。
  • 删除:如果异常值是错误且无法修正,可以删除。
# 将年龄超过100岁的设为缺失值
df.loc[df['age'] > 100, 'age'] = np.nan
# 然后可以选择填充或删除

2.3 数据格式标准化

问卷数据经常包含不一致的格式,如大小写不一致、多余空格、不同表达方式等。

核心技巧:统一文本格式,确保分类变量的一致性。

# 去除前后空格
df['gender'] = df['gender'].str.strip()

# 统一大小写
df['gender'] = df['gender'].str.lower()

# 映射不同表达方式到统一值
gender_mapping = {'男': 'male', '男性': 'male', '女': 'female', '女性': 'female'}
df['gender'] = df['gender'].map(gender_mapping).fillna(df['gender'])

# 检查唯一值
print("标准化后的性别分布:")
print(df['gender'].value_counts())

2.4 处理重复数据

重复的问卷响应可能是由于系统错误或受访者重复提交。

核心技巧:根据关键列(如ID、时间戳)识别重复项。

# 根据ID和时间戳检查重复
duplicates = df.duplicated(subset=['respondent_id', 'timestamp'], keep=False)
print("重复记录数量:", duplicates.sum())

# 删除完全重复的行
df = df.drop_duplicates()

# 保留第一条记录,删除后续重复
df = df.drop_duplicates(subset=['respondent_id'], keep='first')

第三部分:数据转换与增强

3.1 数据类型转换

确保每列的数据类型正确是准确分析的基础。

核心技巧:将文本转换为数值,日期转换为日期对象,分类变量转换为category类型。

# 转换日期列
df['timestamp'] = pd.to_datetime(df['timestamp'], errors='coerce')

# 转换分类变量以节省内存
df['gender'] = df['gender'].astype('category')
df['education'] = df['education'].astype('category')

# 将文本评分转换为数值(如“非常同意”=5,“非常不同意”=1)
rating_mapping = {'非常同意': 5, '同意': 4, '一般': 3, '不同意': 2, '非常不同意': 1}
df['satisfaction_score'] = df['satisfaction_text'].map(rating_mapping)

3.2 创建新特征

从现有数据中提取新信息可以增强分析深度。

核心技巧:基于现有列创建衍生变量。

# 根据年龄创建年龄段
def age_group(age):
    if pd.isna(age):
        return '未知'
    elif age < 18:
        return '未成年'
    elif age < 35:
        return '青年'
    elif age < 55:
        = '中年'
    else:
        return '老年'

df['age_group'] = df['age'].apply(age_group)

# 计算满意度平均分(如果有多个满意度问题)
satisfaction_cols = ['satisfaction_q1', 'satisfaction_q2', 'satisfaction_q3']
df['satisfaction_avg'] = df[satisfaction_cols].mean(axis=1)

3.3 数据重塑与合并

有时需要将多个问卷数据集合并,或重塑数据格式以适应分析需求。

核心技巧:使用Pandas的merge和pivot_table功能。

# 合并两个数据集(如基本信息和问卷回答)
# df_demographics = pd.read_csv('demographics.csv')
# df_responses = pd.read_csv('responses.csv')
# merged_df = pd.merge(df_demographics, df_responses, on='respondent_id', how='inner')

# 重塑数据:从宽格式到长格式(适合多个类似问题)
# 例如,将q1, q2, q3转换为question和answer两列
# df_long = pd.melt(df, id_vars=['respondent_id'], value_vars=['q1', 'q2', 'q3'],
#                   var_name='question', value_name='answer')

第四部分:数据分析与可视化

4.1 描述性统计分析

描述性统计帮助你了解数据的分布和基本特征。

核心技巧:按组计算统计量,使用groupby。

# 按性别计算年龄均值
print("按性别分组的年龄均值:")
print(df.groupby('gender')['age'].mean())

# 按教育水平和性别计算满意度均值
print("\n按教育水平和性别分组的满意度均值:")
print(df.groupby(['education', 'gender'])['satisfaction_score'].mean().unstack())

4.2 可视化:让数据说话

可视化是快速发现模式和传达结果的最有效方式。

核心技巧:使用Matplotlib和Seaborn创建清晰的图表。

”`python import seaborn as sns

设置中文字体(如果需要显示中文)

plt.rcParams[‘font.sans-serif’] = [‘SimHei’] plt.rcParams[‘axes.unicode_minus’] = False

1. 分类变量的分布(柱状图)

plt.figure(figsize=(8, 5)) sns.countplot(data=df, x=‘gender’) plt.title(‘性别分布’) plt.show()

2. 数值变量的分布(直方图)

plt.figure(figsize=(8, 5)) sns.histplot(data=df, x=‘age’, kde=True) plt.title(‘年龄分布’) plt.show()

3. 分组比较(箱线图)

plt.figure(figsize=(8, 5)) sns.boxplot(data=df, x=‘gender’, y=‘satisfaction_score’) plt.title(‘不同性别的满意度分布’) plt.show()

4. 相关性热力图(适合多个数值变量)

numeric_cols = [‘age’, ‘satisfaction_score’, ‘satisfaction_avg’] corr_matrix = df[numeric_cols].corr() plt.figure(figsize=(6, 4)) sns.heatmap(corr_matrix, annot=True, cmap=‘coolwarm’, center=0) plt.title(‘数值变量相关性热力图’) plt