Используя Pandas, как вы можете сопоставить несколько индексов в серии, сопоставить с DataFrame и заменить несколько столбцов - PullRequest
3 голосов
/ 03 августа 2020

Я пытаюсь сопоставить комбинацию значений в одном фрейме данных с той же комбинацией в другом (по сути, таблица поиска). Если я нахожу совпадение в таблице поиска, замените значения в оригинале из поиска. Я пробовал использовать replace, map, используя lo c, но мне кажется, что я больше запутываю себя.

У меня есть пример фрейма данных

example1 = {
    'Code': ['99233','99233','99233','90732','93306','93306','93306'],
    'Modifier': ['','','','','','TC','26'],
    'W': ['0','0','0','0','0','0','0'],
    'P': ['0','0','0','0','0','0','0'],
    'M': ['0','0','0','0','0','0','0']
}
df1 = pd.DataFrame(example1)

который выглядит так,

    Code    Modifier    W   P   M
0   99233               0   0   0
1   99233               0   0   0
2   99233               0   0   0
3   90732               0   0   0
4   93306               0   0   0
5   93306   TC          0   0   0
6   93306   26          0   0   0

Затем я бы использовал таблицу поиска, подобную следующей ...

example2 = {
    'Code': ['99233','90732','93306','93306','93306'],
    'Modifier': ['','','','TC','26'],
    'W': ['2','0','1.5','0','1.5'],
    'P': ['0.81','0','4.29','3.76','0.53'],
    'M': ['0.13','0','0.7','0.2','0.05']
}
df2 = pd.DataFrame(example2)

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

    Code    Modifier    W   P       M
0   99233               2   0.81    0.13
1   90732               0   0       0
2   93306               1.5 4.29    0.7
3   93306   TC          0   3.76    0.2
4   93306   26          1.5 0.53    0.05

Я хочу иметь возможность используйте поля «Код» и «Модификатор» и замените значения W, P и M в основном фрейме данных (df1).

Мне удалось сопоставить одно значение, преобразовав таблицу поиска в series (я не уверен, что это правильно, но это имеет смысл) и использование кода в словаре в качестве индекса

vdic = pd.Series(df2.W.values, index=df2.Code).to_dict()
df1.loc[df1.Code.isin(vdic.keys()), 'W'] = df1.loc[(df1.Code.isin(vdic.keys())), 'Code'].map(vdic)
df1

Это приводит меня к середине пути с первым столбцом, но, очевидно, не выбирая вверх по модификатору.

    Code    Modifier    W   P   M
0   99233               2   0   0
1   99233               2   0   0
2   99233               2   0   0
3   90732               0   0   0
4   93306               1.5 0   0
5   93306   TC          1.5 0   0
6   93306   26          1.5 0   0

Я попытался добавить второй индекс в словарь,

vdic = pd.Series(df2.W.values, index=[df2.Code, df2.Modifier]).to_dict()

{('99233', ''): '2',
 ('90732', ''): '0',
 ('93306', ''): '1.5',
 ('93306', 'TC'): '0',
 ('93306', '26'): '1.5'}

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

Любая помощь или предложения были бы очень признательны.

Также любопытно, могу ли я обновить все три столбца (W, P и M ) за один проход или это должно быть разделено?

Редактировать из первого ответа @ user13802115 (что было круто, кстати)

Я должен изменить вопрос и спросить, можно выполнить ту же операцию, когда фреймы данных имеют разный размер.

example3 = {
    'Other1': ['1','7','4','54','9','43','22'],
    'Other2': ['A','Z','Y','BB','7W','9','Left'],
    'Code': ['99233','99233','99233','90732','93306','93306','93306'],
    'Modifier': ['','','','','','TC','26'],
    'W': ['0','0','0','0','0','0','0'],
    'P': ['0','0','0','0','0','0','0'],
    'M': ['0','0','0','0','0','0','0']
}
df3 = pd.DataFrame(example3)

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

Решение ниже

Благодаря ответу @ user13802115 я использовал следующую ссылку: Pandas слияние фреймов данных разного размера на основе одного столбца

, чтобы получить то, что мне нужно. Используя измененный фрейм данных (df3), я могу выполнить следующее, чтобы объединить мои данные, отбросить добавленные значения в мой исходный фрейм данных и переиндексировать, чтобы все осталось в том виде, в каком оно было создано изначально, с обновленными полями.

df = (df3.merge(df2, on=['Code','Modifier'], how='left', suffixes=('_',''))
        .drop(['W_','P_','M_'], axis=1)
        .reindex(columns=df1.columns))
df

Ответы [ 2 ]

1 голос
/ 03 августа 2020

Я не совсем уверен, но я считаю, что это то, что вам нужно.

df3 = pd.merge(df1[['Code','Modifier']],df2,on = ['Code','Modifier'],how = 'left').fillna('0')
0 голосов
/ 03 августа 2020

Я думаю, что это то, что вы пытаетесь сделать:

for code_ind, code in enumerate(df1.Code.unique()):
    modifiers = df1.loc[df1['Code']==code].Modifier.unique()
    for mod_ind, modifier in enumerate(modifiers):
        row_to_modify = df1.loc[(df1['Code']==code) &(df1['Modifier']==modifier)].iloc[0].name
        lookup_row = df2.loc[(df2['Code']==code) & (df2['Modifier']==modifier),['W','P','M']].iloc[0].name
        df1.loc[df1.index[row_to_modify],['W','P','M']] =  df2.loc[df2.index[lookup_row],['W','P','M']]

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

Вот пример выходного фрейма данных с использованием предоставленных вами словарей:

    Code Modifier    W     P     M
0  99233             2  0.81  0.13
1  99233             0     0     0
2  99233             0     0     0
3  90732             0     0     0
4  93306           1.5  4.29   0.7
5  93306       TC    0  3.76   0.2
6  93306       26  1.5  0.53  0.05
...