Condensar el dataframe de los pandas eliminando los elementos que faltan

Problema

Tengo un dataframe que se ve así:

Key Var ID_1 Var_1 ID_2 Var_2 ID_3 Var_3 1 True 1.0 True NaN NaN 5.0 True 2 True NaN NaN 4.0 False 7.0 True 3 False 2.0 False 5.0 True NaN NaN 

Cada fila tiene exactamente 2 conjuntos de datos que no son nulos (ID / Var), y se garantiza que el tercero restante es nulo. Lo que quiero hacer es “condensar” el dataframe eliminando los elementos que faltan.

Salida deseada

 Key Var First_ID First_Var Second_ID Second_Var 1 True 1 True 5 True 2 True 4 False 7 True 3 False 2 False 5 True 

El orden no es importante, siempre que se mantengan los pares Id / Var.


Solución actual

A continuación se muestra una solución de trabajo que tengo:

 import pandas as pd import numpy as np data = pd.DataFrame({'Key': [1, 2, 3], 'Var': [True, True, False], 'ID_1':[1, np.NaN, 2], 'Var_1': [True, np.NaN, False], 'ID_2': [np.NaN, 4, 5], 'Var_2': [np.NaN, False, True], 'ID_3': [5, 7, np.NaN], 'Var_3': [True, True, np.NaN]}) sorted_columns = ['Key', 'Var', 'ID_1', 'Var_1', 'ID_2', 'Var_2', 'ID_3', 'Var_3'] data = data[sorted_columns] output = np.empty(shape=[data.shape[0], 6], dtype=str) for i, *row in data.itertuples(): output[i] = [element for element in row if np.isfinite(element)] print(output) [['1' 'T' '1' 'T' '5' 'T'] ['2' 'T' '4' 'F' '7' 'T'] ['3' 'F' '2' 'F' '5' 'T']] 

Esto es aceptable, pero no ideal. Puedo vivir sin tener los nombres de las columnas, pero mi gran problema es tener que convertir los datos dentro de la matriz en una cadena para evitar que mis valores booleanos se conviertan en numéricos.

¿Existen otras soluciones que hagan un mejor trabajo para preservar los datos? Puntos de bonificación si el resultado es un dataframe de pandas.

Hay una solución simple, es decir, empujar los nans a la derecha y soltar los nans en el eje 1. Es decir

 ndf = data.apply(lambda x : sorted(x,key=pd.isnull),1).dropna(1) 

Salida:

   Clave Var ID ID_1 Var_1 ID_2 Var_2
 0 1 True 1 True 5 True
 1 2 Verdadero 4 Falso 7 Verdadero
 2 3 Falso 2 Falso 5 Verdadero

Espero eso ayude.

Una solución numpy de Divakar aquí para una velocidad 10x, es decir

 def mask_app(a): out = np.full(a.shape,np.nan,dtype=a.dtype) mask = ~np.isnan(a.astype(float)) out[np.sort(mask,1)[:,::-1]] = a[mask] return out ndf = pd.DataFrame(mask_app(data.values),columns=data.columns).dropna(1) 
   Clave Var ID ID_1 Var_1 ID_2 Var_2
 0 1 True 1 True 5 True
 1 2 Verdadero 4 Falso 7 Verdadero
 2 3 Falso 2 Falso 5 Verdadero