Solution #1:
Use mask with replace and astype(float):
df['col2'] = df['col2'].mask(df['col2'] == 'SP', 1 - df['col1'].replace('SP', 0).astype(float) - df['col3'].replace('SP', 0).astype(float))
df['col3'] = df['col3'].mask(df['col3'] == 'SP', 1 - df['col1'].replace('SP', 0).astype(float) - df['col2'].replace('SP', 0).astype(float))
If column 1 never has strings, you can simplify with:
df['col2'] = df['col2'].mask(df['col2'] == 'SP', 1 - df['col1'] - df['col3'].replace('SP', 0).astype(float))
df['col3'] = df['col3'].mask(df['col3'] == 'SP', 1 - df['col1'] - df['col2'].replace('SP', 0).astype(float))
Out[1]:
col1 col2 col3
0 0.98 0.01 0.01
1 1.00 0 0
2 0.89 0.01 0.1
3 0.97 0.01 0.02
4 0.96 0 0.04
Solution #2:
Alternatively, use mask with pd.to_numeric() since you have strings:
df['col2'] = df['col2'].mask(df['col2'] == 'SP', 1 - pd.to_numeric(df['col1'], errors='coerce') - pd.to_numeric(df['col3'], errors='coerce'))
df['col3'] = df['col3'].mask(df['col3'] == 'SP', 1 - pd.to_numeric(df['col1'], errors='coerce') - pd.to_numeric(df['col2'], errors='coerce'))
df
If column 1 never has strings, you can simplify with:
df['col2'] = df['col2'].mask(df['col2'] == 'SP', 1 - df['col1'] - pd.to_numeric(df['col3'], errors='coerce'))
df['col3'] = df['col3'].mask(df['col3'] == 'SP', 1 - df['col1'] - pd.to_numeric(df['col2'], errors='coerce'))
df
Out[2]:
col1 col2 col3
0 0.98 0.01 0.01
1 1.00 0 0
2 0.89 0.01 0.1
3 0.97 0.01 0.02
4 0.96 0 0.04