python-3.x 替换PandasDataFrame每行中第一个出现的值

tyu7yeag  于 2023-03-09  发布在  Python
关注(0)|答案(4)|浏览(148)

我有一个这样的DataFrame:
| 列1|列2|第3栏|第4栏|
| - ------|- ------|- ------|- ------|
| 五个|七|十二|九|
| 无|九|九|1个|
| 九|九|1个|1个|
| 十个|五个|第二章|九|
| 九|三个|无|十八|
每一行至少有一个9,对于每一行,我想用90替换它的第一个示例。
目前,我正在:

out = df.mask(df.eq(9) & df.apply(lambda x: ~x.duplicated(), axis=1), 90)

还有比这更好/更快的方法吗?
预期产出:

col1  col2  col3  col4
0     5     7    12    90
1     0    90     9     1
2    90     9     1     1
3    10     5     2    90
4    90     3     0    18

施工单位:

data = {'col1': [5, 0, 9, 10, 9],
        'col2': [7, 9, 9, 5, 3],
        'col3': [12, 9, 1, 2, 0],
        'col4': [9, 1, 1, 9, 18]}
df = pd.DataFrame(data)
kx5bkwkv

kx5bkwkv1#

您可以使用numpy assign进行检查

df.values[df.index, np.argmax(df.values==9,1)] = 90 
df
Out[56]: 
   col1  col2  col3  col4
0     5     7    12    90
1     0    90     9     1
2    90     9     1     1
3    10     5     2    90
4    90     3     0    18
des4xlb0

des4xlb02#

使用idxmax的一种方法:

s = df.eq(9).idxmax(axis=1)
s = s.apply(df.columns.get_loc)
df.values[s.index, s.values] = 90

输出:

col1  col2  col3  col4
0     5     7    12    90
1     0    90     9     1
2    90     9     1     1
3    10     5     2    90
4    90     3     0    18

这比原始代码快了大约2.5倍:

%timeit df.mask(df.eq(9) & df.apply(lambda x: ~x.duplicated(), axis=1), 90)
# 2.59 ms ± 80.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%%timeit    
s = df.eq(9).idxmax(axis=1)
s = s.apply(df.columns.get_loc)
df.copy().values[s.index, s.values] = 90 # Note the copy is to keep the df same over the `timeit`

# 1.07 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
dohp0rv5

dohp0rv53#

您可以使用eq + cummax + ^

x = df.eq(9).cummax(axis=1)
df[x ^ x.shift(axis=1)] = 90

# One-liner:
df[df.eq(9).cummax(axis=1).pipe(lambda x: x ^ x.shift(axis=1))] = 90

输出:

>>> df
   col1  col2  col3  col4
0     5     7    12    90
1     0    90     9     1
2    90     9     1     1
3    10     5     2    90
4    90     3     0    18
nhaq1z21

nhaq1z214#

下面是另一种方法:

df.mask(df.eq(9)).T.fillna(90,limit=1).T.fillna(9)

更新:
下面是使用rank()的方法

df.mask(df.eq(9).rank(axis=1,method='first',ascending=False).eq(1),90)

这里有一种使用idxmax()的方法

s = df.set_axis(range(df.shape[1]),axis=1).eq(9).idxmax(axis=1)
df.to_numpy()[range(df.shape[0]),s] = 90

df.mask(df.eq(9).cumsum(axis=1).eq(1) & df.eq(9),90)

输出:

col1  col2  col3  col4
0   5.0   7.0  12.0  90.0
1   0.0  90.0   9.0   1.0
2  90.0   9.0   1.0   1.0
3  10.0   5.0   2.0  90.0
4  90.0   3.0   0.0  18.0

相关问题