Данные по нескольким условиям из столбцов контрольных точек

Рейтинг: 1Ответов: 0Опубликовано: 07.07.2023

У меня возникла проблема со скоростью обработки своих данных. Есть датафрейм из трех блоков: наименование, признаки, контрольные точки. И проще говоря мне нужно собрать наименования с признаками в одну таблицу по всем контрольным точкам построчно. Значения контрольных точек указывают какие признаки выбрать для каждого наименования!

Я использовал конкатенацию с циклом. И это оказалось слишком медленным для меня. Около 20-30 секунд. И я чувствую, что его можно ускорить, но я не знаю, как. Мне нужно, чтобы это заняло 2-3 секунды. Скажите, пожалуйста, я неправильно выбрал метод индексации поиска признаков по значениям всех контрольных точек? Как я могу улучшить или коренным образом изменить код?

Вот описание датафрейма:

  • Наименование ('index', 'name', 'country')
  • Различные признаки по группам 'c', 'd' ('a1_b1_c_foo', 'a1_b1_c_foo_bar', ..., 'a1_b1_d_foo_bar_baz', ...)
  • Несколько контрольных точек к каждому наименованию ('point_1' 'point_1_description', ..., 'point_2', ...). Каждый чекпоинт содержит уточняющие значения для извлечения конкретных столбцов признаков ('point_1_a', point_1_b', ....)

Я привел упрощенный датафрейм в пример. Чтобы понять приблизительный объем данных я напишу сколько будет содержать настоящий датафрейм:

  • Десятки тысяч строк (наименований)
  • Пятнадцать признаков группы 'c', десять признаков группы 'd'
  • 'a1_ ...' 'a2_ ...' планируется от 1 до 15
  • 'b1 ...' 'b2 ...' планируется от 1 до 3
  • 40 контрольных точек
index name country a1_b1_c_foo a1_b1_c_foo_bar a1_b1_d_foo_bar_baz a2_b1_c_foo a2_b1_c_foo_bar a2_b1_d_foo_bar_baz a1_b2_c_foo a1_b2_c_foo_bar a1_b2_d_foo_bar_baz a2_b2_c_foo a2_b2_c_foo_bar a2_b2_d_foo_bar_baz a1_b3_c_foo a1_b3_c_foo_bar a1_b3_d_foo_bar_baz a2_b3_c_foo a2_b3_c_foo_bar a2_b3_d_foo_bar_baz point_1 point_1_description point_1_a point_1_b point_2 point_2_description point_2_a point_2_b point_3 point_3_description point_3_a point_3_b point_4 point_4_description point_4_a point_4_b
0 Bernard France value1 value2 value3 value4 value5 value6 value7 value8 value9 value10 value11 value12 value13 value14 value15 value16 value17 value18 name1 description1 1 1 name2 description2 2 1 name3 description3 1 2 name4 description4 1 2
1 Elon USA value19 value20 value21 value22 value23 value24 value25 value26 value27 value28 value29 value30 value31 value32 value33 value34 value35 value36 name5 description5 1 2 name6 description6 1 2 name8 description8 2 2
2 Jeff USA value37 value38 value39 value40 value41 value42 value43 value44 value45 value46 value47 value48 value49 value50 value51 value52 value53 value54 name9 description9 2 1 name11 description11 2 2 name12 description12 1 1
3 Lawrence USA value55 value56 value57 value58 value59 value60 value61 value62 value63 value64 value65 value66 value67 value68 value69 value70 value71 value72 name13 description13 1 2 name14 description14 1 1 name16 description16 1 2

В итоговой таблице то что я хочу получить: собраны все контрольные точки с соответствующими признаками, которые определяются в зависимости от значения столбцов 'point_...a', 'point...b'.

Пример итоговой таблицы:

name country c_foo c_foo_bar d_foo_bar_baz point point_description point_a point_b
0 Bernard France value1 value2 value9 name1 description1 1 1
1 Elon USA value25 value26 value33 name5 description5 1 2
2 Jeff USA value40 value41 value48 name9 description9 2 1
3 Lawrence USA value61 value62 value69 name13 description13 1 2
0 Bernard France value4 value5 value12 name2 description2 2 1
1 Elon USA value25 value26 value33 name6 description6 1 2
2 Lawrence USA value55 value56 value63 name14 description14 1 1
0 Bernard France value7 value8 value15 name3 description3 1 2
0 Bernard France value7 value8 value15 name4 description4 1 2

Вот мой код:

import pandas as pd
import numpy as np

with open('test_r.csv', encoding='utf-8') as f:
    df = pd.read_csv(f, sep='   ', low_memory=False)





collist_tmp = [
    "a1_b1_c_foo",
    "a1_b1_c_foo_bar",
    "a1_b1_d_foo_bar_baz",
    "a2_b1_c_foo",
    "a2_b1_c_foo_bar",
    "a2_b1_d_foo_bar_baz",
    "a1_b2_c_foo",
    "a1_b2_c_foo_bar",
    "a1_b2_d_foo_bar_baz",
    "a2_b2_c_foo",
    "a2_b2_c_foo_bar",
    "a2_b2_d_foo_bar_baz",
    "a1_b3_c_foo",
    "a1_b3_c_foo_bar",
    "a1_b3_d_foo_bar_baz",
    "a2_b3_c_foo",
    "a2_b3_c_foo_bar",
    "a2_b3_d_foo_bar_baz",
    ]

collist_d = [
    "d_foo_bar_baz",
    ]

collist_final_df = [
    "name",
    "country",
    "c_foo",
    "c_foo_bar",
    "d_foo_bar_baz",
    'point',
    'point_description',
    'point_a',
    'point_b',
    ]





# assembly checkpoints "point"
list_dfs = []





# loop
for i in range(1,5):

    collist_c = [
        "name",
        "country",
        "c_foo",
        "c_foo_bar",
        'point_' + str(i),
        'point_' + str(i) + '_description',
        'point_' + str(i) + '_a',
        'point_' + str(i) + '_b',
        ]
    
    collist_df_all = [
        "name",
        "country",
        "c_foo",
        "c_foo_bar",
        "d_foo_bar_baz",
        'point_' + str(i),
        'point_' + str(i) + '_description',
        'point_' + str(i) + '_a',
        'point_' + str(i) + '_b',
        ]


    df = df.loc[~df[f'point_{i}'].isnull()]

    # tmp
    tmp = df.reindex(columns=collist_tmp)
    tmp.columns = pd.MultiIndex.from_frame(tmp.columns.str.extract('(a[^_]+_b[^_]+)_(.*)'))

    # group c
    target_c = 'a'+ (pd.Series(df[f'point_{i}_a'].astype('Int16') + 0, dtype='string')) + '_b'+ (df[f'point_{i}_b'].astype('Int16').astype(str)) 
    df_c = (df
    .reset_index()
    .merge(tmp.stack(level=0, dropna=False), left_on=['index', target_c], right_index=True)
    .set_index('index')[collist_c]
    .reset_index()
    )

    # group d
    target_d = 'a'+ (df[f'point_{i}_a'].astype('Int16').astype(str)) + '_b'+ (pd.Series(df[f'point_{i}_b'].astype('Int16') + 1, dtype='string'))
    df_d = (df
    .reset_index()
    .merge(tmp.stack(level=0, dropna=False), left_on=['index', target_d], right_index=True)
    .set_index('index')[collist_d]
    .reset_index()
    )

    # assembly df with group c and group d
    df_all = pd.concat(
        objs=(iDF.set_index('index') for iDF in (df_c, df_d)),
        axis=1, 
        join='inner'
    ).reset_index().drop(columns=['index']).reindex(columns=collist_df_all)





    df_all.columns = collist_final_df

    # assembly checkpoints "point"
    list_dfs.append(df_all)






# assembly checkpoints "point"
df_final = pd.concat(list_dfs)

print(df_final)

Ответы

Ответов пока нет.