Pandas value_counts()方法对缺失值计数不一致问题分析
问题:为何两列由np.nan生成的缺失值在value_counts()中表现不同?
1. 示例代码与现象
首先创建示例DataFrame:
import pandas as pd import numpy as np df = pd.DataFrame({'x': [1, 2, 3, 4, 10]}, index = range(5))
生成的DataFrame:
x 0 1 1 2 2 3 3 4 4 10
定义索引列表:
ff_idx = [1, 2] sd_idx= [3, 4]
方式一:分步赋值创建新列
df['ff_sd_indicator'] = np.nan df['ff_sd_indicator'][df.index.isin(ff_idx)] = 'ff_count' df['ff_sd_indicator'][df.index.isin(sd_idx)] = 'sd_count'
方式二:用np.select批量赋值
df['ff_sd_indicator2'] = np.select( [df.index.isin(ff_idx) , df.index.isin(sd_idx)], ['ff_count','sd_count'], default=np.nan )
最终生成的DataFrame:
x ff_sd_indicator ff_sd_indicator2 0 1 NaN nan 1 2 ff_count ff_count 2 3 ff_count ff_count 3 4 sd_count sd_count 4 10 sd_count sd_count
value_counts()的差异
df['ff_sd_indicator'].value_counts()输出(未统计缺失值):
ff_sd_indicator ff_count 2 sd_count 2
df['ff_sd_indicator2'].value_counts()输出(包含缺失值):
ff_sd_indicator2 ff_count 2 sd_count 2 nan 1
补充df.info()输出:
RangeIndex: 5 entries, 0 to 4 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 x 5 non-null int64 1 ff_sd_indicator 5 non-null object 2 ff_sd_indicator2 5 non-null object
2. 原因分析
核心差异源于两列中np.nan的存储类型不同,导致pandas的处理逻辑不同:
对于ff_sd_indicator列
- 初始赋值
df['ff_sd_indicator'] = np.nan时,列的 dtype 为float64,此时的np.nan是Python标准float类型。 - 后续通过链式赋值将部分元素改为字符串,触发列 dtype 转为
object,但原有的np.nan仍保留为float类型。 - 在
object列中,value_counts()默认(dropna=True)会将float类型的np.nan识别为缺失值,因此会排除它。
对于ff_sd_indicator2列
np.select()生成的数组是objectdtype,其中的np.nan是numpy.float64类型的标量。- 对于
object列中的numpy标量类型np.nan,value_counts()默认不会将其视为缺失值(即使pd.isna()返回True),因此会当作普通元素统计。
另外,df.info()显示两列均为5个非空值,是因为对于object dtype的列,pandas仅将None和pd.NA标记为缺失值,np.nan(无论类型)都会被视为有效的object元素,不会计入缺失统计。
3. 验证与建议
验证缺失值统计
如果给ff_sd_indicator列加上dropna=False参数,就能看到缺失值的统计:
df['ff_sd_indicator'].value_counts(dropna=False)
输出:
ff_count 2 sd_count 2 NaN 1 Name: ff_sd_indicator, dtype: int64
统一缺失值处理的建议
建议使用pd.NA标记缺失值,同时避免链式赋值(改用loc防止警告):
df['ff_sd_indicator'] = pd.NA df.loc[df.index.isin(ff_idx), 'ff_sd_indicator'] = 'ff_count' df.loc[df.index.isin(sd_idx), 'ff_sd_indicator'] = 'sd_count'
内容的提问来源于stack exchange,提问作者Saeed
相关产品推荐
相关产品推荐

