Вы можете создать пользовательскую функцию для возврата пропущенных значений, если индексация не удалась:
def f(a, b):
try:
return a[int(b):]
except:
return np.nan
df['colC'] = [f(a,b) for a, b in zip(df['colA'], df['colB'])]
Или:
df['colC'] = df.apply(lambda x: f(x['colA'], x['colB']), axis=1)
print (df)
colA colB colC
0 abcde 4.0 e
1 abcde 2.0 cde
2 abcde 1.0 bcde
3 NaN NaN NaN
4 wxyz 3.0 z
5 wxyz 2.0 yz
Еще одна идея с тестом на отсутствие пропущенных значений:
df['colC'] = [a[int(b):] if pd.notna(a) and pd.notna(b)
else np.nan
for a, b in zip(df['colA'], df['colB'])]
print (df)
colA colB colC
0 abcde 4.0 e
1 abcde 2.0 cde
2 abcde 1.0 bcde
3 NaN NaN NaN
4 wxyz 3.0 z
5 wxyz 2.0 yz