2016-06-04 1 views
3

Долгое время этого сайта, но первый раз задавая вопрос! Благодаря всем доброжелательным пользователей, которые были отвечая на вопросы в течение веков :)python pandas: прохождение в dataframe к df.apply

Я использую df.apply в последнее время и в идеале хотел бы передать dataframe в параметр args выглядеть примерно так: df.apply(testFunc, args=(dfOther), axis = 1)

Моих конечным Цель состоит в том, чтобы итерации по файлу данных передаваться в параметре args и проверять логику на каждую строку исходного фрейма, например df, и возвращать некоторое значение от dfOther. Так что у меня есть функция, как это:

def testFunc(row, dfOther): 
    for index, rowOther in dfOther.iterrows(): 
     if row['A'] == rowOther[0] and row['B'] == rowOther[1]: 
      return dfOther.at[index, 'C'] 

df['OTHER'] = df.apply(testFunc, args=(dfOther), axis = 1) 

моего понимания является то, что args ожидает объект серии, и поэтому, если я на самом деле управлять этим мы получаем следующее сообщение об ошибке:

ValueError: The truth value of a DataFrame is ambiguous. 
Use a.empty, a.bool(), a.item(), a.any() or a.all(). 

Однако, прежде чем я написал testFunc, который проходит только в одном фрейме данных, я на самом деле написал priorTestFunc, который выглядит вот так ... И он работает!

def priorTestFunc(row, dfOne, dfTwo): 
    for index, rowOne in dfOne.iterrows(): 
     if row['A'] == rowOne[0] and row['B'] == rowOne[1]: 
      return dfTwo.at[index, 'C'] 

df['OTHER'] = df.apply(testFunc, args=(dfOne, dfTwo), axis = 1) 

Так к моему ужасу, я приходил в привычку писать testFunc как так и работает как задумано:

def testFunc(row, dfOther, _): 
    for index, rowOther in dfOther.iterrows(): 
     if row['A'] == rowOther[0] and row['B'] == rowOther[1]: 
      return dfOther.at[index, 'C'] 

df['OTHER'] = df.apply(testFunc, args=(dfOther, _), axis = 1) 

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

EDIT: В соответствии с комментарием: Мои dfs обычно выглядят следующим образом. Они будут иметь два соответствующих столбца и будут возвращать значение из dfOther.at[index, column]. Я рассмотрел pd.concat([dfOther, df]), однако я буду запускать условия тестирования алгоритмов на df, а затем обновляя его по определенным значениям на dfOther (который также будет обновляться), и я хотел бы, чтобы df был относительно опрятным, в отличие от создания мультииндекса и метания всего, что в нем было. Также мне известно, что df.iterrows в целом медленный, но эти данные будут составлять около 500 строк на максимальном уровне, поэтому масштабируемость на данный момент не вызывает большого беспокойства.

df 
Out[10]: 
    A B  C 
0 foo bur 6000 
1 foo bur 7000 
2 foo bur 8000 
3 bar kek 9000 
4 bar kek 10000 
5 bar kek 11000 

dfOther 
Out[12]: 
    A B  C 
0 foo bur 1000 
1 foo bur 2000 
2 foo bur 3000 
3 bar kek 4000 
4 bar kek 5000 
5 bar kek 6000 

ответ

3

Ошибка в этой строке:

File "C:\Anaconda3\envs\p2\lib\site-packages\pandas\core\frame.py", line 4017, in apply 
    if kwds or args and not isinstance(func, np.ufunc): 

Здесь if kwds or args проверяет ли длина args передается apply больше 0. Это обычный способ проверить, если итератор является пусто:

l = [] 

if l: 
    print("l is not empty!") 
else: 
    print("l is empty!") 

l is empty!

l = [1] 

if l: 
    print("l is not empty!") 
else: 
    print("l is empty!") 

Если вы передали кортеж df.apply как args, он вернет True и проблем не возникнет.Однако, Python не интерпретирует (ДФ) в виде кортежа:

type((df)) 
Out[39]: pandas.core.frame.DataFrame 

Это просто DataFrame/переменная внутри скобок. При вводе if df:

if df: 
    print("df is not empty") 

Traceback (most recent call last): 

    File "<ipython-input-40-c86da5a5f1ee>", line 1, in <module> 
    if df: 

    File "C:\Anaconda3\envs\p2\lib\site-packages\pandas\core\generic.py", line 887, in __nonzero__ 
    .format(self.__class__.__name__)) 

ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all(). 

Вы получаете то же самое сообщение об ошибке. Однако, если вы используете запятую, чтобы указать, что It'a кортеж, он отлично работает:

if (df,): 
    print("tuple is not empty") 

tuple is not empty 

Как результат, добавив запятую args=(dfOther), сделав его singleton должен решить эту проблему.

df['OTHER'] = df.apply(testFunc, args=(dfOther,), axis = 1) 
+1

@macavich, место сверху! Это хорошая добыча! – MaxU

+0

Спасибо @ayhan за хорошо описанный и элегантный ответ. – macavich

+0

@macavich, рассмотрите [принимаю] (http://meta.stackexchange.com/a/5235) самый полезный ответ - это также укажет, что на ваш вопрос был дан ответ – MaxU