Применить функцию для нескольких фреймов данных и столбцов - PullRequest
0 голосов
/ 10 октября 2019

Здравствуйте, я работаю с двумя фреймами данных, и мне нужно применить пользовательскую функцию, но я получаю следующую ошибку: ValueError: ('The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().', 'occurred at index 0'). Я знаю , почему это происходит, но не знаю, как решить проблему.

Первый кадр данных содержит список всех рабочих дней текущего года:

print(df_workable)
          Date  workable_day  inv_workable_day  day  month
1   2019-01-02           1.0              22.0    2      1
2   2019-01-03           2.0              21.0    3      1
3   2019-01-04           3.0              20.0    4      1
6   2019-01-07           4.0              19.0    7      1
7   2019-01-08           5.0              18.0    8      1
..         ...           ...               ...  ...    ...
364 2019-12-31          20.0               1.0   31     12

Второй кадр данных содержит данные о значениях некоторых дней и флаг.

print(df)
       day_a1     wday_a1     iwday_a1       flag
0        24.0         4.0          6.0        2.1
1         NaN         NaN          NaN        NaN
3        31.0        22.0          1.0        2.2
4        27.0        18.0          5.0  3.3.2.1.3
26816    25.0        19.0          5.0          1
26817    31.0         NaN          NaN        3.2

Я пытаюсь применить функцию, которая будет возвращать дату из любого фрейма данных в зависимости от нескольких условий (но я просто использую «this» и «that» для простоты). Это функция:

def rec_date(row):
    if row['flag'] == '2.1':
        if df_workable[df_workable['workable_day'] == int(row['wday_a1']) & df_workable['month'] == 1]['day'] <= dt.datetime.today().day:
            val = "this"
        else:
            val = "that"
    else:
        val = "Still missing"
    return val

Проблема заключается в том, что я пытаюсь решить условие 2.1, которое мне нужно для перебора каждой строки df и проверки условия. Проблема возникает, потому что, когда он пытается перебрать каждую строку, он не знает, какую строку в df_workable перебирать, поэтому ему нужен дополнительный аргумент (.all (),. Any (),и т.д...). Однако я не хочу повторять, а просто извлекать значение, соответствующее:

df_workable[df_workable['workable_day'] == 4 & df_workable['month'] == 1]['day']

(я передаю 4 в жестком коде, потому что это будет первое значение, переданное из df ['wday_a1']). И вывод для этого должен быть 7. И это значение по сравнению с dt.datetime.today().day, равным 10, вернет true. Я протестировал обе функции по отдельности, и они возвращают ожидаемый результат. Однако проблема возникает, когда applying эти функции работают над кадром данных из-за (я полагаю) причин, объясненных выше. После прохождения функции я ожидаю получить это:

df['rec_date'] = df.apply(rec_date,axis=1)
           day_a1     wday_a1     iwday_a1       flag         rec_date
    0        24.0         4.0          6.0        2.1             this
    1         NaN         NaN          NaN        NaN    Still missing
    3        31.0        22.0          1.0        2.2    Still missing
    4        27.0        18.0          5.0  3.3.2.1.3    Still missing
    26816    25.0        19.0          5.0          1    Still missing
    26817    31.0         NaN          NaN        3.2    Still missing

Ответы [ 2 ]

1 голос
/ 10 октября 2019

У вашего кода есть две небольшие проблемы:

  1. Вы хотите объединить два условия с &, но вам следует заключить каждое из этих условий в скобки, чтобы четко разделить их: (x==...) & (y=...)
  2. Результат этой проверки имеет форму Серии (с одним наблюдением). Python не уверен, как преобразовать эту серию логических значений в одну логическую переменную, потому что в случае, если ряд имеет несколько значений, он не знает, как их агрегировать (должен ли ряд приводить только к одному True, если все значения равны True или достаточноесли хотя бы один из них истинен, ...). Поэтому вы должны уточнить это, добавив series.all() или series.any() к вашему чеку.
def rec_date(row):
    if row['flag'] == '2.1':
        if (df_workable[(df_workable['workable_day'] == int(row['wday_a1'])) & (df_workable['month'] == 1)]['day'] <= dt.datetime.today().day).all():
            val = "this"
        else:
            val = "that"
    else:
        val = "Still missing"
    return val

Вывод:

       day_a1  wday_a1  iwday_a1       flag       rec_date
0        24.0      4.0       6.0        2.1           this
1         NaN      NaN       NaN        NaN  Still missing
3        31.0     22.0       1.0        2.2  Still missing
4        27.0     18.0       5.0  3.3.2.1.3  Still missing
26816    25.0     19.0       5.0          1  Still missing
26817    31.0      NaN       NaN        3.2  Still missing
0 голосов
/ 10 октября 2019

Итак, давайте разберем это утверждение:

df_workable[df_workable['workable_day'] == 4 & df_workable['month'] == 1]['day']

  1. df_workable: полный DataFrame
  2. df_workable[df_workable['workable_day'] == int(row['wday_a1']) & df_workable['month'] == 1]: вы фильтруетеDataFrame основан на определенных значениях для workable_day и month. Это возвращает новый DataFrame с отфильтрованными результатами целом DataFrame.
  3. df_workable[df_workable['workable_day'] == int(row['wday_a1']) & df_workable['month'] == 1]['day']: это берет DataFrame, возвращенный на шаге 2, и обращается к его столбцу ['day']. Это возвращает объект pandas.Series, который содержит все значения для столбца day DataFrame.

Что означает, что при выполнении df_workable[df_workable['workable_day'] == int(row['wday_a1']) & df_workable['month'] == 1]['day'] <= dt.datetime.today().day вы пытаетесь сравнитьцелый объект Series (который содержит несколько значений, соответствующих каждой строке) с одним значением даты и времени, NOT итерация по строкам.

Я не получаю сравнение, которое вы пытаетесьделайте, но это не представляется возможным, следуя вашей текущей логике.

...