python - index - pandas dataframe tutorial
Pandas DataFrames con comparaciĆ³n de igualdad NaNs (5)
En el contexto de la prueba unitaria de algunas funciones, estoy tratando de establecer la igualdad de 2 DataFrames usando pandas python:
ipdb> expect
1 2
2012-01-01 00:00:00+00:00 NaN 3
2013-05-14 12:00:00+00:00 3 NaN
ipdb> df
identifier 1 2
timestamp
2012-01-01 00:00:00+00:00 NaN 3
2013-05-14 12:00:00+00:00 3 NaN
ipdb> df[1][0]
nan
ipdb> df[1][0], expect[1][0]
(nan, nan)
ipdb> df[1][0] == expect[1][0]
False
ipdb> df[1][1] == expect[1][1]
True
ipdb> type(df[1][0])
<type ''numpy.float64''>
ipdb> type(expect[1][0])
<type ''numpy.float64''>
ipdb> (list(df[1]), list(expect[1]))
([nan, 3.0], [nan, 3.0])
ipdb> df1, df2 = (list(df[1]), list(expect[1])) ;; df1 == df2
False
Dado que estoy tratando de probar todo lo expect
contra todo df
, incluidas las posiciones de NaN
, ¿qué estoy haciendo mal?
¿Cuál es la forma más sencilla de comparar la igualdad de Series / DataFrames incluyendo NaN
s?
Cualquier comparación de igualdad utilizando == con np.NaN es False, incluso np.NaN == np.NaN es False.
Simplemente, df1.fillna(''NULL'') == df2.fillna(''NULL'')
, si ''NULL'' no es un valor en los datos originales.
Para estar seguro, haga lo siguiente:
Ejemplo a) Compara dos marcos de datos con valores de NaN
bools = (df1 == df2)
bools[pd.isnull(df1) & pd.isnull(df2)] = True
assert bools.all().all()
Ejemplo b) Filtrar filas en df1 que no coinciden con df2
bools = (df1 != df2)
bools[pd.isnull(df1) & pd.isnull(df2)] = False
df_outlier = df1[bools.all(axis=1)]
(Nota: esto es incorrecto - bools [pd.isnull (df1) == pd.isnull (df2)] = False)
Me gusta la respuesta de @PhillipCloud, pero está más escrita
In [26]: df1 = DataFrame([[np.nan,1],[2,np.nan]])
In [27]: df2 = df1.copy()
Realmente son equivalentes.
In [28]: result = df1 == df2
In [29]: result[pd.isnull(df1) == pd.isnull(df2)] = True
In [30]: result
Out[30]:
0 1
0 True True
1 True True
Un nan en df2 que no existe en df1
In [31]: df2 = DataFrame([[np.nan,1],[np.nan,np.nan]])
In [32]: result = df1 == df2
In [33]: result[pd.isnull(df1) == pd.isnull(df2)] = True
In [34]: result
Out[34]:
0 1
0 True True
1 False True
También puede rellenar con un valor que sepa que no está en el marco
In [38]: df1.fillna(-999) == df1.fillna(-999)
Out[38]:
0 1
0 True True
1 True True
Puede usar assert_frame_equals con check_names = False (para no verificar los nombres de los índices / columnas), que aparecerán si no son iguales:
In [11]: from pandas.util.testing import assert_frame_equal
In [12]: assert_frame_equal(df, expected, check_names=False)
Puedes envolver esto en una función con algo como:
try:
assert_frame_equal(df, expected, check_names=False)
return True
except AssertionError:
return False
En pandas más recientes, esta funcionalidad se ha agregado como .equals
:
df.equals(expected)
Una de las propiedades de NaN
es que NaN != NaN
es True
.
Echa un vistazo a esta respuesta para una buena manera de hacerlo usando numexpr
.
(a == b) | ((a != a) & (b != b))
Dice esto (en pseudocódigo):
a == b or (isnan(a) and isnan(b))
Entonces, o a
es igual a b
, o ambos a
y b
son NaN
.
Si tiene marcos pequeños, entonces assert_frame_equal
estará bien. Sin embargo, para cuadros grandes (10M filas) assert_frame_equal
es bastante inútil. Tuve que interrumpirlo, estaba tardando tanto.
In [1]: df = DataFrame(rand(1e7, 15))
In [2]: df = df[df > 0.5]
In [3]: df2 = df.copy()
In [4]: df
Out[4]:
<class ''pandas.core.frame.DataFrame''>
Int64Index: 10000000 entries, 0 to 9999999
Columns: 15 entries, 0 to 14
dtypes: float64(15)
In [5]: timeit (df == df2) | ((df != df) & (df2 != df2))
1 loops, best of 3: 598 ms per loop
timeit
del bool
único (probablemente) deseado que indica si los dos DataFrame
s son iguales:
In [9]: timeit ((df == df2) | ((df != df) & (df2 != df2))).values.all()
1 loops, best of 3: 687 ms per loop
df.fillna(0) == df2.fillna(0)
Puedes usar fillna()
. Documenación aquí .
from pandas import DataFrame
# create a dataframe with NaNs
df = DataFrame([{''a'': 1, ''b'': 2}, {''a'': 5, ''b'': 10, ''c'': 20}])
df2 = df
# comparison fails!
print df == df2
# all is well
print df.fillna(0) == df2.fillna(0)