Превращение значений в столбцы
Извиняюсь за смутное название вопроса, но я не совсем уверен, как вызвать эту операцию.
У меня есть следующий фрейм данных:
import pandas as pd
df = pd.DataFrame({
'A': [1, 3, 2, 1, 2],
'B': [2, 1, 3, 2, 3],
'C': [3, 2, 1, 3, 1],
})
print(df)
# A B C
# 0 1 2 3
# 1 3 1 2
# 2 2 3 1
# 3 1 2 3
# 4 2 3 1
Эти данные представляют "ранжирование" каждого из параметров, A
, B
и C
для каждой строки. Так, например, в строке 2
C
был лучшим, затем A
, затем B
. Я хотел бы построить "инвертированный" фрейм данных, где для каждой строки у меня есть три столбца для позиции 1
, 2
и 3
ранжирования, с A
, B
и C
сейчас данные. Итак, для приведенного выше примера результат будет следующим:
out = pd.DataFrame({
1: ['A', 'B', 'C', 'A', 'C'],
2: ['B', 'C', 'A', 'B', 'A'],
3: ['C', 'A', 'B', 'C', 'B'],
})
print(out)
# 1 2 3
# 0 A B C
# 1 B C A
# 2 C A B
# 3 A B C
# 4 C A B
В идеале, каждая строка в df
должна иметь три разных значения 1
, 2
и 3
, но могут быть случаи с повторяющимися значениями (значения из этого диапазона не должны рассматриваться), Если это вообще возможно, я бы хотел решить эту проблему, "объединив" имена опций в одной и той же позиции и добавив пустые строки или NaN в пропущенные позиции. Например, с этим вводом:
df_bad = pd.DataFrame({'A': [1], 'B': [2], 'C': [2]})
print(df_bad)
# A B C
# 0 1 2 2
В идеале я бы хотел получить такой вывод:
out_bad = pd.DataFrame({1: ['A'], 2: ['BC'], 3: ['']})
print(out_bad)
# 1 2 3
# 0 A BC
В качестве альтернативы, я могу согласиться на получение одного из значений вместо конкатенации.
Я просматривал melt
, pivot
, pivot_table
и другие функции, но не могу понять, как получить результат Я хочу.
Ответы
Ответ 1
для случаев дублирования ранжирования, таких как 2-й пример, любое решение, использующее pivot
и unstack
на последнем шаге, завершится неудачей. Вам нужен pivot_table
или crosstab
. Как вы уже разобрались с решением, используя pivot_table
. Вот crosstab
df2 = df_bad.stack().reset_index(1, name='cols')
pd.crosstab(index=df2.index, columns=df2.cols, values=df2.level_1,
aggfunc=''.join).fillna('')
Out[171]:
cols 1 2
row_0
0 A BC
Используйте stack
и pivot
df.stack().reset_index(1, name='cols').pivot(columns='cols', values='level_1')
Out[131]:
cols 1 2 3
0 A B C
1 B C A
2 C A B
3 A B C
4 C A B
Ответ 2
Вы можете использовать argsort:
pd.DataFrame(df.columns.values[np.argsort(df.values)])
0 1 2
0 A B C
1 B C A
2 C A B
3 A B C
4 C A B
Ответ 3
вот один из способов стека
df.stack().reset_index(level=1).set_index(0,append=True)['level_1'].unstack()
Out[89]:
0 1 2 3
0 A B C
1 B C A
2 C A B
3 A B C
4 C A B
Ответ 4
Ваш первый пример может быть эффективно решен с помощью argsort
и индексации.
m = np.argsort(df.to_numpy(), 1)
df.columns.to_numpy()[m]
array([['A', 'B', 'C'],
['B', 'C', 'A'],
['C', 'A', 'B'],
['A', 'B', 'C'],
['C', 'A', 'B']], dtype=object)
Второй пример немного хитрый, но все же та же идея, я скоро обновлю.
Ответ 5
Другой способ:
df = pd.DataFrame({
'A': [1, 3, 2, 1, 2],
'B': [2, 1, 3, 2, 3],
'C': [3, 2, 1, 2, 1],
})
(df.stack()
.reset_index()
.groupby(['level_0',0])
.level_1.apply(''.join)
.unstack()
)
Выход:
0 1 2 3
level_0
0 A B C
1 B C A
2 C A B
3 A BC NaN
4 C A B