[Pandas] Способ присвоения нового столбца на основе оператора if

#python #pandas #dataframe

#python #pandas #фрейм данных

Вопрос:

Я знаю, что assign может помочь создать / изменить один столбец на основе лямбда-функции следующим образом:

 df.assign(c = lambda x: x.sum())
  

Но я не смог найти способ сделать это с помощью if-statement, если я хочу сделать оператор встроенным, а не выполнять его отдельно вне операции.

Возможно ли реализовать это, не делая ничего другого за пределами операции:

 df.assign(c = lambda x: x.num_col.sum() if x.num_col > 0)
  

Приведенная выше команда возвращает «SyntaxError: недопустимый синтаксис»

Ответ №1:

IIUC вы можете сделать это таким образом:

Данные:

 In [6]: df = pd.DataFrame(np.random.randn(10,2),columns=list('ab'))

In [7]: df
Out[7]:
          a         b
0  0.493970  1.095644
1  0.128510 -0.542144
2  0.136247 -0.544499
3 -0.540835 -0.100574
4  0.052725 -0.164856
5 -1.201619  1.578153
6  1.921872  0.505875
7 -2.519725  0.282050
8 -1.581868 -0.240352
9 -0.071207 -1.366953

In [8]: df.iloc[:6]
Out[8]:
          a         b
0  0.493970  1.095644
1  0.128510 -0.542144
2  0.136247 -0.544499
3 -0.540835 -0.100574
4  0.052725 -0.164856
5 -1.201619  1.578153
6  1.921872  0.505875
  

давайте найдем сумму положительных значений в a столбце для индексов: [0:6] :

 In [9]: df.iloc[:6].query('a > 0').a.sum()
Out[9]: 2.733322288547374
  

Решение:

 In [10]: df.iloc[:6].assign(c=lambda x: x.query('a > 0').a.sum())
Out[10]:
          a         b         c
0  0.493970  1.095644  2.733322
1  0.128510 -0.542144  2.733322
2  0.136247 -0.544499  2.733322
3 -0.540835 -0.100574  2.733322
4  0.052725 -0.164856  2.733322
5 -1.201619  1.578153  2.733322
6  1.921872  0.505875  2.733322
  

то же самое с переименованными столбцами:

 In [11]: df.iloc[:6].rename(columns={'a':'AAA', 'b':'BBB'}).assign(c=lambda x: x.query('AAA > 0').AAA.sum())
Out[11]:
        AAA       BBB         c
0  0.493970  1.095644  2.733322
1  0.128510 -0.542144  2.733322
2  0.136247 -0.544499  2.733322
3 -0.540835 -0.100574  2.733322
4  0.052725 -0.164856  2.733322
5 -1.201619  1.578153  2.733322
6  1.921872  0.505875  2.733322
  

ОБНОВЛЕНИЕ: начиная с Pandas 0.20.1, индексатор .ix устарел в пользу более строгого .индексаторы iloc и .loc.

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

1. Спасибо, но df уже будет задействован в ряде операций, и для этого придется все еще разделять операцию.

2. @JingtaoYun, я не понял — что ты имеешь в виду? Вам нужен новый виртуальный столбец (с использованием assign метода) или постоянный ?

3. виртуальный, потому что я хочу выполнить множество операций за df, прежде чем выполнять assign, таких как df.ix[].rename()…assign() .. Таким образом, df не является исходным df для применения функции назначения.

4. Это отлично работает. Извините, что не сделал это более понятным в начале. Спасибо @MaxU

Ответ №2:

Синтаксис недопустим, потому что вы используете троичное условие, но только первую половину.

Троичное условие позволяет вам написать if оператор, подобный этому:

 a = 1 if b > 0 else 0
  

В вашем случае вы могли бы написать что-то вроде:

 df = (
  df
  .assign(c = lambda x: x.num_col.sum() if x.num_col > 0 else 0)
)
  

Обратите внимание на добавление else 0 в конце.

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

1. Вы пытались запустить этот код? Я не думаю, что это действительно сработает.

2. Спасибо Майклу за то, что поделился этим знанием. Но это не работает с ошибкой: ValueError: значение истинности ряда неоднозначно. Используйте .empty , .bool(),.item(),.any() или.all() .