pandas - name - Después de cambiar el nombre de la columna, obtenga keyerror
pandas subset (1)
Tengo
df
:
df = pd.DataFrame({''a'':[7,8,9],
''b'':[1,3,5],
''c'':[5,3,6]})
print (df)
a b c
0 7 1 5
1 8 3 3
2 9 5 6
Luego cambie el nombre del primer valor por this :
df.columns.values[0] = ''f''
Todo parece muy lindo:
print (df)
f b c
0 7 1 5
1 8 3 3
2 9 5 6
print (df.columns)
Index([''f'', ''b'', ''c''], dtype=''object'')
print (df.columns.values)
[''f'' ''b'' ''c'']
Si selecciona
b
funciona bien:
print (df[''b''])
0 1
1 3
2 5
Name: b, dtype: int64
Pero si selecciona
a
columna de retorno
f
:
print (df[''a''])
0 7
1 8
2 9
Name: f, dtype: int64
Y si selecciona
f
obtenga keyerror.
print (df[''f''])
#KeyError: ''f''
print (df.info())
#KeyError: ''f''
¿Cual es el problema? ¿Alguien puede explicarlo? O error?
No se espera que altere el atributo de
values
.
Pruebe
df.columns.values = [''a'', ''b'', ''c'']
y obtendrá:
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-61-e7e440adc404> in <module>() ----> 1 df.columns.values = [''a'', ''b'', ''c''] AttributeError: can''t set attribute
Esto se debe a que los
pandas
detectan que estás intentando establecer el atributo y te detienen.
Sin embargo, no puede impedir que cambie los objetos de
values
subyacentes en sí.
Cuando usas
rename
, los
pandas
siguen con un montón de cosas de limpieza.
He pegado la fuente a continuación.
En última instancia, lo que ha hecho es alterar los valores sin iniciar la limpieza.
Puede iniciarlo usted mismo con una llamada de seguimiento a
_data.rename_axis
(puede ver el ejemplo en la fuente a continuación).
Esto obligará a ejecutar la limpieza y luego podrá acceder a
[''f'']
df._data = df._data.rename_axis(lambda x: x, 0, True)
df[''f'']
0 7
1 8
2 9
Name: f, dtype: int64
Moraleja de la historia: probablemente no sea una buena idea cambiar el nombre de una columna de esta manera.
pero esta historia se vuelve más rara
Esto esta bien
df = pd.DataFrame({''a'':[7,8,9],
''b'':[1,3,5],
''c'':[5,3,6]})
df.columns.values[0] = ''f''
df[''f'']
0 7
1 8
2 9
Name: f, dtype: int64
Esto no esta bien
df = pd.DataFrame({''a'':[7,8,9],
''b'':[1,3,5],
''c'':[5,3,6]})
print(df)
df.columns.values[0] = ''f''
df[''f'']
KeyError:
Resulta que podemos modificar el atributo de
values
antes de mostrar
df
y aparentemente ejecutará toda la inicialización en la primera
display
.
Si lo muestra antes de cambiar el atributo de
values
, se producirá un error.
aún más raro
df = pd.DataFrame({''a'':[7,8,9],
''b'':[1,3,5],
''c'':[5,3,6]})
print(df)
df.columns.values[0] = ''f''
df[''f''] = 1
df[''f'']
f f
0 7 1
1 8 1
2 9 1
Como si no supiéramos que era una mala idea ...
fuente para
rename
def rename(self, *args, **kwargs):
axes, kwargs = self._construct_axes_from_arguments(args, kwargs)
copy = kwargs.pop(''copy'', True)
inplace = kwargs.pop(''inplace'', False)
if kwargs:
raise TypeError(''rename() got an unexpected keyword ''
''argument "{0}"''.format(list(kwargs.keys())[0]))
if com._count_not_none(*axes.values()) == 0:
raise TypeError(''must pass an index to rename'')
# renamer function if passed a dict
def _get_rename_function(mapper):
if isinstance(mapper, (dict, ABCSeries)):
def f(x):
if x in mapper:
return mapper[x]
else:
return x
else:
f = mapper
return f
self._consolidate_inplace()
result = self if inplace else self.copy(deep=copy)
# start in the axis order to eliminate too many copies
for axis in lrange(self._AXIS_LEN):
v = axes.get(self._AXIS_NAMES[axis])
if v is None:
continue
f = _get_rename_function(v)
baxis = self._get_block_manager_axis(axis)
result._data = result._data.rename_axis(f, axis=baxis, copy=copy)
result._clear_item_cache()
if inplace:
self._update_inplace(result._data)
else:
return result.__finalize__(self)