python - functions - pandas de pitón eliminan columnas duplicadas
python pandas download windows (4)
La transposición es ineficaz para grandes marcos de datos. Aquí hay una alternativa:
def duplicate_columns(frame):
groups = frame.columns.to_series().groupby(frame.dtypes).groups
dups = []
for t, v in groups.items():
dcols = frame[v].to_dict(orient="list")
vs = dcols.values()
ks = dcols.keys()
lvs = len(vs)
for i in range(lvs):
for j in range(i+1,lvs):
if vs[i] == vs[j]:
dups.append(ks[i])
break
return dups
Úselo así:
dups = duplicate_columns(frame)
frame = frame.drop(dups, axis=1)
Editar
Una versión de memoria eficiente que trata a nans como cualquier otro valor:
from pandas.core.common import array_equivalent
def duplicate_columns(frame):
groups = frame.columns.to_series().groupby(frame.dtypes).groups
dups = []
for t, v in groups.items():
cs = frame[v].columns
vs = frame[v]
lcs = len(cs)
for i in range(lcs):
ia = vs.iloc[:,i].values
for j in range(i+1, lcs):
ja = vs.iloc[:,j].values
if array_equivalent(ia, ja):
dups.append(cs[i])
break
return dups
¿Cuál es la forma más fácil de eliminar columnas duplicadas de un marco de datos?
Estoy leyendo un archivo de texto que tiene columnas duplicadas a través de:
import pandas as pd
df=pd.read_table(fname)
Los nombres de las columnas son:
Time, Time Relative, N2, Time, Time Relative, H2, etc...
Todas las columnas relativas de tiempo y tiempo contienen los mismos datos. Yo quiero:
Time, Time Relative, N2, H2
Todos mis intentos de eliminar, eliminar, etc., como:
df=df.T.drop_duplicates().T
Resultado en errores de índice con valores únicos:
Reindexing only valid with uniquely valued index objects
Perdón por ser un novato de Pandas. Cualquier sugerencia sera apreciada.
Detalles adicionales
Versión de Pandas: 0.9.0
Versión de Python: 2.7.3
Windows 7
(instalado a través de Pythonxy 2.7.3.0)
archivo de datos (nota: en el archivo real, las columnas están separadas por pestañas, aquí están separadas por 4 espacios):
Time Time Relative [s] N2[%] Time Time Relative [s] H2[ppm]
2/12/2013 9:20:55 AM 6.177 9.99268e+001 2/12/2013 9:20:55 AM 6.177 3.216293e-005
2/12/2013 9:21:06 AM 17.689 9.99296e+001 2/12/2013 9:21:06 AM 17.689 3.841667e-005
2/12/2013 9:21:18 AM 29.186 9.992954e+001 2/12/2013 9:21:18 AM 29.186 3.880365e-005
... etc ...
2/12/2013 2:12:44 PM 17515.269 9.991756+001 2/12/2013 2:12:44 PM 17515.269 2.800279e-005
2/12/2013 2:12:55 PM 17526.769 9.991754e+001 2/12/2013 2:12:55 PM 17526.769 2.880386e-005
2/12/2013 2:13:07 PM 17538.273 9.991797e+001 2/12/2013 2:13:07 PM 17538.273 3.131447e-005
Parece que ya conoce los nombres únicos de las columnas. Si ese es el caso, entonces df = df[''Time'', ''Time Relative'', ''N2'']
funcionaría.
Si no, tu solución debería funcionar:
In [101]: vals = np.random.randint(0,20, (4,3))
vals
Out[101]:
array([[ 3, 13, 0],
[ 1, 15, 14],
[14, 19, 14],
[19, 5, 1]])
In [106]: df = pd.DataFrame(np.hstack([vals, vals]), columns=[''Time'', ''H1'', ''N2'', ''Time Relative'', ''N2'', ''Time''] )
df
Out[106]:
Time H1 N2 Time Relative N2 Time
0 3 13 0 3 13 0
1 1 15 14 1 15 14
2 14 19 14 14 19 14
3 19 5 1 19 5 1
In [107]: df.T.drop_duplicates().T
Out[107]:
Time H1 N2
0 3 13 0
1 1 15 14
2 14 19 14
3 19 5 1
Probablemente tengas algo específico para tus datos que lo estropee. Podríamos brindarle más ayuda si hay más detalles que pueda brindarnos sobre los datos.
Edición: como dijo Andy, el problema probablemente sea con los títulos de columna duplicados.
Para un archivo de tabla de muestra ''dummy.csv'', inventé:
Time H1 N2 Time N2 Time Relative
3 13 13 3 13 0
1 15 15 1 15 14
14 19 19 14 19 14
19 5 5 19 5 1
el uso de read_table
da columnas únicas y funciona correctamente:
In [151]: df2 = pd.read_table(''dummy.csv'')
df2
Out[151]:
Time H1 N2 Time.1 N2.1 Time Relative
0 3 13 13 3 13 0
1 1 15 15 1 15 14
2 14 19 19 14 19 14
3 19 5 5 19 5 1
In [152]: df2.T.drop_duplicates().T
Out[152]:
Time H1 Time Relative
0 3 13 0
1 1 15 14
2 14 19 14
3 19 5 1
Si su versión no le permite, puede hackear juntos una solución para que sean únicos:
In [169]: df2 = pd.read_table(''dummy.csv'', header=None)
df2
Out[169]:
0 1 2 3 4 5
0 Time H1 N2 Time N2 Time Relative
1 3 13 13 3 13 0
2 1 15 15 1 15 14
3 14 19 19 14 19 14
4 19 5 5 19 5 1
In [171]: from collections import defaultdict
col_counts = defaultdict(int)
col_ix = df2.first_valid_index()
In [172]: cols = []
for col in df2.ix[col_ix]:
cnt = col_counts[col]
col_counts[col] += 1
suf = ''_'' + str(cnt) if cnt else ''''
cols.append(col + suf)
cols
Out[172]:
[''Time'', ''H1'', ''N2'', ''Time_1'', ''N2_1'', ''Time Relative'']
In [174]: df2.columns = cols
df2 = df2.drop([col_ix])
In [177]: df2
Out[177]:
Time H1 N2 Time_1 N2_1 Time Relative
1 3 13 13 3 13 0
2 1 15 15 1 15 14
3 14 19 19 14 19 14
4 19 5 5 19 5 1
In [178]: df2.T.drop_duplicates().T
Out[178]:
Time H1 Time Relative
1 3 13 0
2 1 15 14
3 14 19 14
4 19 5 1
Si no me equivoco, lo siguiente hace lo que se solicitó sin los problemas de memoria de la solución de transposición y con menos líneas que la función de @kalu, manteniendo la primera de las columnas con el mismo nombre.
Cols = list(df.columns)
for i,item in enumerate(df.columns):
if item in df.columns[:i]: Cols[i] = "toDROP"
df.columns = Cols
df = df.drop("toDROP",1)
Todo lo anterior parece ser un método innecesariamente pesado y tedioso: hay una solución de una sola línea para el problema. Esto se aplica si algunos nombres de columna están duplicados y desea eliminarlos:
df = df.loc[:,~df.columns.duplicated()]
[actualización] Cómo funciona:
Supongamos que las columnas del marco de datos son [''alpha'',''beta'',''alpha'']
df.columns.duplicated()
devuelve una matriz booleana: a True
o False
para cada columna. Si es False
, el nombre de la columna es único hasta ese punto; si es True
, el nombre de la columna se duplicará antes. Por ejemplo, usando el ejemplo dado, el valor devuelto sería [False,False,True]
.
Pandas
permite a uno indexar usando valores booleanos por lo que selecciona solo los valores True
. Como queremos mantener las columnas no duplicadas, necesitamos que la matriz booleana anterior sea volteada (es decir, [True, True, False] = ~[False,False,True]
)
Finalmente, df.loc[:,[True,True,False]]
selecciona solo las columnas no duplicadas utilizando la capacidad de indexación mencionada anteriormente.
Nota : lo anterior solo verifica los nombres de las columnas, no los valores de las columnas.