Python数据分析实战:用Pandas挖掘MBTI测试数据的隐藏价值
MBTI性格测试作为全球最流行的心理测评工具之一,每年有数百万人参与测试。但大多数人只关注最终的四个字母结果,却忽略了测试过程中产生的丰富数据金矿。本文将带你用Python的Pandas库,从数据科学的角度重新审视这些测试数据,发现性格特征背后的有趣规律。
1. 数据采集与预处理
收集MBTI测试数据是分析的起点。一个完整的测试包含93道选择题,每道题都有A/B两个选项,最终会生成四个维度的分数(E/I、S/N、T/F、J/P)。我们可以设计一个CSV格式来存储这些数据:
import pandas as pd # 示例数据结构 data = { 'user_id': [1, 2, 3], 'E_I_score': [5, -3, 8], 'S_N_score': [-2, 7, 4], 'T_F_score': [6, -1, -5], 'J_P_score': [-4, 2, 3], 'Q1': ['A', 'B', 'A'], 'Q2': ['B', 'A', 'B'], # ...其他题目 } df = pd.DataFrame(data)处理原始数据时常见的几个问题:
- 缺失值处理:测试者可能跳过某些题目
- 异常值检测:检查是否存在非A/B的无效输入
- 数据标准化:将A/B选项转换为数值便于计算
# 将A/B选项转换为0/1 for col in df.columns[5:]: # 从第5列开始是题目 df[col] = df[col].map({'A': 0, 'B': 1})2. 基础统计分析
有了清洗好的数据,我们可以开始进行一些基础统计分析,了解测试群体的整体性格分布。
性格类型分布统计:
# 根据四个维度分数确定性格类型 def get_mbti_type(row): type_str = '' type_str += 'I' if row['E_I_score'] >=0 else 'E' type_str += 'N' if row['S_N_score'] >=0 else 'S' type_str += 'F' if row['T_F_score'] >=0 else 'T' type_str += 'P' if row['J_P_score'] >=0 else 'J' return type_str df['mbti_type'] = df.apply(get_mbti_type, axis=1) # 统计各类型占比 type_dist = df['mbti_type'].value_counts(normalize=True) * 100 print(type_dist)各维度得分分布可视化:
import matplotlib.pyplot as plt plt.figure(figsize=(12, 8)) dimensions = ['E_I_score', 'S_N_score', 'T_F_score', 'J_P_score'] titles = ['外向(E) vs 内向(I)', '实感(S) vs 直觉(N)', '思考(T) vs 情感(F)', '判断(J) vs 感知(P)'] for i, dim in enumerate(dimensions, 1): plt.subplot(2, 2, i) df[dim].hist(bins=20) plt.title(titles[i-1]) plt.xlabel('得分') plt.ylabel('人数') plt.tight_layout() plt.show()3. 深入数据挖掘
基础统计只是开始,真正有价值的是隐藏在数据中的关联和模式。
题目与性格维度的相关性分析:
# 计算每道题与四个维度的相关性 correlation_results = [] for q in df.columns[5:97]: # 假设前5列是元数据,后面是93道题 for dim in dimensions: corr = df[q].corr(df[dim]) correlation_results.append({'question': q, 'dimension': dim, 'correlation': corr}) corr_df = pd.DataFrame(correlation_results) # 找出与各维度最相关的题目 top_correlations = corr_df.groupby('dimension').apply( lambda x: x.nlargest(5, 'correlation')).reset_index(drop=True)性格类型与答题模式的聚类分析:
from sklearn.cluster import KMeans # 使用K-means聚类分析答题模式 X = df.iloc[:, 5:98] # 所有题目数据 kmeans = KMeans(n_clusters=16, random_state=42) # 16种MBTI类型 df['cluster'] = kmeans.fit_predict(X) # 比较聚类结果与实际MBTI类型 cluster_type_crosstab = pd.crosstab(df['cluster'], df['mbti_type'])4. 高级分析与应用
有了前面的分析基础,我们可以探索一些更高级的应用场景。
性格类型预测模型:
from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # 准备数据 X = df.iloc[:, 5:98] # 题目数据 y = df['mbti_type'] # 目标变量 # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 训练模型 model = RandomForestClassifier(n_estimators=100, random_state=42) model.fit(X_train, y_train) # 评估模型 y_pred = model.predict(X_test) print(f"模型准确率: {accuracy_score(y_test, y_pred):.2f}") # 查看特征重要性 feature_importance = pd.DataFrame({ 'question': X.columns, 'importance': model.feature_importances_ }).sort_values('importance', ascending=False)测试结果随时间的变化分析:
如果收集了同一批测试者多次测试的数据,可以分析性格特征的变化:
# 假设df包含timestamp列 df['test_date'] = pd.to_datetime(df['timestamp']) df.set_index('test_date', inplace=True) # 按月统计各类型占比变化 monthly_type_dist = df.groupby([pd.Grouper(freq='M'), 'mbti_type']).size().unstack().fillna(0) monthly_type_dist = monthly_type_dist.div(monthly_type_dist.sum(axis=1), axis=0) # 绘制变化趋势 monthly_type_dist.plot(figsize=(12, 6)) plt.title('MBTI类型占比随时间变化') plt.ylabel('占比') plt.xlabel('日期') plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.show()不同人群的性格特征对比:
如果有额外的人口统计信息(如年龄、职业等),可以进行更丰富的交叉分析:
# 假设df中有age_group和occupation列 age_type_dist = pd.crosstab(df['age_group'], df['mbti_type'], normalize='index') occupation_type_dist = pd.crosstab(df['occupation'], df['mbti_type'], normalize='index') # 可视化 fig, axes = plt.subplots(1, 2, figsize=(16, 6)) age_type_dist.plot(kind='bar', stacked=True, ax=axes[0]) occupation_type_dist.plot(kind='bar', stacked=True, ax=axes[1]) axes[0].set_title('不同年龄段的MBTI分布') axes[1].set_title('不同职业的MBTI分布') plt.tight_layout()在实际项目中,我发现数据质量对分析结果影响很大。特别是当测试者随意答题时,会产生大量噪声数据。一个实用的技巧是设置"验证题"——在测试中插入几道内容相似的问题,通过回答一致性来识别无效数据。