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

В двух словах, я пытаюсь применить свою функцию для выбора строки. У меня это работает путем подмножества dataframe, запустить функцию, а затем объединить подмножество обратно в основной dataframe. Однако, это громоздко, и должно быть более эффективное решение, которое ускользает от меня. Я нашел несколько полезных постов ( здесь , здесь и здесь ), которые помогли улучшить мой код.

Вот пример данных:

data = {'firm': ['Smith', 'Jones', 'Smith New York', 'Jones International', 'Winter'], 
        'id': [np.nan, 732, 216, np.nan, 1714], 
        'url1': ['url', np.nan, 'url', 'url', 'url'],
        'url2': ['url', 'url', 'url', np.nan, 'url'],
        'text': ['foo', 'bar', np.nan, np.nan, 'foo bar']}
df = pd.DataFrame(data)

Следующая функция будет анализировать веб-сайт, с помощью которого пользователь может задать ключевое слово для поиска в уже загруженных файлах и использовать эти сохраненные данные, если они есть. Если последнее сканирование произошло какое-то время, необходимо выполнить новое сканирование обновленного веб-сайта.

def fetch(id, url, **kwargs):
    if backup == 'Yes':
        print('Fetching {} from {}'.format(id, url))
        # Actual fetching code
    else:
        print('Loading stored data for {}'.format(id))
        # Actual loading code 

Функция работает так, как я тестировал ее на отдельных URL-адресах, но у меня возникают проблемы при ее применении. У меня есть несколько условий, когда запустить его. В настоящее время я использую их для подмножества данных. Примечание: если присутствуют два URL, предпочтительным является url1. После документации Pandas аргументы ключевых слов могут быть представлены. Сначала я попробовал np.where. Всего 4 условия, ниже два:

df['content'] = np.where(df['text'].isna() & df['url1'].notnull() &
                            df['url2'].notnull() & df['firm'].str.contains('Smith'),
                         df['url1'].apply(fetch, args=df['id'], backup='Yes'),
                         np.where(df['text'].isna() & df['url1'].notnull() & 
                                    df['url2'].isna() & df['firm'].str.contains('Smith'),
                                  df['url1'].apply(**fetch, backup='Yes'**),
                                  pd.np.nan))
TypeError: fetch() takes 2 positional arguments but --some other number-- were given

Следовательно, добавление серии панд не работает. И я не могу понять, как добавить его в качестве скаляра. Еще один неудачный подход только с двумя столбцами / сериями:

df[['id', 'url1']][fd['text'].isna() & df['url1'].notnull() &
    df['url2'].notnull() & df['firm'].str.contains('Smith')].apply(fetch) # Should fetch nothing
df[['id', 'url1']][fd['text'].isna() & df['url1'].notnull() &
    df['url2'].isna() & df['firm'].str.contains('Smith')].apply(fetch) # Should fetch one
TypeError: ("fetch() missing 1 required positional argument: 'url1'", 'occurred at index id')

И наконец я попробовал lambda:

df['text'].where(fd['text'].isna() & df['url1'].notnull() & df['url2'].isna()
   & df['fidm'].str.contains('Smith'), df[['id', 'url1']].apply(lambda x,y: get_XML(x,y)))
TypeError: ("<lambda>() missing 1 required positional argument: 'y'", 'occurred at index id')

Полагаю, мне не хватает чего-то простого, но, очевидно, решающего. Любые указатели приветствуются.


Правка - Решение


Я принял комментарии от Дэмиена Айерса (см. Ниже) к сердцу и упростил код. Это также привело меня к пути к решению:

def get_ft(text, xml, id, url1, url2, firm, backup= 'Yes'):
    if pd.notnull(id):
        if pd.isna(text) and pd.notnull(url1) and (pd.notnull(url2) or pd.isna(url2)):
            if 'Smith' in firm:
                return fetch(id, url1, backup)
            ... code continues

А здесь правильное использование apply и lambda благодаря этой дискуссии :

df['text_new'] = df.apply(lambda x: x['text'], x['id'], x['url1'],
                                    x['url2'], x['firm'], backup), axis=1)

Намного чище, а главное, работает.

...