web-dev-qa-db-ja.com

列の名前を変更した後、キーエラーが発生する

私は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

次に、最初の値の名前を this に変更します。

df.columns.values[0] = 'f'

すべてがとてもいいようです:

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']

bを選択すると、正常に動作します。

print (df['b'])
0    1
1    3
2    5
Name: b, dtype: int64

ただし、aを選択すると、列fが返されます。

print (df['a'])
0    7
1    8
2    9
Name: f, dtype: int64

fを選択すると、キーエラーが発生します。

print (df['f'])
#KeyError: 'f'

print (df.info())
#KeyError: 'f'

問題は何ですか?誰かがそれを説明できますか?それともバグ?

13
jezrael

values属性を変更することは想定されていません。

df.columns.values = ['a', 'b', 'c']を試してみてください:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-61-e7e440adc404> in <module>()
----> 1 df.columns.values = ['a', 'b', 'c']

AttributeError: can't set attribute

これは、属性を設定しようとしていることをpandasが検出して停止したためです。

ただし、基になるvaluesオブジェクト自体を変更することはできます。

renameを使用すると、pandasが一連のクリーンアップ処理を実行します。以下のソースを貼り付けました。

最終的には、クリーンアップを開始せずに値を変更します。 _data.rename_axisへのフォローアップコールで自分で開始できます(例は下のソースで確認できます)。これによりクリーンアップが強制的に実行され、['f']にアクセスできます

df._data = df._data.rename_axis(lambda x: x, 0, True)
df['f']

0    7
1    8
2    9
Name: f, dtype: int64

話の教訓:この方法で列の名前を変更することは、おそらく良い考えではありません。


しかし、この話は奇妙になります

これでいい

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

これはnotで結構です

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:

結局のところ、valuesを表示する前にdf属性を変更すると、最初のdisplayですべての初期化が実行されるようです。 values属性を変更する前に表示すると、エラーになります。

奇妙な静止画

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

これが悪い考えであることをまだ知らなかったかのように...


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)
18
piRSquared