изменение формы фрейма данных с помощью stack / unstack

#pandas #dataframe #stack #pivot #multi-index

#pandas #фрейм данных #стек #сводная #многоиндексный

Вопрос:

У меня есть фрейм данных, который выглядит следующим образом:

 df1 = pd.DataFrame({'Type' : ['Q','A','A'], 'Fields': ['Q1','Pre','Post'],'ChildA' : [0,3,5],'ChildB' : [0,2,3]})

    ChildA  ChildB Fields Field_Type
 0       0       0     Q1          Q
 1       3       2    Pre          A
 2       5       3   Post          A
  

всего около 200 дочерних элементов и около 50 вопросов. То, к чему я пытаюсь добраться, выглядит примерно так:

       Name     Question    Pre     Post
   0  ChildA   Q1          3       5
   1  ChildB   Q1          2       3
   2  ChildA   Q2          1       4
   3  ChildB   Q2          3       3
  

но я не уверен, как лучше всего подойти к этому, я пробовал stack и pivot , но оба вернутся ValueError: Index contains duplicate entries, cannot reshape , или когда это сработает, это не в том формате, который мне нужен, или может работать в правильном формате. Ближе всего, что у меня пока есть, — использовать transpose df2 = df1[0:3].T , который работает нормально, пока я беру 3 строки за раз, но это кажется очень неэффективным, и я знаю, что должен быть лучший способ с использованием pivot или stack / unstack.

Возможно, это потребует некоторой множественной индексации, поэтому меня привлекает, stack поскольку pivot возникают всевозможные проблемы, такие как Exception: Data must be 1-dimensional когда я попытался бы сказать

 df1.pivot(columns='Name',values=['Ben','Jack'])
  

Любая помощь приветствуется!

Ответ №1:

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

  1. поставьте вопрос против каждого ответа, используя комбинацию np.where и fillna()
  2. только с ответами индексируйте его, поэтому транспонирование имеет смысл
  3. stack() вопрос снова должен быть столбцом
 import numpy as np
df1 = pd.DataFrame({'Type' : ['Q','A','A'], 'Fields': ['Q1','Pre','Post'],'ChildA' : [0,3,5],'ChildB' : [0,2,3]})

maskq = df1["Type"]=="Q"
# need to get question against each answer
df1 = (df1
 .assign(Question=lambda x: np.where(x["Type"]=="Q", x["Fields"], np.nan))
 .assign(Question=lambda x: x["Question"].fillna(method="ffill"))
)
# now take just questions and organise as required
df1 = df1.loc[~maskq, [c for c in df1.columns if c!="Type"]].set_index(["Fields","Question"]).T.stack()

  

вывод

 Fields           Post  Pre
       Question           
ChildA Q1           5    3
ChildB Q1           3    2