pandas valores únicos columnas múltiples

134
df = pd.DataFrame({'Col1': ['Bob', 'Joe', 'Bill', 'Mary', 'Joe'],
                   'Col2': ['Joe', 'Steve', 'Bob', 'Bob', 'Steve'],
                   'Col3': np.random.random(5)})

¿Cuál es la mejor manera de devolver los valores únicos de 'Col1' y 'Col2'?

La salida deseada es

'Bob', 'Joe', 'Bill', 'Mary', 'Steve'
usuario2333196
fuente
3
Vea también combinaciones únicas de valores en columnas seleccionadas en el marco de datos de pandas y cuente para una pregunta diferente pero relacionada. La respuesta seleccionada allí usadf1.groupby(['A','B']).size().reset_index().rename(columns={0:'count'})
Paul Rougieux

Respuestas:

198

pd.unique devuelve los valores únicos de una matriz de entrada, o columna o índice de DataFrame.

La entrada a esta función debe ser unidimensional, por lo que será necesario combinar varias columnas. La forma más simple es seleccionar las columnas que desee y luego ver los valores en una matriz NumPy aplanada. Toda la operación se ve así:

>>> pd.unique(df[['Col1', 'Col2']].values.ravel('K'))
array(['Bob', 'Joe', 'Bill', 'Mary', 'Steve'], dtype=object)

Tenga en cuenta que ravel()es un método de matriz que devuelve una vista (si es posible) de una matriz multidimensional. El argumento 'K'le dice al método que aplaste la matriz en el orden en que los elementos se almacenan en la memoria (los pandas generalmente almacenan las matrices subyacentes en orden contiguo a Fortran ; columnas antes de filas). Esto puede ser significativamente más rápido que usar el orden predeterminado 'C' del método.


Una forma alternativa es seleccionar las columnas y pasarlas a np.unique:

>>> np.unique(df[['Col1', 'Col2']].values)
array(['Bill', 'Bob', 'Joe', 'Mary', 'Steve'], dtype=object)

No es necesario usar ravel()aquí ya que el método maneja matrices multidimensionales. Aun así, es probable que sea más lento que pd.uniquecuando utiliza un algoritmo basado en clasificación en lugar de una tabla hash para identificar valores únicos.

La diferencia de velocidad es significativa para los marcos de datos más grandes (especialmente si solo hay un puñado de valores únicos):

>>> df1 = pd.concat([df]*100000, ignore_index=True) # DataFrame with 500000 rows
>>> %timeit np.unique(df1[['Col1', 'Col2']].values)
1 loop, best of 3: 1.12 s per loop

>>> %timeit pd.unique(df1[['Col1', 'Col2']].values.ravel('K'))
10 loops, best of 3: 38.9 ms per loop

>>> %timeit pd.unique(df1[['Col1', 'Col2']].values.ravel()) # ravel using C order
10 loops, best of 3: 49.9 ms per loop
Alex Riley
fuente
2
¿Cómo se recupera un marco de datos en lugar de una matriz?
Lisle
1
@Lisle: ambos métodos devolver una matriz NumPy, por lo que tiene que construir de forma manual, por ejemplo, pd.DataFrame(unique_values). No hay una buena manera de recuperar un DataFrame directamente.
Alex Riley
@Lisle ya que ha usado pd.unique, devuelve un numpy.ndarray como salida final. ¿Es esto lo que estabas preguntando?
Ash Upadhyay
1
@Lisle, ¿quizás este df = df.drop_duplicates (subconjunto = ['C1', 'C2', 'C3'])?
patata cosquillas
14

He configurado un DataFramecon algunas cadenas simples en sus columnas:

>>> df
   a  b
0  a  g
1  b  h
2  d  a
3  e  e

Puede concatenar las columnas que le interesan y llamar a la uniquefunción:

>>> pandas.concat([df['a'], df['b']]).unique()
array(['a', 'b', 'd', 'e', 'g', 'h'], dtype=object)
Miguel
fuente
7
In [5]: set(df.Col1).union(set(df.Col2))
Out[5]: {'Bill', 'Bob', 'Joe', 'Mary', 'Steve'}

O:

set(df.Col1) | set(df.Col2)
James Little
fuente
1

No pandassolución: usando set ().

import pandas as pd
import numpy as np

df = pd.DataFrame({'Col1' : ['Bob', 'Joe', 'Bill', 'Mary', 'Joe'],
              'Col2' : ['Joe', 'Steve', 'Bob', 'Bob', 'Steve'],
               'Col3' : np.random.random(5)})

print df

print set(df.Col1.append(df.Col2).values)

Salida:

   Col1   Col2      Col3
0   Bob    Joe  0.201079
1   Joe  Steve  0.703279
2  Bill    Bob  0.722724
3  Mary    Bob  0.093912
4   Joe  Steve  0.766027
set(['Steve', 'Bob', 'Bill', 'Joe', 'Mary'])
NullDev
fuente
1

para aquellos de nosotros que amamos todas las cosas pandas, aplicamos y, por supuesto, las funciones lambda:

df['Col3'] = df[['Col1', 'Col2']].apply(lambda x: ''.join(x), axis=1)
Lisle
fuente
1

aquí hay otra manera


import numpy as np
set(np.concatenate(df.values))
muon
fuente
0
list(set(df[['Col1', 'Col2']].as_matrix().reshape((1,-1)).tolist()[0]))

La salida será ['Mary', 'Joe', 'Steve', 'Bob', 'Bill']

smishra
fuente