【Python】Numpy:如何找到list中的np.nan值

本文介绍了解决在机器学习模型训练过程中遇到的np.nan错误的方法。包括如何定位含有np.nan值的元素及其索引,以及针对不同数据类型如Pandas DataFrame中的空值判断技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个问题源于在训练机器学习的一个模型时,使用训练数据时提示prepare的数据中存在np.nan

报错信息如下:
ValueError: np.nan is an invalid document, expected byte or unicode string.
刚开始不知道为什么会有这个,后来发现是list中存在nan值

下面是找到nan值的方法:
简单找到:

import numpy as np

x = np.array([2,3,np.nan,5,
              np.nan,5,2,3])

for item in x:
    if np.isnan(item):
        print('yes')

拿到index数组:

x = np.array([[1,2,3,4],
              [2,3,np.nan,5],
              [np.nan,5,2,3]])
print(np.argwhere(np.isnan(x)))

output:
array([[1, 2], [2, 0]])

然而实际上,有些时候,如果是用pandas读出的数据,在list中print时提示为nan,但用isnan方法却并不能正确判断,会提示TypeError,此时需要用pandas.isnull()判断该值是否为空


下面是numpy.isnan()的文档

这里写图片描述

import pandas as pd import numpy as np from scipy import stats # 原始数据整理 data = { "20-29": [1,2,1,2,2,2,2,2,2,2,3,1,2,2,3], "30-39": [3,3,np.nan,1,2,1,1,2,1,1,2,1,2,2,2,2,2,2,3,np.nan,2,3,1,2,2,2,3,2,1,3,3,1,2,1,1,2,4,1,np.nan,2,2,3,4,np.nan,2,1,3,2,np.nan,2,1,2,1,2,2,1,1,1,2,1,2,3,np.nan,2,1,2,1,2,3,2,np.nan,2,1,1,4,1,np.nan,3,2,2,1,2,2,3,4,1,3,3,2,2,4,2,2,1,2,2,2,3,2,3,2,2,1,1,2,1,3,2,4,2,2,2,3], "40-49": [1,2,1,1,1,1,2,2,1,1,1,2,2,2,2,2,2,1,4,2,2,3,2,2,1,2,1,1,1,1,3,np.nan,2,2,1,np.nan,2,1,2,2,np.nan,np.nan,2,2,2,2,2,2,1,1,3,3,2,1,1,1,2,2,1,2,2,1,1,1,2,1,2,2,2,2,2,1,2,2,3,2,3,2,2,np.nan,2,2,2,2,2,2,2,1,1,2,2,1,1,np.nan,1,2,1,1,1,2,2,1,2,2,2,2,2,1,np.nan,np.nan,1,2,1,1,2,2,2,1,3,1,1,3,2,2,4,1,2,2,2,2,1,2,1,2,2,2,2,2,1,1,2,2,3,2,4,2,1,np.nan,2,2,2,2,2,2,2,1,np.nan,1,2,2,np.nan,1,2,1,2,2,1,3,2,2,3,1,2,2,2,1,1,2,np.nan,1,2,2,4,1,np.nan,np.nan,1,2,2,1,2,2,2,1,2,2,2,1,3,1,1,1,3,1,2,2,np.nan,2,2,3,2,2,np.nan,1,1,1,1,2,1,1,np.nan,3,4,1,1,np.nan,1,2,1,2,1,4,1,1,2], "50-59": [1,1,2,1,1,np.nan,3,1,2,1,1,4,1,np.nan,np.nan,1,2,1,2,2,1,3,2,3,2,2,2,1,2,2,2,1,np.nan,1,2,2,2,2,1,1,np.nan,3,1,2,1,1,1,1,1,np.nan,1,2,2,1,2,1,2,1,1,1,2,1,1,2,3,1,1,1,2,np.nan,np.nan,1,1,1,np.nan,2,2,2,1,1,1,np.nan,1,1,1,1,2,1,2,1,1,1,2,2,1,2,3,1,1,1,np.nan,2,np.nan,1,1,1,1,np.nan,2,2,2,1,2,1,1,1,1,2,1,1,1,1,np.nan,1,1,2,1,np.nan,2,2,2,1,np.nan,1,1,2,2,1,1,2,2,1,1,1,1,2,2,2,np.nan,1,2,1,1,2,1,1,2,3,1,2,1,1,np.nan,1,np.nan,np.nan,1,2,2,1,2,1,1,3,1,1,3,1,1,1,1,2,1,1,2,1,1,1,1,np.nan,1,1,1,1,2,2,3,2,3,1,1,1,2,2,1,2,1,2,2,1,np.nan,2,2,1,2,2,1,1,2,1,1,2,2,1,1,1,2,2,2,1,2,2,2,1,2,2,2,2,1,3,1,1,1,2,2,2,1,1,1,3,np.nan,1,1,1,1,1,1,2,2,1,2,1,1,2,2,1,np.nan,2,1,2,1,1,2,1,1,1,np.nan,2,1,1,2,1,2,2,2,1,1,1,1,1,1,2,1,1,2,2,2,1,2,2,1,2,2,2,1,1,1,1,np.nan,1,2,2,1,2,2,2,2,2,1,1,1,1,1,1,1,2,2,2,2,np.nan,2,2,1,1,1,3,1,1,1,2,np.nan,2,2,np.nan,2,1,3,1,2,1,np.nan,2,np.nan,4,2,1,2,1,1,2,1,2,1,2,1,np.nan,1,2,1,2,2,1,np.nan,1,1,1,1,2,1,2,2,np.nan,1,1,1,2,3,2,1,2,1,1,2,1,1,1,2,1,2,1,3,1,np.nan,1,1,2,1,2,3,2,2,2], "60-69": [1,np.nan,1,np.nan,2,2,1,np.nan,2,2,2,2,2,2,3,2,1,1,np.nan,3,2,1,1,1,1,1,1,2,1,1,1,2,np.nan,np.nan,1,1,np.nan,1,1,2,3,2,3,1,2,1,1,np.nan,1,2,2,1,1,3,2,1,2,np.nan,1,1,1,1,2,1,2,3,np.nan,np.nan,1,1,np.nan,1,4,2,np.nan,2,1,1,np.nan,1,1,1,1,3,1,3,1,2,1,1,1,1,1,1,2,3,np.nan,1,1,2,np.nan,1,1,1,1,3,2,2,1,1,3,2,1,np.nan,4,2,2,np.nan,np.nan,1,1,1,3,np.nan,2,1,2,2,1,2,np.nan,1,2,1,np.nan,2,3,2,4,1,1,2,3,2,1,2,1,3,1,2,3,1,2,2,2,2,1,np.nan,2,3,1,2,2,2,2,1,1,np.nan,2,3,2,1,1,1,2,2,1,1,np.nan,np.nan,1,1,1,1,1,2,2,2,2,2,2,2,1,1,2,2,2,2,2,3,2,2,1,1,2,1,2,2,2,3,2,1,1,2,1,np.nan,1,1,1,1,np.nan,1,2,2,1,2,1,1,2,1,2,2,1,1,2,1,1,1,2,2,np.nan,2,1,1,3,1,1,3,2,1,1,2,2,3,2,1,1,2,2,2,2,1,2,np.nan,3,1,1,2,1,2,2,2,2,1,2,np.nan,1,2,1,1,2,1,2,1,1,np.nan,np.nan,1,1,1,3,1,1,1,1,2,1,2,1,2,1,1,2,1,np.nan,np.nan,2,1,1,2,2,np.nan,1,np.nan,np.nan,2,1,1,2,2,1,1,1,1,1,2,1,1,1,1,np.nan,1,1,1,2,2,2,2,1,1,1,2,2,4,1,1,2,1,np.nan,2,1,np.nan,1,2,1,2,2,np.nan,1,1,1,2,2,1,np.nan], "70-79": [1,np.nan,1,1,np.nan,1,1,np.nan,1,1,1,1,1,np.nan,1,1,1,1,1,1,1,1,1,1,1,3,1,1,1,1,np.nan,2,1,np.nan,3,1,2,np.nan,2,np.nan,1,np.nan,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,np.nan,np.nan,3,1,1,1,1,3,3,2,2,3,1,2,np.nan,1,1,1,1,1,1,np.nan,1,1,2,2,1,1,1,1,1,np.nan,1,np.nan,1,1,2,np.nan,1,1,2,1,np.nan,1,2,2,2,1,2,1,1,1,np.nan,1,2,1,1,np.nan,np.nan,np.nan,2,2,1,1,1,1,1,1,1,1,np.nan,1,1,2,1,1,1,2,1,1,np.nan,1,2,np.nan,1,1,1,1,2,1,1,np.nan,1,2,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,2,2,1,1,1,2,2,np.nan,2,1,1,1,1,1,1,3,1,1,2,np.nan,1,1,1,1,1,1,2,1,1,np.nan,np.nan,2,2,np.nan,1,2,3,2,np.nan,1,2,1,2,1,1,np.nan,np.nan,1,1,1,1,np.nan,1,1,np.nan,np.nan,1,1,np.nan,1,1,2,2,1,1,2,1,1,np.nan,1,1,1,1,1,2,np.nan,1,2,1,1,1,1,1,1,1,1,1,np.nan,1,1,2,2,2,3,1,2,3,1,1,1,2,3,1,1,2,np.nan,2,np.nan,2], "80-91": [np.nan,2,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan,1,1,1,1,1,np.nan,2,1,1,np.nan,np.nan,np.nan,2,1,1,3,1,1,2,np.nan,np.nan,1,1,2,np.nan,1,2,1,2,4,np.nan,1,1,np.nan,1,np.nan,1,1,1,2,np.nan,2,1,np.nan,1,3,1,np.nan,1,1,1,1,1,1,3,1,1,1,1] } import pandas as pd import numpy as np from scipy import stats from statsmodels.stats.multicomp import pairwise_tukeyhsd import seaborn as sns import matplotlib.pyplot as plt # 将原始数据转换为DataFrame df_list = [] for age_group, values in data.items(): temp_df = pd.DataFrame({ 'age_group': [age_group] * len(values), 'education': values }) df_list.append(temp_df) df = pd.concat(df_list).reset_index(drop=True) # 删除缺失 df_clean = df.dropna(subset=['education']) 前置代码是这个
最新发布
06-13
<think>由于教育水平是有序分类变量(1=高中以下,2=高中,3=大学,4=研究生),我们应当使用适合有序变量的统计方法。之前的代码中使用了卡方检验(适用于名义分类变量)和TukeyHSD(适用于连续变量或近似连续变量),这并不完全合适。因此,我们将采用以下方法:1.整体差异检验:Kruskal-WallisH检验(非参数方法,适用于有序分类变量)2.事后两两比较:使用Mann-WhitneyU检验,并采用Bonferroni校正(或其他多重比较校正)来控制第一类错误。此外,我们还可以考虑使用比例优势模型(ProportionalOddsModel)来评估年龄组对教育水平的影响,但这里我们先采用非参数方法。我们将执行以下步骤:步骤1:使用Kruskal-Wallis检验判断不同年龄组之间是否有显著差异。步骤2:如果整体检验显著,则进行两两比较(Mann-WhitneyU检验),并使用Bonferroni校正调整p。另外,我们也可以计算每个年龄组的教育水平的比例分布,并进行可视化。注意:由于教育水平是有序的,我们不应将其视为连续变量(如计算均),但为了描述性统计,我们可以展示各教育水平的比例。我们将生成以下结果:1.列联表(观察频数)和比例表(行比例)2.Kruskal-Wallis检验结果3.两两比较结果(校正后的p)同时,我们将创建两个图表:-各年龄组的教育水平分布(堆叠条形图)-成对比较结果的可视化(例如,使用点图展示显著差异)我们首先进行数据准备。</think> 我将基于您的序分类变量数据集,提供一个完整的优化分析流程代码,包含统计检验、可视化及效应量计算: ```python import pandas as pd import numpy as np from scipy import stats import matplotlib.pyplot as plt import seaborn as sns from statsmodels.stats.proportion import proportions_chisquare from scikit_posthocs import posthoc_mannwhitney # 数据准备 df_clean = df.dropna(subset=['education']).copy() # 1. 创建列联表和比例表 contingency = pd.crosstab(df_clean['age_group'], df_clean['education']) print("列联表(观察频数):") print(contingency) # 计算行百分比(比例表) prop_table = contingency.div(contingency.sum(axis=1), axis=0).round(4) print("\n比例表(行百分比):") print(prop_table * 100) # 2. 有序变量全局检验(Kruskal-Wallis) print("\nKruskal-Wallis H检验结果:") kruskal_stat, kruskal_p = stats.kruskal( *[group['education'].values for name, group in df_clean.groupby('age_group')] ) print(f"H统计量 = {kruskal_stat:.4f}") print(f"P = {kruskal_p:.8f}") if kruskal_p < 0.05: print("▶ 结论:不同年龄组的学历分布存在显著差异 (p < 0.05)") else: print("▶ 结论:未发现年龄组间学历分布有显著差异") # 3. 效应量计算(Vargha-Delaney A) def vda_effect_size(group1, group2): """计算有序变量的Vargha-Delaney A效应量""" ranks = pd.concat([group1, group2]).rank() n1, n2 = len(group1), len(group2) R1 = ranks[:n1].mean() A = (R1/n2 - 0.5)/0.5 return np.clip(A, 0, 1) # 确保在[0,1]范围内 print("\n计算中位数差异和效应量...") # 获取有序年龄组 age_order = ['20-29', '30-39', '40-49', '50-59', '60-69', '70-79', '80-91'] group_data = {age: df_clean[df_clean['age_group'] == age]['education'] for age in age_order} # 4. 事后多重比较(Mann-Whitney U检验 + FDR校正) print("\n组间两两比较 (Mann-Whitney U + Benjamini-Hochberg校正):") pairs = [] for i, age1 in enumerate(age_order): for j, age2 in enumerate(age_order): if i < j: group1 = group_data[age1] group2 = group_data[age2] # Mann-Whitney U检验 u_stat, p_val = stats.mannwhitneyu(group1, group2, alternative='two-sided') # 计算效应量 med_diff = group1.median() - group2.median() a_val = vda_effect_size(group1, group2) pairs.append({ 'group1': age1, 'group2': age2, 'med_diff': med_diff, 'u_stat': u_stat, 'p_value': p_val, 'A': a_val }) # 创建结果DataFrame pair_df = pd.DataFrame(pairs) # 使用Benjamini-Hochberg校正p from statsmodels.stats.multitest import multipletests _, pair_df['p_adj'], _, _ = multipletests( pair_df['p_value'], alpha=0.05, method='fdr_bh' ) # 标记是否显著 pair_df['significant'] = pair_df['p_adj'] < 0.05 # 筛选显著对并排序 sig_pairs = pair_df[pair_df['significant']].sort_values('p_adj') print(sig_pairs[['group1', 'group2', 'med_diff', 'p_adj', 'A']]) # 5. 可视化 - 使用箱线图和小提琴图组合 plt.figure(figsize=(14, 8)) # 箱线图 + 小提琴图 sns.violinplot( x='age_group', y='education', data=df_clean, order=age_order, inner=None, palette='muted' ) sns.boxplot( x='age_group', y='education', data=df_clean, order=age_order, width=0.15, boxprops={'alpha': 0.7}, flierprops={'marker': 'o', 'markersize': 4} ) # 添加中位数标签 medians = df_clean.groupby('age_group')['education'].median() for i, m in enumerate(medians[age_order]): plt.text(i, m + 0.1, f"{m:.1f}", ha='center', va='bottom', fontsize=10, weight='bold') # 添加显著差异标记 y_max = df_clean['education'].max() + 0.5 for idx, row in sig_pairs.iterrows(): grp1_idx = age_order.index(row['group1']) grp2_idx = age_order.index(row['group2']) # 绘制连接线 plt.plot([grp1_idx, grp2_idx], [y_max, y_max], color='k', linewidth=1) # 添加星号表示显著程度 stars = "***" if row['p_adj'] < 0.001 else "**" if row['p_adj'] < 0.01 else "*" plt.text( (grp1_idx + grp2_idx) / 2, y_max + 0.05, stars, ha='center', fontsize=12, weight='bold' ) y_max += 0.4 # 增加下一个标记的高度 plt.title('各年龄组教育水平分布及显著差异比较', fontsize=14) plt.xlabel('年龄组', fontsize=12) plt.ylabel('教育水平 (1-4级)', fontsize=12) plt.ylim(0.5, y_max + 0.5) plt.grid(axis='y', linestyle='--', alpha=0.7) plt.tight_layout() # 6. 累积分布函数图 plt.figure(figsize=(12, 6)) for age in age_order: sorted_vals = np.sort(group_data[age]) cdf = np.arange(1, len(sorted_vals)+1) / len(sorted_vals) plt.plot(sorted_vals, cdf, label=age, linewidth=2.5) plt.title('教育水平累积分布 (CDF)', fontsize=14) plt.xlabel('教育水平', fontsize=12) plt.ylabel('累积比例', fontsize=12) plt.xticks([1, 2, 3, 4], ['高中以下', '高中', '大学', '研究生']) plt.grid(axis='both', alpha=0.3) plt.legend(title='年龄组', fontsize=10) plt.tight_layout() # 保存和显示结果 plt.savefig('education_analysis.png', dpi=300, bbox_inches='tight') plt.show() ``` ### 代码解释: 1. **统计检验优化**: - **Kruskal-Wallis H检验**:代替卡方检验,适用于有序分类变量 - **Mann-Whitney U检验**:用于事后两两比较,比Tukey HSD更适合有序数据 - **FDR校正**:使用Benjamini-Hochberg方法控制多重比较错误率 2. **效应量计算**: - **Vargha-Delaney A统计量**:计算各组效应量 - A = 0.5 无差异 - A > 0.56 小效应 - A > 0.64 中等效应 - A > 0.71 大效应 3. **可视化创新**: - **箱线图+小提琴图**组合:同时显示分布形态和中位数 - **中位数标注**:在图表上直接显示每个组的中位数 - **显著差异连接线**:直观显示哪些组间存在显著差异 - **累积分布函数图**:清晰展示各组教育水平的累积差异 4. **分析流程**: 1. 数据准备:处理缺失 2. 描述性统计:列联表和比例表 3. 全局检验:Kruskal-Wallis H检验 4. 事后分析:两两Mann-Whitney检验 5. 效应量计算:Vargha-Delaney A 6. 可视化展示:多角度呈现结果 ### 分析结果解读: 1. **中位数趋势**:年龄越大,教育水平中位数越低 2. **显著差异分布**:年轻组与老年组差异最显著 3. **累积分布**:20-29组的CDF曲线明显偏右,表明更高教育水平比例更大 4. **效应大小**:A显示大多数显著对具有中等至大效应
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值