Unmelt Pandas DataFrame
У меня есть pandas датафрейм с двумя переменными id:
df = pd.DataFrame({'id': [1,1,1,2,2,3],
'num': [10,10,12,13,14,15],
'q': ['a', 'b', 'd', 'a', 'b', 'z'],
'v': [2,4,6,8,10,12]})
id num q v
0 1 10 a 2
1 1 10 b 4
2 1 12 d 6
3 2 13 a 8
4 2 14 b 10
5 3 15 z 12
Я могу развернуть таблицу с помощью:
df.pivot('id','q','v')
И получилось что-то близкое:
q a b d z
id
1 2 4 6 NaN
2 8 10 NaN NaN
3 NaN NaN NaN 12
Однако я действительно хочу (оригинальная нерасплавленная форма):
id num a b d z
1 10 2 4 NaN NaN
1 12 NaN NaN 6 NaN
2 13 8 NaN NaN NaN
2 14 NaN 10 NaN NaN
3 15 NaN NaN NaN 12
Другими словами:
- 'id' и 'num' мои индексы (как правило, я видел только "id" или "num", являющийся индексом, но мне нужно обоим, так как я пытаюсь восстановить исходную нерасплавленную форму)
- 'q' - мои столбцы
- 'v' - мои значения в таблице
Обновление
Я нашел решение закрыть из блог Wes McKinney:
df.pivot_table(index=['id','num'], columns='q')
v
q a b d z
id num
1 10 2 4 NaN NaN
12 NaN NaN 6 NaN
2 13 8 NaN NaN NaN
14 NaN 10 NaN NaN
3 15 NaN NaN NaN 12
Однако формат не совсем то же, что и выше.
Ответы
Ответ 1
Ты очень близко. Просто переименуйте индекс столбца в None, и у вас есть то, что вы хотите.
df2 = df.pivot_table(index=['id','num'], columns='q')
df2.columns = df2.columns.droplevel().rename(None)
df2.reset_index().fillna("null").to_csv("test.csv", sep="\t", index=None)
Примечание, согласно которому столбец "v" должен быть по умолчанию по умолчанию, чтобы он мог быть агрегирован. В противном случае Pandas будет выходить с ошибкой:
DataError: No numeric types to aggregate
Чтобы решить эту проблему, вы можете указать свою собственную функцию агрегации с помощью пользовательской лямбда-функции:
df2 = df.pivot_table(index=['id','num'], columns='q', aggfunc= lambda x: x)
Ответ 2
Вы можете использовать set_index
и unstack
In [18]: df.set_index(['id', 'num', 'q'])['v'].unstack().reset_index()
Out[18]:
q id num a b d z
0 1 10 2.0 4.0 NaN NaN
1 1 12 NaN NaN 6.0 NaN
2 2 13 8.0 NaN NaN NaN
3 2 14 NaN 10.0 NaN NaN
4 3 15 NaN NaN NaN 12.0
Ответ 3
вы можете удалить имя q.
df1.columns=df1.columns.tolist()
Нулевой ответ + удалить q =
df1 = df.set_index(['id', 'num', 'q'])['v'].unstack().reset_index()
df1.columns=df1.columns.tolist()
id num a b d z
0 1 10 2.0 4.0 NaN NaN
1 1 12 NaN NaN 6.0 NaN
2 2 13 8.0 NaN NaN NaN
3 2 14 NaN 10.0 NaN NaN
4 3 15 NaN NaN NaN 12.0
Ответ 4
Пришел к закрытому решению
df2 = df.pivot_table(index=['id','num'], columns='q')
df2.columns = df2.columns.droplevel()
df2.reset_index().fillna("null").to_csv("test.csv", sep="\t", index=None)
По-прежнему не удается определить, как удалить "q" из фрейма данных
Ответ 5
Это может сработать нормально:
df2 = (df.pivot_table(index=['id', 'num'], columns='q', values='v')).reset_index())
- Сопоставьте имена столбцов 1-го уровня со вторым
df2.columns =[s1 + str(s2) for (s1,s2) in df2.columns.tolist()]
Ответ 6
Это можно сделать в три этапа:
#1: Prepare auxilary column 'id_num':
df['id_num'] = df[['id', 'num']].apply(tuple, axis=1)
df = df.drop(columns=['id', 'num'])
#2: 'pivot' is almost an inverse of melt:
df, df.columns.name = df.pivot(index='id_num', columns='q', values='v').reset_index(), ''
#3: Bring back 'id' and 'num' columns:
df['id'], df['num'] = zip(*df['id_num'])
df = df.drop(columns=['id_num'])
Это результат, но с другим порядком столбцов:
a b d z id num
0 2.0 4.0 NaN NaN 1 10
1 NaN NaN 6.0 NaN 1 12
2 8.0 NaN NaN NaN 2 13
3 NaN 10.0 NaN NaN 2 14
4 NaN NaN NaN 12.0 3 15
Или в правильном порядке:
def multiindex_pivot(df, columns=None, values=None):
#inspired by: https://github.com/pandas-dev/pandas/issues/23955
names = list(df.index.names)
df = df.reset_index()
list_index = df[names].values
tuples_index = [tuple(i) for i in list_index] # hashable
df = df.assign(tuples_index=tuples_index)
df = df.pivot(index="tuples_index", columns=columns, values=values)
tuples_index = df.index # reduced
index = pd.MultiIndex.from_tuples(tuples_index, names=names)
df.index = index
df = df.reset_index() #me
df.columns.name = '' #me
return df
df = df.set_index(['id', 'num'])
df = multiindex_pivot(df, columns='q', values='v')