poverty

I just don’t understand why we have poverty today. There is so much money in the world. We are rich enough to really make poverty history. My government talks about making a better society while there are thousands of people living on the streets. My government says it is making a more equal society. Rubbish. This is all words. Many people say religion is very important to them but do little to help poor people. In fact, many religious people I know don’t like poor people. And then there are multinational companies who give very little to the poor. They even take away their land and water. The people with the most power to reduce poverty are those doing the least. How can they live in such big houses and drive such fancy cars?

 

 

http://www.tingclass.net/show-8099-236349-1.html

内容概要:本文介绍了一个基于多传感器融合的定位系统设计方案,采用GPS、里程计和电子罗盘作为定位传感器,利用扩展卡尔曼滤波(EKF)算法对多源传感器数据进行融合处理,最终输出目标的滤波后位置信息,并提供了完整的Matlab代码实现。该方法有效提升了定位精度与稳定性,尤其适用于存在单一传感器误差或信号丢失的复杂环境,如自动驾驶、移动采用GPS、里程计和电子罗盘作为定位传感器,EKF作为多传感器的融合算法,最终输出目标的滤波位置(Matlab代码实现)机器人导航等领域。文中详细阐述了各传感器的数据建模方式、状态转移与观测方程构建,以及EKF算法的具体实现步骤,具有较强的工程实践价值。; 适合人群:具备一定Matlab编程基础,熟悉传感器原理和滤波算法的高校研究生、科研人员及从事自动驾驶、机器人导航等相关领域的工程技术人员。; 使用场景及目标:①学习和掌握多传感器融合的基本理论与实现方法;②应用于移动机器人、无人车、无人机等系统的高精度定位与导航开发;③作为EKF算法在实际工程中应用的教学案例或项目参考; 阅读建议:建议读者结合Matlab代码逐行理解算法实现过程,重点关注状态预测与观测更新模块的设计逻辑,可尝试引入真实传感器数据或仿真噪声环境以验证算法鲁棒性,并进一步拓展至UKF、PF等更高级滤波算法的研究与对比。
内容概要:文章围绕智能汽车新一代传感器的发展趋势,重点阐述了BEV(鸟瞰图视角)端到端感知融合架构如何成为智能驾驶感知系统的新范式。传统后融合与前融合方案因信息丢失或算力需求过高难以满足高阶智驾需求,而基于Transformer的BEV融合方案通过统一坐标系下的多源传感器特征融合,在保证感知精度的同时兼顾算力可行性,显著提升复杂场景下的鲁棒性与系统可靠性。此外,文章指出BEV模型落地面临大算力依赖与高数据成本的挑战,提出“数据采集-模型训练-算法迭代-数据反哺”的高效数据闭环体系,通过自动化标注与长尾数据反馈实现算法持续进化,降低对人工标注的依赖,提升数据利用效率。典型企业案例进一步验证了该路径的技术可行性与经济价值。; 适合人群:从事汽车电子、智能驾驶感知算法研发的工程师,以及关注自动驾驶技术趋势的产品经理和技术管理者;具备一定自动驾驶基础知识,希望深入了解BEV架构与数据闭环机制的专业人士。; 使用场景及目标:①理解BEV+Transformer为何成为当前感知融合的主流技术路线;②掌握数据闭环在BEV模型迭代中的关键作用及其工程实现逻辑;③为智能驾驶系统架构设计、传感器选型与算法优化提供决策参考; 阅读建议:本文侧重技术趋势分析与系统级思考,建议结合实际项目背景阅读,重点关注BEV融合逻辑与数据闭环构建方法,并可延伸研究相关企业在舱泊一体等场景的应用实践。
# -*- coding: utf-8 -*- """ Created on Fri Aug 15 14:34:51 2025 @author: fly03 """ import os import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from datetime import datetime from sklearn.preprocessing import StandardScaler from sklearn.cluster import KMeans from sklearn.decomposition import PCA from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score from sklearn.impute import SimpleImputer import warnings warnings.filterwarnings('ignore') # 设置中文字体和样式 plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'DejaVu Sans'] plt.rcParams['axes.unicode_minus'] = False sns.set_style("whitegrid") #读取多个含有相同字段的Excel文件 def readMulFile(inputfilename=[]): megred_data=pd.DataFrame() for file in inputfilename: data=pd.read_excel(file) megred_data=pd.concat([megred_data,data],ignore_index=True) return megred_data #是否贫困预处理,用0和1表示 def processPinKun(data): data['是否贫困'] = data['是否贫困'].apply(lambda x: 1 if x == '是' else 0) return data #统计每列缺失值的情况 def countMissingValue(data): return data.isnull().sum() #统计交易金额正负情况,分别返回为负数和非负数的记录数 def countMoneyNegative(data): amount_distribution=(data['交易金额']<0).value_counts() return amount_distribution.get(True),amount_distribution.get(False) #删除交易金额为负数的记录 def deleteMoneyNegative(data): data_cleaned = data[(data[['交易金额']] >= 0).all(axis=1)] return data_cleaned #按交易地点分类,分为普通餐饮类、特色餐饮类、生活服务类和休闲娱乐类 def classify(data): # 定义分类条件 #含水果店、水吧、超市为生活服务类 condition1 = ( data['交易地点'].str.contains('水果店|水吧|超市', na=False, regex=True) ) #含雪、果茶、水果捞、甜品、糖葫芦、咖啡、蛋糕、面包为休闲娱乐类 condition2 = ( data['交易地点'].str.contains('雪|果茶|水果捞|甜品|糖葫芦|咖啡|蛋糕|面包', na=False, regex=True) ) # 创建分类列并设置默认值 data['分类'] = '餐饮类' # 默认分类为特色餐饮 #满足条件1则为生活服务类 data.loc[condition1,'分类'] = '生活服务类' #满足条件2为休闲娱乐类 data.loc[condition2,'分类'] = '休闲娱乐类' return data #数据时间预处理 def preprocess_time(df): """数据预处理和时间特征提取""" # 转换日期和时间 df['交易日期'] = pd.to_datetime(df['交易日期']) df['交易时间'] = pd.to_datetime(df['交易时间'], format='%H:%M:%S').dt.time df['交易日期时间'] = df.apply(lambda x: datetime.combine(x['交易日期'], x['交易时间']), axis=1) # 提取时间特征 df['月份'] = df['交易日期'].dt.month df['周几'] = df['交易日期'].dt.dayofweek # 0-6, 周一到周日 df['是否周末'] = df['周几'].isin([5, 6]).astype(int) # 提取时间段 def get_time_period(time_obj): hour = time_obj.hour if 6 <= hour < 9: return '早餐时段' elif 11 <= hour < 14: return '午餐时段' elif 17 <= hour < 20: return '晚餐时段' elif 20 <= hour < 24: return '夜宵时段' else: return '其他时段' df['时间段'] = df['交易时间'].apply(get_time_period) return df #按月统计贫困生和非贫困生在不同交易地点的交易次数和占比,交易点的分类的字段名为‘分类’ def countMonthNum(data): data['年月']=data['交易日期'].dt.to_period('M') pivot_result = data.pivot_table( index=['年月','分类'], columns='是否贫困', values='学号', aggfunc='count', fill_value=0 ).reset_index() pivot_result.columns = ['年月','交易地点类别','非贫困生交易次数','贫困生交易次数'] pivot_result['非贫困生月总次数']=pivot_result.groupby('年月')['非贫困生交易次数'].transform('sum') pivot_result['非贫困生每月交易地点占比']=(pivot_result['非贫困生交易次数']/pivot_result['非贫困生月总次数']*100).round(2) pivot_result['贫困生月总次数']=pivot_result.groupby('年月')['贫困生交易次数'].transform('sum') pivot_result['贫困生每月交易地点占比']=(pivot_result['贫困生交易次数']/pivot_result['贫困生月总次数']*100).round(2) #按年月和交易地点排序 pivot_result=pivot_result.sort_values(['年月','交易地点类别'],ascending=[True,False]) result=pivot_result[['年月','交易地点类别','非贫困生每月交易地点占比','贫困生每月交易地点占比']] result['差异']=pivot_result['非贫困生每月交易地点占比']-pivot_result['贫困生每月交易地点占比'] return result #按交易地点统计贫困生和非贫困生的消费总额占比,按分类列处理交易地点 def countMoney(data): data['年月']=data['交易日期'].dt.to_period('M') pivot_result = data.pivot_table( index=['年月','分类'], columns='是否贫困', values='交易金额', aggfunc=['sum'], fill_value=0 ).reset_index() pivot_result.columns = ['年月','交易地点类别','非贫困生总消费额','贫困生总消费额'] pivot_result['非贫困生月总消费额']=pivot_result.groupby('年月')['非贫困生总消费额'].transform('sum') pivot_result['非贫困生月总消费额占比']=(pivot_result['非贫困生总消费额']/pivot_result['非贫困生月总消费额']*100).round(2) pivot_result['贫困生月总消费额']=pivot_result.groupby('年月')['贫困生总消费额'].transform('sum') pivot_result['贫困生月总消费额占比']=(pivot_result['贫困生总消费额']/pivot_result['贫困生月总消费额']*100).round(2) #按年月和交易地点排序 pivot_result=pivot_result.sort_values(['年月','交易地点类别'],ascending=[True,False]) result=pivot_result[['年月','交易地点类别','非贫困生月总消费额占比','贫困生月总消费额占比']] result['差异']=pivot_result['非贫困生月总消费额占比']-pivot_result['贫困生月总消费额占比'] return result #统计消费月均值 def monthMean(data): data['年月']=data['交易日期'].dt.to_period('M') data['年月']=data['交易日期'].dt.to_period('M') pivot_result = data.pivot_table( index='年月', columns='是否贫困', values='交易金额', aggfunc=['mean'], fill_value=0 ).reset_index() pivot_result.columns = ['年月','非贫困生月均消费额','贫困生月均消费额'] pivot_result['差异']=pivot_result['非贫困生月均消费额']-pivot_result['贫困生月均消费额'] pivot_result=pivot_result.round(2) return pivot_result #分析周一到周日每天的交易金额平均值 def week(df): """分析时间模式""" results = [] #1 周内消费分析 pivot_result = df.pivot_table( index='周几', columns='是否贫困', values='交易金额', aggfunc=['mean'], fill_value=0 ).reset_index() pivot_result.columns = ['周几','非贫困生均消费额','贫困生均消费额'] pivot_result['差异']=pivot_result['非贫困生均消费额']-pivot_result['贫困生均消费额'] pivot_result=pivot_result.round(2) return pivot_result #按时间段分析均消费额 def time(df): """分析时间模式""" results = [] #1 周内消费分析 pivot_result = df.pivot_table( index='时间段', columns='是否贫困', values='交易金额', aggfunc=['mean'], fill_value=0 ).reset_index() pivot_result.columns = ['时间段','非贫困生均消费额','贫困生均消费额'] pivot_result['差异']=pivot_result['非贫困生均消费额']-pivot_result['贫困生均消费额'] pivot_result=pivot_result.round(2) return pivot_result def pinKunFenxi(df): grouped = df.groupby('学号') # 初始化特征 DataFrame features = pd.DataFrame(index=grouped.groups.keys()) features.index.name = '学号' # 1. 消费金额相关特征 features['总消费金额'] = grouped['交易金额'].sum() features['消费次数'] = grouped.size() features['平均消费金额'] = grouped['交易金额'].mean() features['消费金额标准差'] = grouped['交易金额'].std() features['消费金额变异系数'] = features['平均消费金额'] / (features['消费金额标准差'] + 1e-5) features['最大消费金额'] = grouped['交易金额'].max() features['最小消费金额'] = grouped['交易金额'].min() features['消费金额中位数'] = grouped['交易金额'].median() # 2. 消费时间相关特征 time_period_counts = df.groupby(['学号', '时间段']).size().unstack(fill_value=0) time_period_counts.columns = [f'{col}_消费次数' for col in time_period_counts.columns] features = features.join(time_period_counts) # 周末消费 weekend_stats = df.groupby('学号')['是否周末'].mean() features['周末消费比例'] = weekend_stats # 3. 消费地点相关特征 location_counts = df.groupby('学号')['分类'].nunique() features['消费地点类别数量'] = location_counts # 计算主要消费地点比例 main_locations = df.groupby(['学号', '分类']).size().groupby('学号').max() / features['消费次数'] features['主要地点类别消费比例'] = main_locations # 对交易地点进行编码并计算熵(衡量消费地点的分散程度) from scipy.stats import entropy def calculate_entropy(series): value_counts = series.value_counts(normalize=True) return entropy(value_counts) location_entropy = df.groupby('学号')['分类'].apply(calculate_entropy) features['消费地点熵'] = location_entropy.fillna(0) # 计算食堂消费比例 cafeteria_mask = df['分类'].str.contains('餐饮') cafeteria_ratio = df[cafeteria_mask].groupby('学号')['交易金额'].sum() / features['总消费金额'] features['餐饮类消费比例'] = cafeteria_ratio.fillna(0) # 计算生活服务类消费比例 cafeteria_mask = df['分类'].str.contains('生活') cafeteria_ratio = df[cafeteria_mask].groupby('学号')['交易金额'].sum() / features['总消费金额'] features['生活服务类消费比例'] = cafeteria_ratio.fillna(0) # 计算休闲娱乐类消费比例 cafeteria_mask = df['分类'].str.contains('休闲') cafeteria_ratio = df[cafeteria_mask].groupby('学号')['交易金额'].sum() / features['总消费金额'] features['休闲娱乐类消费比例'] = cafeteria_ratio.fillna(0) # 处理缺失值 features = features.fillna(0) # 处理无穷大值(由于除以0导致) features = features.replace([np.inf, -np.inf], 0) return features # 3. 确定最佳K值 def find_optimal_k(X_scaled, max_k=10): """ 使用肘部法则和轮廓系数确定最佳K值 """ # 计算不同K值的SSE(平方误差和) sse = [] silhouette_scores = [] k_range = range(2, max_k+1) for k in k_range: kmeans = KMeans(n_clusters=k, random_state=42, n_init=10) kmeans.fit(X_scaled) sse.append(kmeans.inertia_) # 计算轮廓系数(仅当k>1时) if k > 1: silhouette_scores.append(silhouette_score(X_scaled, kmeans.labels_)) else: silhouette_scores.append(0) # 绘制肘部法则图 plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) plt.plot(k_range, sse, 'bo-') plt.xlabel('K值') plt.ylabel('SSE') plt.title('肘部法则') # 绘制轮廓系数图 plt.subplot(1, 2, 2) plt.plot(k_range[1:], silhouette_scores[1:], 'ro-') plt.xlabel('K值') plt.ylabel('轮廓系数') plt.title('轮廓系数法') plt.tight_layout() plt.show() # 找到轮廓系数最大的K值 best_k = np.argmax(silhouette_scores[1:]) + 2 # +2因为从K=2开始 print(f"最佳K值(基于轮廓系数): {best_k}") print(f"对应的轮廓系数: {silhouette_scores[best_k-2]:.4f}") return best_k # 4. K-Means聚类分析 def perform_kmeans_clustering(features, n_clusters=3): """ 使用K-Means算法对学生进行聚类 """ # 检查并处理缺失值 print(f"处理前数据形状: {features.shape}") print(f"缺失值统计:\n{features.isnull().sum()}") # 删除包含NaN的行 features_clean = features.dropna() print(f"删除缺失值后数据形状: {features_clean.shape}") if len(features_clean) == 0: print("错误: 删除缺失值后数据为空!") return None, None, None, None, None # 标准化特征 scaler = StandardScaler() X_scaled = scaler.fit_transform(features_clean) # 使用PCA进行降维可视化 pca = PCA(n_components=2) X_pca = pca.fit_transform(X_scaled) # 执行K-Means聚类 kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init=10) clusters = kmeans.fit_predict(X_scaled) # 评估聚类效果 silhouette = silhouette_score(X_scaled, clusters) calinski = calinski_harabasz_score(X_scaled, clusters) davies = davies_bouldin_score(X_scaled, clusters) print(f"K-Means聚类评估指标:") print(f"轮廓系数: {silhouette:.4f} (越大越好,范围[-1,1])") print(f"Calinski-Harabasz指数: {calinski:.4f} (越大越好)") print(f"Davies-Bouldin指数: {davies:.4f} (越小越好)") # 可视化聚类结果 plt.figure(figsize=(10, 6)) scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=clusters, cmap='viridis', alpha=0.6) plt.colorbar(scatter, label='聚类标签') plt.xlabel('主成分1') plt.ylabel('主成分2') plt.title(f'K-Means聚类结果 (K={n_clusters})') plt.show() return clusters, kmeans, scaler, X_scaled, features_clean # 5. 解释聚类结果并分配贫困等级 def interpret_clusters_and_assign_poverty_level(features, clusters, kmeans_model): """ 分析聚类结果并为每个簇分配贫困等级 """ # 将聚类标签添加到特征数据中 features_with_clusters = features.copy() features_with_clusters['cluster'] = clusters # 计算每个聚类的特征均值 cluster_means = features_with_clusters.groupby('cluster').mean() # 打印每个聚类的特征统计 print("各聚类的特征均值:") print(cluster_means[['总消费金额', '平均消费金额', '餐饮类消费比例', '消费地点熵', '周末消费比例']]) # 根据总消费金额排序聚类,消费最低的为最贫困 poverty_mapping = {} sorted_clusters = cluster_means.sort_values('总消费金额').index # 分配贫困等级 - 固定为3个等级 # 0: '特别贫困', 1: '一般贫困', 2: '相对不贫困' for i, cluster_id in enumerate(sorted_clusters): poverty_mapping[cluster_id] = i features_with_clusters['贫困等级'] = features_with_clusters['cluster'].map(poverty_mapping) # 固定使用3个贫困等级标签(针对贫困生内部的细分) label_mapping = {0: '特别贫困', 1: '一般贫困', 2: '相对不贫困'} # 如果聚类数量不等于3,需要调整映射 n_clusters = len(cluster_means) if n_clusters != 3: print(f"警告: 聚类数量为{n_clusters},但需要3个贫困等级。将尝试重新分配...") # 根据聚类数量重新分配标签 if n_clusters < 3: # 如果聚类数量少于3,重复使用某些标签 labels = ['特别贫困', '一般贫困', '相对不贫困'] label_mapping = {i: labels[min(i, 2)] for i in range(n_clusters)} else: # 如果聚类数量多于3,使用前缀+编号 label_mapping = {i: f'贫困等级{i+1}' for i in range(n_clusters)} features_with_clusters['贫困等级标签'] = features_with_clusters['贫困等级'].map(label_mapping) # 显示贫困等级分布 poverty_distribution = features_with_clusters['贫困等级标签'].value_counts() print("\n贫困等级分布:") for level, count in poverty_distribution.items(): percentage = count / len(features_with_clusters) * 100 print(f"{level}: {count} 名学生 ({percentage:.1f}%)") # 可视化贫困等级与关键特征的关系 fig, axes = plt.subplots(2, 2, figsize=(12, 10)) # 总消费金额 vs 食堂消费比例 scatter = axes[0, 0].scatter( features_with_clusters['总消费金额'], features_with_clusters['餐饮类消费比例'], c=features_with_clusters['贫困等级'], cmap='viridis' ) axes[0, 0].set_xlabel('总消费金额') axes[0, 0].set_ylabel('餐饮消费比例') plt.colorbar(scatter, ax=axes[0, 0], label='贫困等级') axes[0, 0].set_title('总消费金额 vs 餐饮消费比例') # 平均消费金额 vs 消费地点熵 scatter = axes[0, 1].scatter( features_with_clusters['平均消费金额'], features_with_clusters['消费地点熵'], c=features_with_clusters['贫困等级'], cmap='viridis' ) axes[0, 1].set_xlabel('平均消费金额') axes[0, 1].set_ylabel('消费地点熵') plt.colorbar(scatter, ax=axes[0, 1], label='贫困等级') axes[0, 1].set_title('平均消费金额 vs 消费地点熵') # 贫困等级与总消费金额的箱线图 sns.boxplot(x='贫困等级标签', y='总消费金额', data=features_with_clusters, ax=axes[1, 0]) axes[1, 0].set_title('各贫困等级的总消费金额分布') axes[1, 0].tick_params(axis='x', rotation=45) # 贫困等级与食堂消费比例的箱线图 sns.boxplot(x='贫困等级标签', y='餐饮类消费比例', data=features_with_clusters, ax=axes[1, 1]) axes[1, 1].set_title('各贫困等级的餐饮消费比例分布') axes[1, 1].tick_params(axis='x', rotation=45) plt.tight_layout() plt.show() # 打印每个贫困等级的典型特征 print("\n各贫困等级的典型特征:") poverty_means = features_with_clusters.groupby('贫困等级标签').mean() for level in poverty_means.index: row = poverty_means.loc[level] print(f"\n{level}学生:") print(f" 平均总消费金额: {row['总消费金额']:.2f}元") print(f" 平均单次消费金额: {row['平均消费金额']:.2f}元") print(f" 餐饮消费比例: {row['餐饮类消费比例']:.2%}") print(f" 消费地点多样性(熵): {row['消费地点熵']:.3f}") return features_with_clusters def main(): inputfilename=[] filenum=int(input('请输入文件的个数:\n')) for i in range(filenum): fname=input(f'请输入第{i+1}个文件名:\n') if os.path.exists(fname): inputfilename.append(fname) else: print('输入有误,该文件不存在!') print("文件输入完毕!") print("是否贫困数据标准化化预处理中......") data=readMulFile(inputfilename) if data.empty: print("数据为空!") return #数据不为空,则进行是否贫困数据预处理 data=processPinKun(data) #输出每列缺失值情况 print(f'每列缺失值情况如下:\n{countMissingValue(data)}') #输出交易金额负数和非负数记录数情况 yes,no=countMoneyNegative(data) print('交易金额正负数情况如下:') print(f'交易金额为负数的记录共{yes}条,非负数的记录共{no}条') #删除交易金额为负数的记录 print('交易金额为负的记录正在删除中......') data=deleteMoneyNegative(data) print('交易金额为负的记录删除完成') #筛选贫困生数据 print('筛选贫困生数据中......') poverty_data = data[data['是否贫困'] == 1].copy() print(f"贫困生数据记录数: {len(poverty_data)}") print(f"贫困生人数: {poverty_data['学号'].nunique()}") if len(poverty_data) == 0: print("错误: 没有找到贫困生数据!") return #按交易地点进行分类 print('按交易地点进行分类中......') poverty_data=classify(poverty_data) poverty_data=preprocess_time(poverty_data) # 生成特征 print('生成贫困生消费特征中......') features = pinKunFenxi(poverty_data) # 检查特征数据 print(f"特征数据形状: {features.shape}") print(f"特征数据缺失值统计:\n{features.isnull().sum()}") # 如果有缺失值,进行处理 if features.isnull().sum().sum() > 0: print("处理缺失值...") features = features.fillna(0) features = features.replace([np.inf, -np.inf], 0) # 删除仍有缺失值的行 features_clean = features.dropna() print(f"清理后特征数据形状: {features_clean.shape}") if len(features_clean) == 0: print("错误: 清理后数据为空!") return # 标准化特征 scaler = StandardScaler() X_scaled = scaler.fit_transform(features_clean) # 强制使用3个聚类,因为需要3个贫困等级 optimal_k = 3 print(f"\n使用K={optimal_k}进行K-Means聚类(固定为3个贫困等级)...") result = perform_kmeans_clustering(features_clean, n_clusters=optimal_k) if result[0] is not None: clusters, kmeans_model, scaler, X_scaled, features_clean = result print("\n解释聚类结果并分配贫困等级...") features_with_clusters = interpret_clusters_and_assign_poverty_level(features_clean, clusters, kmeans_model) # 保存结果 result_df = features_with_clusters[['贫困等级', '贫困等级标签']].copy() result_df.to_csv('贫困生内部贫困等级划分结果.csv') print("\n结果已保存到 '贫困生内部贫困等级划分结果.csv'") # 显示部分学生的贫困等级 print("\n部分贫困生的贫困等级划分结果:") sample_results = result_df.sample(min(10, len(result_df))) for idx, row in sample_results.iterrows(): print(f"学号: {idx}, 贫困等级: {row['贫困等级标签']}") # 显示贫困等级统计 print("\n贫困等级统计:") poverty_stats = result_df['贫困等级标签'].value_counts().sort_index() for level, count in poverty_stats.items(): percentage = count / len(result_df) * 100 print(f"{level}: {count}人 ({percentage:.1f}%)") # 保存详细的贫困生分析结果 detailed_results = features_with_clusters.copy() detailed_results.to_csv('贫困生详细分析结果.csv') print("详细分析结果已保存到 '贫困生详细分析结果.csv'") else: print("聚类分析失败!") if __name__=='__main__': main()
09-27
<think>我们有一个Python脚本,该脚本用于分析贫困生的消费数据,并根据消费行为将贫困生分为三个贫困等级(特别贫困、一般贫困、相对不贫困)。脚本的主要步骤包括: 1. 读取多个Excel文件并合并。 2. 数据预处理(将“是否贫困”列转换为0/1,删除交易金额为负的记录,按交易地点分类,提取时间特征等)。 3. 筛选贫困生数据(即“是否贫困”为1的记录)。 4. 为每个贫困生生成消费特征(如总消费金额、平均消费金额、消费时间分布、消费地点分布等)。 5. 使用K-Means聚类算法(固定K=3)对贫困生进行聚类,并将每个聚类解释为贫困等级。 6. 保存结果并可视化。 然而,在聚类步骤中,函数`perform_kmeans_clustering`可能返回None(当数据为空时),并且聚类结果解释函数`interpret_clusters_and_assign_poverty_level`要求聚类数量为3,但代码中做了非3个聚类的处理(但主函数中固定为3)。 现在,假设我们想要改进这个脚本,特别是在聚类部分,我们想确保即使数据量小或者特征有变化,也能稳定运行。同时,我们注意到在生成特征时,可能因为某个特征的计算(如消费金额标准差)导致NaN或无穷大,虽然已经做了处理,但可能还有遗漏。 我们将对以下部分进行改进: 1. 在特征生成步骤,为了避免除以0导致的无穷大,我们在计算变异系数时加了一个小常数(1e-5),但可能不够。我们可以考虑在计算变异系数时,如果标准差为0,则变异系数设为0(因为均值为0时,变异系数无意义;均值不为0而标准差为0,说明所有值相同,变异系数为0)。 2. 在聚类之前,我们删除所有包含NaN的行,但这样可能会丢失数据。我们可以考虑使用更鲁棒的缺失值处理,比如使用中位数或均值填充(但注意,我们的特征中有一些比例特征,使用中位数填充可能更合适)。 3. 在`perform_kmeans_clustering`函数中,我们使用PCA降维可视化,但PCA可能受到异常值影响。我们可以考虑使用RobustScaler代替StandardScaler,或者在使用PCA之前先去除异常值。 但是,考虑到时间,我们主要改进特征生成部分的稳健性。 具体修改如下: 在`pinKunFenxi`函数中,计算变异系数时,我们修改为: 变异系数 = 标准差 / 均值 (当均值不为0时) 如果均值为0,则变异系数设为0(因为此时标准差也必然为0,否则会出现无穷大)。 修改代码: features['消费金额变异系数'] = features.apply( lambda x: x['消费金额标准差'] / x['平均消费金额'] if x['平均消费金额'] != 0 else 0, axis=1 ) 另外,在计算各项比例时,如果分母为0,我们已经用fillna(0)填充,但可能之前计算时出现0/0导致NaN。所以我们在计算比例时,使用: 分母为0时,比例设为0。 但是,查看现有代码,在计算比例时已经使用了fillna(0),所以已经处理了NaN。 此外,在特征生成后,我们使用: features = features.fillna(0) features = features.replace([np.inf, -np.inf], 0) 所以可以保证特征矩阵没有NaN和无穷大。 另一个问题是,在`perform_kmeans_clustering`函数中,我们删除了所有包含NaN的行,但我们已经填充了,所以理论上不会有NaN。所以这里可以去掉删除NaN的步骤?但为了保险,我们保留。 另外,我们注意到主函数中,在生成特征后,又进行了一次缺失值处理: features = features.fillna(0) features = features.replace([np.inf, -np.inf], 0) 然后才进行标准化。所以数据应该是干净的。 现在,我们重新检查整个流程,确保在特征生成后没有NaN和无穷大。 但是,在`pinKunFenxi`函数中,我们在返回前已经做了: features = features.fillna(0) features = features.replace([np.inf, -np.inf], 0) 所以主函数中的处理是冗余的,可以去掉。 因此,我们修改主函数中的特征处理部分: 原主函数中: # 生成特征 ... # 如果有缺失值,进行处理 if features.isnull().sum().sum() > 0: print("处理缺失值...") features = features.fillna(0) features = features.replace([np.inf, -np.inf], 0) 由于在`pinKunFenxi`中已经处理,所以这里可以删除。但为了保险(比如以后修改了`pinKunFenxi`函数),我们保留。 现在,我们考虑另一种情况:当贫困生数据量很少(比如少于3个)时,聚类无法进行。因此,在聚类之前,我们需要检查贫困生数量是否大于等于3。 修改主函数中的聚类部分: # 强制使用3个聚类,因为需要3个贫困等级 optimal_k = 3 # 检查贫困生数量 if len(features_clean) < optimal_k: print(f"警告: 贫困生数量({len(features_clean)})少于聚类数量({optimal_k}),无法进行聚类分析!") # 这里我们可以考虑将所有人标记为同一贫困等级(比如一般贫困)? # 创建默认结果 features_with_clusters = features_clean.copy() features_with_clusters['cluster'] = 0 # 分配贫困等级标签,由于只有1个类,我们将其设为“一般贫困” features_with_clusters['贫困等级'] = 0 features_with_clusters['贫困等级标签'] = '一般贫困' # 保存结果 result_df = features_with_clusters[['贫困等级', '贫困等级标签']].copy() result_df.to_csv('贫困生内部贫困等级划分结果.csv') print("由于贫困生数量不足,所有贫困生被标记为'一般贫困'。") else: # 进行聚类 ... 这样修改后,当贫困生数量少于3时,程序不会崩溃。 由于代码较长,我们只给出修改的关键部分。 修改1:特征生成函数中的变异系数计算 修改2:主函数中增加贫困生数量检查 以下是修改后的代码部分(只修改了`pinKunFenxi`函数和`main`函数中的聚类部分): </think>以下是针对提供的贫困生消费数据分析脚本的详细分析和改进建议: ### 代码分析与优化建议 #### 1. 数据预处理优化 ```python # 优化后的分类函数 def classify(data): # 优先匹配生活服务类 condition1 = data['交易地点'].str.contains('水果店|水吧|超市', na=False, regex=True) # 其次匹配休闲娱乐类 condition2 = data['交易地点'].str.contains('雪|果茶|水果捞|甜品|糖葫芦|咖啡|蛋糕|面包', na=False, regex=True) # 创建分类列 data['分类'] = np.select( [condition1, condition2], ['生活服务类', '休闲娱乐类'], default='餐饮类' # 默认分类 ) return data ``` **优化说明:** 1. 使用`np.select()`替代多个`loc`赋值,提高执行效率 2. 明确条件优先级,避免分类重叠 3. 简化逻辑,提高可读性 #### 2. 特征工程改进 ```python # 改进后的消费特征提取 def pinKunFenxi(df): # ... 其他特征计算保持不变 # 使用正则表达式精确匹配分类 features['餐饮类消费比例'] = calculate_category_ratio(df, '餐饮类') features['生活服务类消费比例'] = calculate_category_ratio(df, '生活服务类') features['休闲娱乐类消费比例'] = calculate_category_ratio(df, '休闲娱乐类') # 添加消费稳定性特征 features['消费稳定性'] = 1 / (features['消费金额标准差'] + 1e-5) return features def calculate_category_ratio(df, category): mask = df['分类'] == category return df[mask].groupby('学号')['交易金额'].sum() / features['总消费金额'] ``` **改进点:** 1. 添加消费稳定性特征(标准差的倒数) 2. 使用精确匹配替代模糊匹配(str.contains) 3. 模块化分类消费比例计算 4. 添加微小常量防止除零错误 #### 3. 聚类分析优化 ```python # 增强的聚类函数 def perform_kmeans_clustering(features, n_clusters=3): # 使用更鲁棒的填充方法 imputer = SimpleImputer(strategy='median') features_imputed = pd.DataFrame( imputer.fit_transform(features), columns=features.columns, index=features.index ) # 标准化处理 scaler = RobustScaler() # 使用RobustScaler减少异常值影响 X_scaled = scaler.fit_transform(features_imputed) # 使用UMAP降维可视化(替代PCA) reducer = umap.UMAP(n_components=2, random_state=42) X_umap = reducer.fit_transform(X_scaled) # ... 后续聚类逻辑保持不变 ``` **优化说明:** 1. 使用中位数填充替代简单删除缺失值 2. 采用RobustScaler标准化,减少异常值影响 3. 使用UMAP替代PCA进行降维,更好保留局部结构 4. 保持原始索引,便于结果回溯 #### 4. 贫困等级分配逻辑增强 ```python def interpret_clusters_and_assign_poverty_level(features, clusters, kmeans_model): # 添加聚类中心分析 cluster_centers = kmeans_model.cluster_centers_ scaled_centers = pd.DataFrame( scaler.inverse_transform(cluster_centers), columns=features.columns ) # 基于多维度排序(消费金额 + 食堂比例 + 稳定性) poverty_score = ( 0.5 * scaled_centers['总消费金额'].rank(ascending=True) + 0.3 * scaled_centers['餐饮类消费比例'].rank(ascending=False) + 0.2 * scaled_centers['消费稳定性'].rank(ascending=True) ) # 动态分配贫困等级 poverty_mapping = { cluster_id: poverty_score.rank()[cluster_id] for cluster_id in range(len(poverty_score)) } # ... 后续逻辑保持不变 ``` **改进点:** 1. 多维度计算贫困得分(消费金额 + 食堂比例 + 稳定性) 2. 动态映射贫困等级,不限定3个等级 3. 显示逆向转换后的聚类中心特征 4. 使用加权评分替代简单排序 ### 完整改进脚本 ```python # -*- coding: utf-8 -*- """改进版贫困生消费分析脚本""" import os import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import umap # 新增降维库 from datetime import datetime from sklearn.preprocessing import RobustScaler, StandardScaler from sklearn.cluster import KMeans from sklearn.impute import SimpleImputer from sklearn.metrics import silhouette_score, calinski_harabasz_score, davies_bouldin_score import warnings warnings.filterwarnings('ignore') # ... [保持原有的设置和辅助函数] ... # 优化分类函数 def classify(data): condition1 = data['交易地点'].str.contains('水果店|水吧|超市', na=False, regex=True) condition2 = data['交易地点'].str.contains('雪|果茶|水果捞|甜品|糖葫芦|咖啡|蛋糕|面包', na=False, regex=True) data['分类'] = np.select( [condition1, condition2], ['生活服务类', '休闲娱乐类'], default='餐饮类' ) return data # 增强特征工程 def pinKunFenxi(df): grouped = df.groupby('学号') features = pd.DataFrame(index=grouped.groups.keys()) features.index.name = '学号' # 基础消费特征 features['总消费金额'] = grouped['交易金额'].sum() features['消费次数'] = grouped.size() features['平均消费金额'] = grouped['交易金额'].mean() features['消费金额标准差'] = grouped['交易金额'].std() features['消费金额变异系数'] = np.where( features['平均消费金额'] > 0, features['消费金额标准差'] / features['平均消费金额'], 0 ) features['消费稳定性'] = 1 / (features['消费金额标准差'] + 1e-5) # 时间特征 features['周末消费比例'] = df.groupby('学号')['是否周末'].mean() # 分类消费比例 for category in ['餐饮类', '生活服务类', '休闲娱乐类']: mask = df['分类'] == category category_sum = df[mask].groupby('学号')['交易金额'].sum() features[f'{category}消费比例'] = category_sum / features['总消费金额'] # 处理缺失和异常 features = features.fillna(0).replace([np.inf, -np.inf], 0) return features # 聚类分析优化 def perform_kmeans_clustering(features, n_clusters=3): # 缺失值处理 imputer = SimpleImputer(strategy='median') features_imputed = pd.DataFrame( imputer.fit_transform(features), columns=features.columns, index=features.index ) # 标准化 scaler = RobustScaler() X_scaled = scaler.fit_transform(features_imputed) # 降维可视化 reducer = umap.UMAP(n_components=2, random_state=42) X_umap = reducer.fit_transform(X_scaled) # 聚类 kmeans = KMeans(n_clusters=n_clusters, random_state=42, n_init=10) clusters = kmeans.fit_predict(X_scaled) # 评估 scores = { '轮廓系数': silhouette_score(X_scaled, clusters), 'Calinski-Harabasz': calinski_harabasz_score(X_scaled, clusters), 'Davies-Bouldin': davies_bouldin_score(X_scaled, clusters) } # 可视化 plt.figure(figsize=(10,6)) plt.scatter(X_umap[:,0], X_umap[:,1], c=clusters, cmap='viridis') plt.title(f'UMAP降维聚类结果 (K={n_clusters})') plt.show() return clusters, kmeans, scaler, X_scaled, features_imputed # 动态贫困等级分配 def interpret_clusters_and_assign_poverty_level(features, clusters, kmeans_model, scaler): features['cluster'] = clusters cluster_centers = scaler.inverse_transform(kmeans_model.cluster_centers_) # 计算贫困得分 poverty_score = ( 0.5 * cluster_centers[:, features.columns.get_loc('总消费金额')] + 0.3 * (1 - cluster_centers[:, features.columns.get_loc('餐饮类消费比例')]) + 0.2 * cluster_centers[:, features.columns.get_loc('消费稳定性')] ) # 分配等级 rank = pd.Series(poverty_score).rank() poverty_mapping = dict(zip(range(len(rank)), rank)) features['贫困等级'] = features['cluster'].map(poverty_mapping) # 标签映射 bins = [0, 1.5, 2.5, np.inf] labels = ['特别贫困', '一般贫困', '相对不贫困'] features['贫困等级标签'] = pd.cut( features['贫困等级'], bins=bins, labels=labels, include_lowest=True ) # ... [保持原有的分析和可视化] ... return features # 主函数更新 def main(): # ... [保持文件读取和预处理] ... # 聚类前检查数据量 if len(features_clean) < 3: print("贫困生数量不足,无法聚类") features_clean['贫困等级标签'] = '一般贫困' # 默认标签 result_df = features_clean[['贫困等级标签']].copy() else: # 执行聚类分析 results = perform_kmeans_clustering(features_clean, n_clusters=min(3, len(features_clean))) features_with_clusters = interpret_clusters_and_assign_poverty_level(*results) result_df = features_with_clusters[['贫困等级标签']].copy() # 保存结果 result_df.to_csv('贫困生内部贫困等级划分结果.csv') ``` ### 关键改进总结 1. **数据处理增强** - 使用`np.select()`优化分类逻辑 - 采用中位数填充缺失值 - 添加消费稳定性新特征 2. **聚类分析优化** - 引入UMAP降维替代PCA - 使用RobustScaler减少异常值影响 - 动态确定贫困等级映射 3. **鲁棒性提升** - 增加贫困生数量检查 - 多维度贫困评分机制 - 灵活处理小样本情况 4. **可解释性增强** - 可视化聚类中心特征 - 贫困等级动态分箱 - 多维度贫困评分公式 ### 执行说明 1. 需要安装新依赖: ```bash pip install umap-learn ``` 2. 运行时优先处理数据质量问题: - 检查交易地点分类准确性 - 验证贫困生标识正确性 - 确认金额单位为一致
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值