我们有一个包含三个不同列的数据框,如上例(df)所示。此任务的目标是每次第1列中的字母更改时,用np.nan替换第2列的第一个元素。由于研究中的数据库非常大,因此不能用于循环。此外,每个涉及班次的解决方案都被排除在外,因为它太慢了。
我相信最简单的方法是使用groupby和head方法,但是我不知道如何替换原始数据帧。
例子:
df = pd.DataFrame([['A','Z',1.11],['B','Z',2.1],['C','Z',3.1],['D', 'X', 2.1], ['E','X',4.3],['E', 'X', 2.1], ['F','X',4.3]])
要选择我们想要更改的元素,我们可以执行以下操作:
df.groupby(by=1).head(1)[2] = np.nan
但是在原始数据帧中没有任何变化。 目标是获得以下内容:
根据评论,我们不会让df[1]
回到已经看过的小组,例如['Z', 'Z', 'X', 'Z']
是不可能的。
mask
and shift
df[2] = df[2].mask(df[1].ne(df[1].shift(1)))
masked_array
:df[2] = np.ma.masked_array(df[2], df[1].ne(df[1].shift(1))).filled(np.nan)
# array([nan, 2.1, 3.1, nan, 4.3, 2.1, 4.3])
np.roll
and loc
:a = df[1].values
df.loc[np.roll(a, 1)!=a, 2] = np.nan
0 1 2
0 A Z NaN
1 B Z 2.1
2 C Z 3.1
3 D X NaN
4 E X 4.3
5 E X 2.1
6 F X 4.3
运用
df[2].mask(df.groupby(1).cumcount().eq(0))
Out[41]:
0 NaN
1 2.1
2 3.1
3 NaN
4 4.3
5 2.1
6 4.3
Name: 2, dtype: float64
#df[2] = df[2].mask(df.groupby(1).cumcount().eq(0))
您可以使用numpy.where
进行矢量化条件赋值。这假设df[1]
已经排序。
df[2] = np.where(df[1].duplicated(), df[2], np.nan)
如果不能假设排序:
df[2] = np.where(df[1] != df[1].shift(), np.nan, df[2])
结果:
0 1 2
0 A Z NaN
1 B Z 2.1
2 C Z 3.1
3 D X NaN
4 E X 4.3
5 E X 2.1
6 F X 4.3
可以使用pd.DataFrame.mask
应用等效逻辑。
a = df[1].values
b = np.flatnonzero(np.append(True, a[1:] != a[:-1]))
df[2].values[b] = np.nan
df
0 1 2
0 A Z NaN
1 B Z 2.1
2 C Z 3.1
3 D X NaN
4 E X 4.3
5 E X 2.1
6 F X 4.3
您可以从您的groupby获取索引并将其用作.loc
的掩码。
import pandas as pd
import numpy as np
df = pd.DataFrame([
['A','Z',1.11],
['B','Z',2.1],
['C','Z',3.1],
['D', 'X', 2.1],
['E','X',4.3],
['E', 'X', 2.1],
['F','X',4.3]
])
m = df.groupby(by=1).head(1).index
df.loc[m,2] = np.nan
print(df)
或者您可以使用duplicated()代替。这应该更快。
m = ~df[1].duplicated()
df.loc[m, 2] = np.nan
收益:
0 1 2
0 A Z NaN
1 B Z 2.1
2 C Z 3.1
3 D X NaN
4 E X 4.3
5 E X 2.1
6 F X 4.3