ВПР с помощью Python

Есть два датасета. В df_spec - компоненты, их аналоги и их количество на одно устройство. В df_all_comp - компоненты каждого вида с количеством на складе.

Необходимо в таблицу df_spec добавить количества каждого компонента и его аналога из таблицы df_all_comp (заполнить ими столбцы Quantity_Comp, Quantity_A1, Quantity_A2)

Мой код:

df_spec = pd.DataFrame({'Comp': ['s1', 'c1', 'p1', 'l1', 't1', 'r1', 'a1', 'm1'],
 'analog1': ['s2', 'c2', 'p2', 'l2', 't2', None, 'a2', 'm2'],
 'analog2': ['s3', 'c3', None, None, 't3', None, None, 'm3'],
 'Quantity_per_1': [4.0, 3.0, 9.0, 0.0, 4.0, 11.0, 25.0, 11]})
df_spec['Quantity_Comp'] = np.nan
df_spec['Quantity_A1'] = np.nan
df_spec['Quantity_A2'] = np.nan

df_all_comp = pd.DataFrame({'Comp': ['s1', 's2', 's3', 'c1', 'c2', 'c3', 'p1', 'p2', 'l1', 'l2', 't1', 't2', 't3', 'r1', 'a1', 'a2', 'm1', 'm2', 'm3'],
 'Quantity': [4.0, 3.0, 9.0, 0.0, 4.0, 11.0, 25.0, 11.0, 13.0, 3.0, 4.0, 3.0, 9.0, 0.0, 4.0, 11.0, 25.0, 11.0, 13.0]})
#print(df_all_comp)

df=pd.merge(df_spec, df_all_comp, on='Comp', how='outer') # равно как и left, inner и т.д.
df=pd.merge(df_spec, df_all_comp, on='Quantity_A1', how='outer')
df=pd.merge(df_spec, df_all_comp, on='Quantity_A2', how='outer')
print (df)

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


Ответы (1 шт):

Автор решения: Vitalizzare ушел в монастырь

Будем исходить из того, что в df_all_comp каждое наименование комплектующих встречается ровно один раз.

Преобразуем df_all_comp в последовательность pandas.Series, индексы которой - это наименования деталей, а значения - количество деталей на складе:

df_all = df_all_comp.set_index('Comp').squeeze()

У этой последовательности есть метод Series.get, который принимает индекс и возвращает содержимое по нему, если есть что возвращать, или дефолтное значение, по умолчанию равное None. Этот метод мы передадим как аргумент методу DataFrame.map исходной таблицы, чтобы заменить наименования комплектующих на их количество на складе:

df_comp_count = (
    df_spec
    .set_index('Comp')                 # сохраним опорные комплектующие в индексе
    .filter(regex=r'^analog[0-9]+$')   # выберем столбцы наименований аналогов
    .reset_index()                     # вернем опорные комплектующие в столбцы
    .map(df_all.get)                   # заменим наименование комплектующих на их количество на складе
    .rename(columns='Quantity_{}'.format)  # добавим к названию столбцов `Quantity`, чтобы не путать с исходными
)

Результат присоединяем к исходной таблице:

df = df_spec.join(df_comp_count)   # join по индексам

Полный код в чуть более сжатом виде:

import pandas as pd

df_spec = pd.DataFrame({
    'Comp': ['s1', 'c1', 'p1', 'l1', 't1', 'r1', 'a1', 'm1'],
    'analog1': ['s2', 'c2', 'p2', 'l2', 't2', None, 'a2', 'm2'],
    'analog2': ['s3', 'c3', None, None, 't3', None, None, 'm3'],
    'Quantity_per_1': [4.0, 3.0, 9.0, 0.0, 4.0, 11.0, 25.0, 11]
})

df_all_comp = pd.DataFrame({
    'Comp': ['s1', 's2', 's3', 'c1', 'c2', 'c3', 'p1', 'p2', 'l1', 'l2', 't1', 't2', 't3', 'r1', 'a1', 'a2', 'm1', 'm2', 'm3'],
    'Quantity': [4.0, 3.0, 9.0, 0.0, 4.0, 11.0, 25.0, 11.0, 13.0, 3.0, 4.0, 3.0, 9.0, 0.0, 4.0, 11.0, 25.0, 11.0, 13.0]
})

df = df_spec.join(
    df_spec[['Comp', 'analog1', 'analog2']]
    .map(df_all_comp.set_index('Comp').squeeze().get)
    .rename(columns='Quantity_{}'.format)
)

print(df.to_string())

Результат:

  Comp analog1 analog2  Quantity_per_1  Quantity_Comp  Quantity_analog1  Quantity_analog2
0   s1      s2      s3             4.0            4.0               3.0               9.0
1   c1      c2      c3             3.0            0.0               4.0              11.0
2   p1      p2    None             9.0           25.0              11.0               NaN
3   l1      l2    None             0.0           13.0               3.0               NaN
4   t1      t2      t3             4.0            4.0               3.0               9.0
5   r1    None    None            11.0            0.0               NaN               NaN
6   a1      a2    None            25.0            4.0              11.0               NaN
7   m1      m2      m3            11.0           25.0              11.0              13.0
→ Ссылка