Как эффективно проверить столбцы и поместить определенное значение в другой столбец в другом кадре данных? - PullRequest
0 голосов
/ 10 мая 2019

У меня есть два кадра данных, df1 и df2. Оба имеют одинаковые идентификаторы. В df2 один идентификатор находится в нескольких строках (ни один, ни один из columnB не может иметь значение «a», а в каждой строке есть другое значение в столбце «columnC»).

df1 = pd.DataFrame({'ID': ['111.111', '222.222', '333.333','444.444], 'columnA': [np.nan,np.nan,np.nan,np.nan]}) # or columnA does not has to be defined yet
df2 = pd.DataFrame({'ID': ['111.111', '111.111','111.111', '222.222' ,'222.222', '333.333', '333.333', '444.444'],
'columnB': [np.nan,'a',np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],
'columnC':['0432', '0987','5460','0955','4356','6029','7329','9006']})

Это выглядит так:

df1                   df2
ID       columnA       ID     columnB   columnC
111.111              111.111             0432
222.222              111.111     a       0987
333.333              111.111             5460
444.444              222.222             0955
                     222.222             4356
                     333.333             6029
                     333.333             7329
                     444.444             9006

Моя цель: Если columnB == 'a' ИЛИ ни один из columnC isin (validValues), я хочу поместить значение 'AA' в columnA из df1 с тем же ID, где одно из условий дало true.

Мне нужен эффективный способ для этого.

Допустим, validValues = {'0987', '2638', '5460', '9386'}

ожидается df1:

ID      columnA
111.111
222.222    AA
333.333
444.444    AA

До сих пор я пробовал следующее:

df2['temp']=df2['columnB']

tmp_df = df2.groupby('ID').temp.apply(lambda x: 'AA' if (x=='a').any() else ' ')


tmp_df=tmp_df.to_frame()

df1['columnA']=df1.merge(tmp_df, how='outer',
               left_on=df1.ID, 
               right_on=tmp_df.index).drop('key_0', axis=1)['temp']


df2['temp']=df2['columnc']
tmp_df = df2.groupby('ID').temp.apply(lambda x: 'AA' if (x.isin(validValues)).any() else ' ')
tmp_df=tmp_df.to_frame()

df1['columnA']=df1.merge(tmp_df, how='outer',
               left_on=df1.ID, 
               right_on=tmp_df.index).drop('key_0', axis=1)['temp']

Одна проблема заключается в том, что второе слияние отменяет первое. Решение вообще плохое.

Кроме того, было бы неплохо удалить thous ID, где 'AA' был вставлен в df1 из df2.

1 Ответ

0 голосов
/ 11 мая 2019
df2IDs = df2[(df2['columnB'] == 'a') | (df2['columnC'].isin(validValues))][ID].tolist()

df1.loc[df1['ID'].isin(df2IDs), 'columnA'] = 'a'

1) Первый фильтр df2 для тех, где columnB - это или columnC - в ваших допустимых значениях, посмотрите на столбец ID и сохраните его в списке.

2) Возьмите этот список и посмотрите в df1, где идентификатор совпадает, посмотрите на столбец A и установите его равным «a».

EDIT

df2IDs = df2.groupby('ID').filter(lambda x:any(x.columnB == 'a') | all(np.logical_not(x.columnC.isin(validValues))))['ID']

df1.loc[df1['ID'].isin(df2IDs), 'columnA'] = 'a'

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

...