Estoy tratando de hacer algunas comparaciones en un DataFrame de pandas.

# create simple DataFrame
df = pd.DataFrame(['one', 'two', 'three'], range(1,4), columns=['col1'])
#df:
#    col1
#1    one
#2    two
#3  three

# assign one col1 value to be NAN
df.loc[1, 'col1'] = np.nan 
# this comparison works
print(df['col1'] == 'three')

# assign all col1 values to NAN
df.loc[:, 'col1'] = np.nan
# this comparison fails
print(df['col1'] == 'three')

La primera comparación (con solo un valor NAN en la columna) funciona como se esperaba, pero la segunda (con todos los valores NAN en la columna) produce este error: TypeError: invalid type comparison

¿Qué está pasando aquí?

Vi esta pregunta, lo que sugiere algunas posibles pero un poco hack-y soluciones a este problema.

Pero, ¿por qué es este el comportamiento que ocurre en primer lugar? ¿Es útil esta restricción, de alguna manera? Puedo solucionarlo usando df.fillna('') antes de mis comparaciones, pero esto parece torpe e irritante.

Entonces mis preguntas son:
1. ¿Cuál es la forma más limpia de solucionar este problema?
2. ¿Por qué es este el comportamiento predeterminado, de todos modos?

3
J Jones 12 may. 2016 a las 02:44

3 respuestas

La mejor respuesta

Su col1 es del tipo float después de asignar todos np.nan, por lo que intentar compararlo con un string arroja un TypeError. :

df = pd.DataFrame(['one', 'two', 'three'], range(1, 4), columns=['col1'])
df.loc[1, 'col1'] = np.nan

    col1
1    NaN
2    two
3  three

La asignación de un solo np.nan a una columna que contiene valores string deja el objeto dtype:

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 1 to 3
Data columns (total 1 columns):
col1    2 non-null object
dtypes: object(1)

Pero todos los valores de np.nan se convierten en float:

df.loc[:, 'col1'] = np.nan
df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3 entries, 1 to 3
Data columns (total 1 columns):
col1    0 non-null float64
dtypes: float64(1)
2
Stefan 11 may. 2016 a las 23:54

Si hubieras hecho:

# assign all col1 values to None
df.loc[:, 'col1'] = None

Entonces

# this comparison does not fail
print df['col1'] == 'three'

1    False
2    False
3    False
Name: col1, dtype: bool
0
piRSquared 12 may. 2016 a las 00:33

El problema se puede resolver utilizando el indexador ix en lugar de iloc, en cuyo caso no se cambia el tipo de datos de la serie (no estoy seguro de por qué, presumiblemente ambos tipos de indexadores deberían tener un comportamiento consistente , mi preferencia sería cambiar iloc para que coincida con ix):

>>> df = pd.DataFrame(['one', 'two', 'three'], range(1,4), columns=['col1'])
>>> df['col1'].ix[:] = np.nan
>>> df.dtypes

col1    object
dtype: object
1
maxymoo 12 may. 2016 a las 01:27