如何用来自 Pandas 数据框的单独 NaN 的不同值替换重复的 NaN
How to replace repeated NaNs with a different value from lone NaNs from Pandas data frame
我在一个数据框中排列了几个时间序列,类似于下面:
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 值(即同时 time_idx),那么我想用 -1 替换每个值。
用一个值替换 NaN 在 Pandas 中当然是微不足道的,但是在给定时间专门替换每个类别的 NaN 的 NaN 的额外复杂性让我感到难过。我知道我可以循环遍历时间索引,但我的实际数据集将有 900 多个类别,所以我想找到一种更有效的 Pandas-esque 方法。
我唯一能想到的就是列表理解,我认为它不一定比显式循环更有效,而且我想不出一个可以正常工作的方法。
我知道我可以像这样替换所有 NaN:
data["value"] = data["value"].replace(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 NaN 0
1 830 NaN 0
2 1120 NaN 0
3 1370 NaN 0
4 810 0.129385 1
5 830 NaN 1
6 1120 0.144378 1
7 1370 NaN 1
8 810 0.124334 2
9 830 0.487274 2
10 1120 0.119153 2
11 1370 0.871687 2
我想要这个输出:
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
在此示例中,在时间 = 0 时每个类别的值为 NaN,因此它们将被替换为 -1。在时间 = 1 时,存在非 NaN 值,因此存在的任何 NaN 值(类别 830 和 1370)都将替换为 0。
您可以使用 groupby
然后 group.isna().all()
找到所有条目均为 NaN 的那些 time_idx
。您可以使用该掩码用 -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_idx
分组并遍历组。
然后在每个组中计算 value
列中 NaN
值的数量。
根据 nans 的数量,可以更新 value
列。
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
我在一个数据框中排列了几个时间序列,类似于下面:
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 值(即同时 time_idx),那么我想用 -1 替换每个值。
用一个值替换 NaN 在 Pandas 中当然是微不足道的,但是在给定时间专门替换每个类别的 NaN 的 NaN 的额外复杂性让我感到难过。我知道我可以循环遍历时间索引,但我的实际数据集将有 900 多个类别,所以我想找到一种更有效的 Pandas-esque 方法。
我唯一能想到的就是列表理解,我认为它不一定比显式循环更有效,而且我想不出一个可以正常工作的方法。
我知道我可以像这样替换所有 NaN:
data["value"] = data["value"].replace(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 NaN 0
1 830 NaN 0
2 1120 NaN 0
3 1370 NaN 0
4 810 0.129385 1
5 830 NaN 1
6 1120 0.144378 1
7 1370 NaN 1
8 810 0.124334 2
9 830 0.487274 2
10 1120 0.119153 2
11 1370 0.871687 2
我想要这个输出:
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
在此示例中,在时间 = 0 时每个类别的值为 NaN,因此它们将被替换为 -1。在时间 = 1 时,存在非 NaN 值,因此存在的任何 NaN 值(类别 830 和 1370)都将替换为 0。
您可以使用 groupby
然后 group.isna().all()
找到所有条目均为 NaN 的那些 time_idx
。您可以使用该掩码用 -1
.
然后使用 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_idx
分组并遍历组。
然后在每个组中计算 value
列中 NaN
值的数量。
根据 nans 的数量,可以更新 value
列。
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