我有一个数据集,我想按("CustomerID")分组,并使用组内最接近的数字填充nan。
df['num'] = df['num'].interpolate(method="nearest")
df['num'] = df.groupby('CustomerID')['num'].transform(lambda x: x.interpolate(method="nearest"))
我得到ValueError: x和y数组必须至少有2个条目,我认为这是因为有些客户只有一个带有NaN或只有NaN的条目。但是,当我提取了应该工作的几行并创建了一个新的数据框架时,什么也没有发生。
是否有一种方法可以按customerID分组,并在组内填充具有最接近数字的nan,并跳过只有nan或只有一个观察值的客户?
我遇到了相同的"ValueError: x和y数组必须至少有2个条目"在我的代码里。根据你的代码改编(显然我无法复制),我是这样解决这个问题的:
import pandas as pd
import numpy as np
df.loc[:,'num'] = df.groupby('CustomerID')['num'].apply(lambda group: group.interpolate(method='nearest') if np.count_nonzero(np.isnan(group)) < (len(group) - 1) else group)
df.loc[:,'num'] = df.groupby('CustomerID').apply(lambda group: group.interpolate(method='linear', limit_area='outside', limit_direction='both'))
执行以下操作:
- 第一个"groupby + apply"只有当组中至少有两个非nan值时,才用'nearest'方法插入每个组。
np.isnan(group)
返回一个包含True的数组,如果组中有nan,则返回False。
np.count_nonzero(np.isnan(group))
返回前一个数组中True的个数(即该组中nan的个数)。
如果nan的数量严格小于该组的长度减1(即该组中至少有两个非nan),则使用"最近邻"插值该组,否则不动。
- 第二个"groupby + apply"完成插值每组,使用方法='linear'和参数limit_direction='both'。
- 如果一个组在前一步中被完全插入:没有发生。
- 如果一个组只有一个非NaN值(因此被留下)在前一步中未动):非NaN值将用于
- 如果一个组只有nan(因此在前一步中保持不变):该组仍然充满nan。
下面是一个使用您的符号的虚拟示例:
df=pd.DataFrame({'CustomerID':['a']*3+['b']*3+['c']*3,'num':[1,np.nan,2,np.nan,1,np.nan,np.nan,np.nan,np.nan]})
df
CustomerID num
0 a 1.0
1 a NaN
2 a 2.0
3 b NaN
4 b 1.0
5 b NaN
6 c NaN
7 c NaN
8 c NaN
df.loc[:,'num'] = df.groupby('CustomerID')['num'].apply(lambda group: group.interpolate(method='nearest') if np.count_nonzero(np.isnan(group)) < (len(group) - 1) else group)
df
CustomerID num
0 a 1.0
1 a 1.0
2 a 2.0
3 b NaN
4 b 1.0
5 b NaN
6 c NaN
7 c NaN
8 c NaN
df.loc[:,'num'] = df.groupby('CustomerID').apply(lambda group: group.interpolate(method='linear', limit_area='outside', limit_direction='both'))
df
CustomerID num
0 a 1.0
1 a 1.0
2 a 2.0
3 b 1.0
4 b 1.0
5 b 1.0
6 c NaN
7 c NaN
8 c NaN
编辑:重要提示
插值方法'nearest'使用索引的数值(参见文档https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.interpolate.html)。它在上面的虚拟示例中工作得很好,因为索引是干净的。如果你的数据帧的索引是混乱的(例如,在连接数据帧之后),你可能需要在插入之前执行df.reset_index(inplace=True)
。