python pandas

python - Convertir valores en columnas



pandas (5)

Disculpas por el vago nombre de la pregunta, pero no estoy realmente seguro de cómo llamar a esta operación.

Tengo el siguiente marco de datos:

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

Estos datos representan una "clasificación" de cada una de las opciones, A , B y C para cada fila. Entonces, por ejemplo, en la fila 2 , C fue el mejor, luego A , luego B Me gustaría construir el marco de datos "invertido", donde, para cada fila, tengo tres columnas para la posición 1 , 2 y 3 de la clasificación, siendo A , B y C los datos. Entonces, para el ejemplo anterior, el resultado sería:

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

Idealmente, cada fila en df debería tener los tres valores distintos 1 , 2 y 3 , pero puede haber casos con valores repetidos (los valores fuera de ese rango no necesitan ser considerados). Si es posible, me gustaría resolver esto "concatenando" los nombres de las opciones en la misma posición y teniendo cadenas vacías o NaN en las posiciones faltantes. Por ejemplo, con esta entrada:

df_bad = pd.DataFrame({''A'': [1], ''B'': [2], ''C'': [2]}) print(df_bad) # A B C # 0 1 2 2

Idealmente, me gustaría obtener esta salida:

out_bad = pd.DataFrame({1: [''A''], 2: [''BC''], 3: ['''']}) print(out_bad) # 1 2 3 # 0 A BC

Alternativamente, podría conformarme con obtener uno de los valores en lugar de la concatenación.

He estado buscando a través de melt , pivot , pivot_table y otras funciones, pero no puedo encontrar la manera de obtener el resultado que quiero.


De otra manera:

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() )

Salida:

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


Puedes usar 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


Su primer ejemplo se puede resolver de manera eficiente con argsort e indexación.

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)

El segundo ejemplo es un poco complicado, pero sigue siendo la misma idea, actualizaré en breve.


aquí hay una stack ida

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


para casos de clasificación duplicados, como el segundo ejemplo, cualquier solución que utilice pivot y unstack en el último paso fallará. Necesita pivot_table o crosstab pivot_table crosstab . Como ya descubriste la solución usando pivot_table . Aquí está la 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

Usar stack y 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