Как итеративно задать nan в столбце на основе другого значения столбца?

#python #pandas #numpy

Вопрос:

Представьте, что у вас есть следующий df:

 d = {'taxrate#1': [1, 2], 'taxrate#2': [3, np.nan],'line amount#1': [10, 20], 'line amount #2': [50, 12]}
df = pd.DataFrame(data=d)
df

    taxrate#1   taxrate#2   line amount#1   line amount #2
0   1             3.0           10            50.0
1   2             NaN           20            12
 

Теперь я хотел бы установить значение суммы строки № 2 равным nan, если ставка налога № 2 равна nan. Я хотел бы сделать это итеративно/динамически, потому что суммы строк/ ставки налогов могут достигать 10.

Таким образом, идеальным результатом было бы:

     taxrate#1   taxrate#2   line amount#1   line amount #2
0   1             3.0           10            50.0
1   2             NaN           20            NaN
 

Как достичь вышеперечисленного?

Пожалуйста, помогите!

Ответ №1:

Использование Series.isna() и цикл

 d = {'taxrate#1': [np.nan, 2], 'taxrate#2': [3, np.nan],
     'line amount#1': [10, 20], 'line amount#2': [50, 12]}
df = pd.DataFrame(data=d)

for taxrate_col in {x for x in df.columns if x.startswith("taxrate")}:
    col_id = taxrate_col.split("#")[1]
    df.loc[df[taxrate_col].isna(), f'line amount#{col_id}'] = np.nan
 

Которые делают

    taxrate#1  taxrate#2  line amount#1  line amount#2
0        NaN        3.0             10             50
1        2.0        NaN             20             12
 

Становится

    taxrate#1  taxrate#2  line amount#1  line amount#2
0        NaN        3.0            NaN           50.0
1        2.0        NaN           20.0            NaN
 

Комментарии:

1. Спасибо за ваш комментарий, однако я хотел бы сделать это динамически, потому что ставки налогов / суммы строк могут занимать до 10 строк

2. @Max вы имеете в виду несколько столбцов, а не несколько строк ? То есть вы имеете в виду lineamount1 на основе таксона1, lineamount2 на основе таксона2, … ?

3. Да, извините, несколько столбцов! Точно!

4. @Max, если вы можете добавить аналогичные примеры данных в вопрос, которые помогут вам быстро получить правильный ответ.

Ответ №2:

Вы можете использовать pandas.wide_to_long :

 >>> d = {
         'taxrate#1': [1, 2], 'taxrate#2': [3, np.nan],
         'line amount#1': [10, 20], 'line amount#2': [50, 12]
    }
>>> df = pd.DataFrame(data=d)
>>> longdf = pd.wide_to_long(
        df.reset_index(), 
        stubnames=['taxrate', 'line amount'], 
        i='index', sep='#', j='number'
    )
>>> longdf
              taxrate  line amount
index number                      
0     1           1.0           10
1     1           2.0           20
0     2           3.0           50
1     2           NaN           12

>>> longdf.loc[longdf['taxrate'].isna(), 'line amount'] = np.nan
>>> widedf = longdf.reset_index().pivot(index=['index'], columns=['number'])
>>> widedf.columns = [f'{stub}#{num}' for stub, num in widedf.columns]

>>> widedf
       taxrate#1  taxrate#2  line amount#1  line amount#2
index                                                    
0            1.0        3.0           10.0           50.0
1            2.0        NaN           20.0            NaN
 

Комментарии:

1. Кажется, я не могу перезаписать существующий df, знаете почему?

2. @Макс, что ты имеешь в виду? df = widedf не работает?

3. Поэтому я хочу перезаписать существующий df с большим количеством значений, но с теми же именами столбцов: dftaxitems.update(widedf, перезапись = True). Однако он не обновляет значения..

4. @Max да, правильно, вы не можете обновлять существующие значения, отличные от na, значениями na с помощью df.update

5. Спасибо тебе, Цитторак!