Изменить строку по условию
Задача в следующем: необходимо добавить в конец датафрейма строку, но если такая строка уже существует по индексу, то просто изменить значения ячеек этой строки на значения добавляемой строки.
Пример:
A B C
K 1 2 3
L 1 3 5
M 2 5 3
Добавляем строку в конец:
df2 = DataFrame({'A': 2, 'B': 3, 'C': 6}, index=['N'])
df = df.concat(df, df2)
Получаем:
A B C
K 1 2 3
L 1 3 5
M 2 5 3
N 2 3 6
Далее добавляем строку DataFrame({'A': 2, 'B': 7, 'C': 7}, index=['N']), получаем:
A B C
K 1 2 3
L 1 3 5
M 2 5 3
N 2 7 7
Проблема не в способе добавления , а в скорости этой операции, я пытался:
Проверить существует ли добавляемый индекс и если да, то просто изменить значения ячеек в оригинальном датафрейме функциями
at, set_value- по скорости это очень дорого выходит, примерно 60мсПросто приравнять по индексу новый датафрейм
df['N'] = [{'A': 2, 'B': 7, 'C': 7}], так же дорого, примерно 58мсКаждый раз удалять строку по индексу, от датафрейма которого присоединяем
dropи затем вызываемdf.concat(df, df2)- получается просто нереально дорого 112мсЕсли использовать просто
df.concat(df, df2), то это самый лучший вариант, примерно 6-7мс, но когда пытаешь присоединить новую строку, а в оригинальном датафрейме уже есть такая строка с индексом, то изменение значений не произойдет, тупо добавиться в конец еще одна строка и нет возможности прописать какие-либо условия в функцииconcat, чтобы не добавлялся новый индекс, а заменялся старый, новыми значениями в ячейках(столбцах)
Так вот вопрос, можно ли это сделать, чтобы работало по скорости как и concat, знаю что датафреймы не предназначены для редактирования, а только для анализа, но вдруг...
Ответы (2 шт):
Могу предложить ещё несколько способов, быстрее которых вряд ли мне кажется можно что-то придумать. Какой будет быстрее и устроят ли они вас по скорости - это вы сами проверьте, у меня ведь нет ваших данных.
Подготовка примера данных, общая для последующих версий кода:
import pandas as pd
df = pd.DataFrame({'A': [1,2,3], 'B': [4,5,6], 'C': [7,8,9]}, index=list('NMK'))
df2 = pd.DataFrame({'A': [2,3], 'B': [3,4], 'C': [6,7]}, index=['N','Q'])
Собственно сами способы:
-
- Выбираем в
df2те индексы, которые есть и вdf - "Векторно" присваиваем сразу по всем этим индексам в
dfновые значения изdf2 - Для остальных индексов из
df2делаем конкатенацию значенийdfиdf2
- Выбираем в
mask = df2.index.isin(df.index)
idx_set = df2.index[mask]
idx_concat = df2.index[~mask]
df.loc[idx_set] = df2.loc[idx_set]
df = pd.concat([df, df2.loc[idx_concat]])
-
- Выбираем индексы
df, которых нет вdf2 - Конкатенируем только к части
dfсогласно этих индексов датафреймdf2
- Выбираем индексы
idx_keep = df.index[~df.index.isin(df2.index)]
df = pd.concat([df.loc[idx_keep], df2])
Таким образом, в этом способе мы фактически удаляем из df предварительно совпадающие индексы перед конкатенацией, но мне кажется это будет быстрее, чем через отдельный drop (хотя тоже смотря как вы его делаете). Вот тоже самое через drop. Тут скорость будет зависеть от того, что возвращает drop - вью или новый датафрейм. Если вью, то, возможно, скорость будет как через .loc, но это нужно проверять:
idx_drop = df.index[df.index.isin(df2.index)]
df = pd.concat([df.drop(index=idx_drop), df2])
-
- Просто объединяем датафреймы
- Для индексов-дубликатов выкидываем старые значения
df = pd.concat([df, df2])
df = df.loc[~df.index.duplicated(keep='last')]
если буквально следовать тому что вы написали - добавить в конец датафрейма строку, но если такая строка уже существует по индексу, то просто изменить значения ячеек этой строки на значения добавляемой строки, то можно обойтись простым присвоением:
df.loc['N'] = [2,3,6]
df.loc['K'] = [2,7,7]
>>> df
'''
A B C
K 2 7 7
L 1 3 5
M 2 5 3
N 2 3 6