2017-01-31 4 views
3

Заранее спасибо за чтение.Как применить функцию к столбцу в Pandas в зависимости от значения в другом столбце?

У меня есть dataframe:

df = pd.DataFrame({'Words':[{'Sec': ['level']},{'Sec': ['levels']},{'Sec': ['level']},{'Und': ['ba ']},{'Pro': ['conf'],'ProAbb': ['cth']}],'Conflict':[None,None,None,None,'Match Conflict']}) 


     Conflict          Words 
0   None      {u'Sec': [u'level']} 
1   None      {u'Sec': [u'levels']} 
2   None      {u'Sec': [u'level']} 
3   None      {u'Und': [u'ba ']} 
4 Match Conflict {u'ProAbb': [u'cth'], u'Pro': [u'conf']} 

Я хочу, чтобы применить процедуру, которая для каждого элемента в 'Words', проверяет Conflict = 'Match Conflict' и если да, то применяется некоторую функцию к значению в 'Words'.

Например, с помощью следующей функции замещающий:

def func(x): 
    x = x.clear() 
    return x 

Я пишу:

df['Words'] = df[df['Conflict'] == 'Match Conflict']['Words'].apply(lambda x: func(x)) 

Мой ожидается выход:

  Conflict          Words 
0   None      {u'Sec': [u'level']} 
1   None      {u'Sec': [u'levels']} 
2   None      {u'Sec': [u'level']} 
3   None      {u'Und': [u'ba ']} 
4 Match Conflict          None 

Вместо этого я получаю:

  Conflict Words 
0   None NaN 
1   None NaN 
2   None NaN 
3   None NaN 
4 Match Conflict None 

Функция применяется только к строке, которая имеет Conflict = 'Match Conflict', но за счет других строк (которые все стали None. Я предположил, что остальные строки останутся нетронутыми; очевидно, это не так.

Можете ли вы объяснить, как я мог бы достичь желаемого результата, не отбрасывая всю информацию в столбце Words? Я считаю, что ответ может лежать на np.where, но я не смог выполнить эту работу, это было лучшее, что я мог придумать.

Любая помощь очень ценится. Благодарю.

+0

'пеленгации [«Слова»] = # anything' перезаписывает' words' столбец Так что это ведет себя точно. как вы его просили. –

+0

@PaulH Оцените обратную связь. Я попытался применить то, что мало знал, и это было насколько мне удалось. Я рад за вашу помощь и помощь Psidom. – Chuck

ответ

3

Вы можете попробовать обновить только те строки, которые соответствуют условию, используя .loc:

df.loc[df['Conflict'] == 'Match Conflict', 'Words'] = df.loc[df['Conflict'] == 'Match Conflict', 'Words'].apply(lambda x: func(x)) 

enter image description here

+0

Большое спасибо за вашу помощь.Я могу адаптировать это и @Paul H, чтобы делать все, что мне нужно. Действительно ценю это. – Chuck

+0

Просто хотел вернуться и снова сказать спасибо. Сегодня я реализовал это в производстве, и он решил целый ряд проблем. Спасибо – Chuck

3

Вы должны переписать функцию, чтобы работать со всеми своими строками:

def func(x, match): 
    if x['Conflict'] == match: 
     return None 
    return x['Words'] 

df['Words'] = df.apply(lambda row: func(row, 'Match Conflict'), axis=1) 
+0

Большое спасибо за вашу помощь Пол :) Это очень полезно. Я весь день вытаскивал волосы. – Chuck

2

Вы также можете использовать where, как вы описали,

condition = df.Conflict != 'Match Conflict' 
df['Words'] = df.Words.where(condition, None) 

     Conflict     Words 
0   None {u'Sec': [u'level']} 
1   None {u'Sec': [u'levels']} 
2   None {u'Sec': [u'level']} 
3   None  {u'Und': [u'ba ']} 
4 Match Conflict     None 
+0

Большое спасибо вам за ваш ответ и ввод! Что же касается реализации 'where' с функцией, а не просто' None' a la: 'df ['Words'] = df.Words.where (condition, #func())' Каким будет синтаксис этого вида? (Я спрашиваю об этом, потому что эта функция является просто заполнителем, реальная является гораздо более существенной) – Chuck

+0

Функция должна быть модифицирована, вероятно, в зависимости от того, что это такое. –

2

предположит местозаполнитель

def func(x): 
    x = x.clear() 
    return x 

Тогда мы можем использовать логические индексацию и применять для получения желаемых результатов.

df.ix[df['Conflict']=='Match Conflict', 'Words'].apply(func) 

Я хотел дать краткий Однострочник, но я был слишком поздно: (

+0

Бог, я так много учусь. Спасибо за ваш вклад. Ваш ответ привел меня к этому вопросу http://stackoverflow.com/questions/27667759/is-ix-always-better-than-loc-and-iloc-since-it-is-faster-and-supports-i и on и дальше. Благодарю. – Chuck

+0

Не могли бы вы также воспользоваться функцией '== 'Match Conflict'', если бы вы хотели расширить свои критерии до более строгих? – Chuck

+0

Я так считаю. Булева и вызываемая индексация подробно описаны в [документации] (http://pandas.pydata.org/pandas-docs/stable/indexing.html). Я полагаю, вы можете написать функцию, которая возвращает bool и использовать ее как 'df.ix [bool_func (df.A), 'B']'. Однако я никогда не пробовал это сам. – spicypumpkin