¿Cómo eliminar celdas duplicadas de cada fila, considerando cada fila por separado (y quizás reemplazarlas con NaN) en un marco de datos de Pandas?
Sería aún mejor si pudiéramos cambiar todos los NaN recién creados al final de cada fila.
Publicaciones sobre cómo eliminar filas enteras que se consideran duplicadas:
Publicar sobre cómo eliminar duplicados de una lista que está en una columna de Pandas :
La respuesta dada aquí devuelve una serie de cadenas, no un marco de datos.
import pandas as pdVamos a crear un marco de datos:
df = pd.DataFrame({'a': ['A', 'A', 'C', 'B'], 'b': ['B', 'D', 'B', 'B'], 'c': ['C', 'C', 'C', 'A'], 'd': ['D', 'D', 'B', 'A']}, index=[0, 1, 2, 3]) df creado:
+----+-----+-----+-----+-----+ | | a | b | c | d | |----+-----+-----+-----+-----| | 0 | A | B | C | D | | 1 | A | D | C | D | | 2 | C | B | C | B | | 3 | B | B | A | A | +----+-----+-----+-----+-----+(Impreso usando este .)
Una forma de eliminar duplicados de cada fila, considerando cada fila por separado:
df = df.apply(lambda row: pd.Series(row).drop_duplicates(keep='first'),axis='columns')usando apply() , una función lambda , pd.Series() y Series.drop_duplicates() .
Empuje todos los NaN al final de cada fila, usando Shift NaN al final de sus respectivas filas :
df.apply(lambda x : pd.Series(x[x.notnull()].values.tolist()+x[x.isnull()].values.tolist()),axis='columns')Producción:
+----+-----+-----+-----+-----+ | | 0 | 1 | 2 | 3 | |----+-----+-----+-----+-----| | 0 | A | B | C | D | | 1 | A | D | C | nan | | 2 | C | B | nan | nan | | 3 | B | A | nan | nan | +----+-----+-----+-----+-----+Tal como deseábamos.
¿Hay una manera más eficiente de hacer esto? ¿Quizás con algunas funciones integradas de Pandas?
Puede buscar duplicados en el eje de la row y luego ordenar los resultados para "empujar" el Nan al final de las filas clasificándolos con una clave específica:
duplicates = df.apply(pd.Series.duplicated, axis=1) df.where(~duplicates, np.nan).apply(lambda x: pd.Series(sorted(x, key=pd.isnull)), axis=1)Producción
| 0 | 1 | 2 | 3 | |:----|:----|:----|:----| | A | B | C | D | | A | D | C | NaN | | C | B | NaN | NaN | | B | A | NaN | NaN |intenta algo nuevo
df = pd.DataFrame(list(map(pd.unique, df.values))) Out[447]: 0 1 2 3 0 ABCD 1 ADC None 2 CB None None 3 BA None NoneUse apply y construya un nuevo marco de datos mediante pd.DataFrame.from_dict con la opción orient='index'
df_final = pd.DataFrame.from_dict(df.apply(lambda x: x.drop_duplicates().tolist(), axis=1).to_dict(), orient='index') Out[268]: 0 1 2 3 0 ABCD 1 ADC None 2 CB None None 3 BA None None Nota: None prácticamente es similar a NaN . Si desea NaN exacto. Simplemente encadene .fillna adicional .fillna(np.nan)
Aplique pd.Series.unique en cada fila, extraiga el resultado y vuelva a construir el marco de datos:
print (pd.DataFrame(df.apply(pd.Series.unique, axis=1).tolist())) 0 1 2 3 0 ABCD 1 ADC None 2 CB None None 3 BA None None