Python 如何用不同于Pandas数据帧中的孤立NaN的值替换重复NaN
我在一个数据帧中安排了几个时间序列,如下所示:Python 如何用不同于Pandas数据帧中的孤立NaN的值替换重复NaN,python,pandas,dataframe,nan,repeat,Python,Pandas,Dataframe,Nan,Repeat,我在一个数据帧中安排了几个时间序列,如下所示: category value time_idx 0 810 0.118794 0 1 830 0.552947 0 2 1120 0.133193 0 3 1370 0.840183 0 4 810 0.129385 1 ... ... ... ... 6095 1370 0.157391 1523 6096 810 0.141377
category value time_idx
0 810 0.118794 0
1 830 0.552947 0
2 1120 0.133193 0
3 1370 0.840183 0
4 810 0.129385 1
... ... ... ...
6095 1370 0.157391 1523
6096 810 0.141377 1524
6097 830 0.212254 1524
6098 1120 0.069970 1524
6099 1370 0.134947 1524
有些值是NaN。我想用0替换任何没有重复的NaN值,因为我假设当时该类别的值为0。但是,任何时候,如果每个类别在同一时间有一个值NaN(即,在同一时间_idx),那么我想用-1替换每个值
在熊猫身上,仅仅用一个值来替换NaN当然是微不足道的,但在给定时间专门替换每个类别的NaN所增加的复杂性让我感到困惑。我知道我可以循环使用时间索引,但我的实际数据集将有900多个类别,因此我想找到一种更有效的方法
我能想到的唯一一件事就是列表理解,我认为它甚至不一定比显式循环更有效,而且我也不能想出一个工作正常的循环
我知道我可以这样替换所有的NAN:
data[“value”]=data[“value”].替换(np.nan,0)
但我不确定如何在我的例子中实现这一点,我只想用0替换长NaN。这是我目前的循环:
num_channels = data["category"].nunique()
nan_vals = data[lambda x: np.isnan(x.value)]
nan_times = nan_vals["time_idx"]
for time in nan_times:
if nan_vals[lambda x: x.time_idx == time]["category"].nunique() < num_channels:
# Set 0 for every channel that has nan at time t
index = nan_vals[lambda x: x.time_idx == time].index
data.loc[index, ["value"]] = data.loc[index, "value"].replace(np.nan, 0)
else:
index = nan_vals[lambda x: x.time_idx == time].index
data.loc[index, ["value"]] = data[lambda x: x.time_idx == time]["value"].replace(np.nan, -1)
我希望此输出:
category value time_idx
0 810 -1.000000 0
1 830 -1.000000 0
2 1120 -1.000000 0
3 1370 -1.000000 0
4 810 0.129385 1
5 830 0.000000 1
6 1120 0.144378 1
7 1370 0.000000 1
8 810 0.124334 2
9 830 0.487274 2
10 1120 0.119153 2
11 1370 0.871687 2
在本例中,在time=0时,每个类别的值都是NaN,因此它们将替换为-1。在time=1时,存在非NaN值,因此存在的任何NaN值(类别830和1370)都将替换为0。您可以使用
groupby
找到那些time\u idx
,其中所有条目都是NaN,然后使用group.isna().all()
。您可以使用该遮罩用-1
填充NAN
然后使用fillna
将0
填充到所有其他NAN中
all_nas = df.groupby("time_idx").value.apply(lambda group: group.isna().all())
df = df.set_index("time_idx")
df.loc[all_nas, "value"] = -1
df = df.reset_index().fillna(0)
print(df)
# time_idx category value
# 0 0 810 -1.000000
# 1 0 830 -1.000000
# 2 0 1120 -1.000000
# 3 0 1370 -1.000000
# 4 1 810 0.129385
# 5 1 830 0.000000
# 6 1 1120 0.144378
# 7 1 1370 0.000000
# 8 2 810 0.124334
# 9 2 830 0.487274
# 10 2 1120 0.119153
# 11 2 1370 0.871687
您可以按
time\u idx
分组,并在组上迭代。
然后在每组中,计算value
列中NaN
值的数量。
根据NAN的数量,可以更新值
列
import pandas as pd
df = pd.DataFrame(
{
'category': [810, 830, 1120, 810, 830, 1120, 810, 830, 1120],
'value': [None, None, None, 1, 2, None, None, None, 4],
'time_idx': [0, 0, 0, 1, 1, 1, 2, 2, 2],
}
)
print(df, end='\n\n')
for name, group in df.copy().groupby('time_idx'):
num_nans = group['value'].isnull().sum()
mask = (df['time_idx'] == name) & df['value'].isna()
if num_nans == len(group):
df.loc[mask, 'value'] = -1
else:
df.loc[mask, 'value'] = 0
print(df)
输出
category value time_idx
0 810 NaN 0
1 830 NaN 0
2 1120 NaN 0
3 810 1.0 1
4 830 2.0 1
5 1120 NaN 1
6 810 NaN 2
7 830 NaN 2
8 1120 4.0 2
category value time_idx
0 810 -1.0 0
1 830 -1.0 0
2 1120 -1.0 0
3 810 1.0 1
4 830 2.0 1
5 1120 0.0 1
6 810 0.0 2
7 830 0.0 2
8 1120 4.0 2
嗨,Ryan,你试过我们可以调查的东西吗?嗨,Anwarvic,谢谢你的回答。我能够通过每次循环成功地实现它,但正如我所提到的,我想更有效地实现它。我将在我的问题后面附上我的想法的更多细节。@RyanDempsey您能展示输入数据帧的示例和预期的输出吗?
category value time_idx
0 810 NaN 0
1 830 NaN 0
2 1120 NaN 0
3 810 1.0 1
4 830 2.0 1
5 1120 NaN 1
6 810 NaN 2
7 830 NaN 2
8 1120 4.0 2
category value time_idx
0 810 -1.0 0
1 830 -1.0 0
2 1120 -1.0 0
3 810 1.0 1
4 830 2.0 1
5 1120 0.0 1
6 810 0.0 2
7 830 0.0 2
8 1120 4.0 2