У меня есть следующие данные:
import pandas as pd, numpy as np
data = [['id', 'date', 'b_field', 'a_field'],
['XYX', '01/01/2024', 100, 101],
['XYX', '01/02/2024', 200, 201],
['ABC', '01/01/2024', 300, 301],
['ABC', '01/02/2024', 400, 401]]
id_sort=['ABC', 'XYZ']
field_sort=['a_field', 'b_field']
df = pd.DataFrame(data[1:], columns=data[:1])

Я хотел бы эффективно преобразовать это так, чтобы если бы я сериализовал это в массив csv или json, это выглядело бы так:

где:
До сих пор я пробовал несколько вещей. Ближе всего я подошел к следующему:
df.set_index('date').reindex(pd.MultiIndex.from_product([id_sort, field_sort]),axis=1).reset_index()
Конечно, как видите, есть несколько проблем:

Обновлено: Для № 2, чтобы сдвинуть метку даты вниз, похоже, я могу это сделать (не уверен, что это лучший способ):
df = df.rename(columns = {'date': '', '':'date'})






Вот один из подходов:
df = pd.DataFrame(data[1:], columns=data[0])
out = (
df
.set_index(['id', 'date'])
.unstack(0)
.swaplevel(axis=1)
.sort_index(axis=1)
.rename_axis(index=[('date', '')],
columns=(None, None))
.reset_index()
)
Выход
date ABC XYX
a_field b_field a_field b_field
0 01/01/2024 301 300 101 100
1 01/02/2024 401 400 201 200
Объяснение
columns внутри pd.DataFrame. columns=data[:1] приведет к кортежам типа ('id',). Я надеюсь, вам нужны только строки в качестве заголовков: data[0].['id', 'date'] в качестве индекса с df.set_index и df.unstack 'id' (уровень 0).[('date', '')] здесь для переименования index, чтобы в итоге получить ('date',''), а не ('','date') после финального df.reset_index . (следуя подходу @mozway.)Спасибо. добавление этого в конец выглядит так, как будто оно будет обрабатывать метку «дата»: .reset_index().rename(columns = {'date': '', '':'date'}) Насколько это эффективно? набор данных может состоять из миллиона строк, с которыми я это сделаю?
Обновлено с возвращением «даты» в качестве первого столбца и цепочкой df.reset_index в конце.
С точки зрения производительности, похоже, между моим решением и решением @mozway не так уж много различий. Я получаю 3,05 (мой) против 3,25 (mozway) на df с формой (1000000, 4), индивидуальными id значениями. Предположим, что одним из потенциальных преимуществ подхода Mozway является то, что он позволяет легко выполнить пользовательскую сортировку на случай, если простой sort_index не подойдет (но в данном случае подойдет :)).
да, я тестировал, и на самом деле производительность между двумя решениями колеблется. между 0,01–0,03 мс. Его решения касаются сортировки. я могу отметить только одно решение. так ценно...
Не волнуйтесь, удачи в проекте!
Похоже, вы могли бы повернуть , уровень подкачки и переиндексировать с помощью своего пользовательского индекса.
Лучшим подходом к перемещению «даты» на верхний уровень было бы переименовать_ось с помощью кортежа ('date', '') перед вызовом reset_index:
df = pd.DataFrame(data[1:], columns=data[0])
id_sort=['ABC', 'XYX']
field_sort=['a_field', 'b_field']
idx = pd.MultiIndex.from_product([id_sort, field_sort])
out = (df.pivot(index='date', columns='id').swaplevel(axis=1)
.reindex(idx, axis=1)
.rename_axis([('date', '')]).reset_index()
)
Выход:
date ABC XYX
a_field b_field a_field b_field
0 01/01/2024 301 300 101 100
1 01/02/2024 401 400 201 200
одно примечание: для очень больших наборов данных это дает PerformanceWarning: indexing past lexsort depth may impact performance.. Я думаю, мне следует сначала отсортировать по мультииндексу?
@mike01010 действительно, ты можешь сначала sort_,index,()
Вам нужно использовать Pivot с помощью Lambda:
import pandas as pd
import numpy as np
data = [['id', 'date', 'b_field', 'a_field'],
['XYZ', '01/01/2024', 100, 101],
['XYZ', '01/02/2024', 200, 201],
['ABC', '01/01/2024', 300, 301],
['ABC', '01/02/2024', 400, 401]]
id_sort = ['ABC', 'XYZ']
field_sort = ['a_field', 'b_field']
df = pd.DataFrame(data[1:], columns=data[0], index=None)
# Set 'id' as index
df.set_index('id', inplace=True)
# Sort the index according to id_sort
df = df.loc[id_sort]
# Reset index to make 'id' a column again
df.reset_index(inplace=True)
# Melt the DataFrame to reshape it
df_melted = df.melt(id_vars=['id', 'date'],
value_vars=field_sort, var_name='field')
df.index = df.index + 1
# Pivot the melted DataFrame to get the desired format
df_pivot = df_melted.pivot(
index='date', columns=['id', 'field'], values='value').reset_index()
# Flatten the MultiIndex columns
df_pivot.columns = df_pivot.columns.map(
lambda x: '_'.join(map(str, x)) if x[1] else x[0])
print(df_pivot)
Обратите внимание, что у вас есть опечатка в данных XYX/XYZ.