【问题标题】:Applying a function to a MultiIndex pandas.DataFrame column将函数应用于 MultiIndex pandas.DataFrame 列
【发布时间】:2014-05-20 22:05:14
【问题描述】:

我有一个 MultiIndex pandas DataFrame,我想在其中将一个函数应用到它的一列并将结果分配给同一列。

In [1]:
    import numpy as np
    import pandas as pd
    cols = ['One', 'Two', 'Three', 'Four', 'Five']
    df = pd.DataFrame(np.array(list('ABCDEFGHIJKLMNO'), dtype='object').reshape(3,5), index = list('ABC'), columns=cols)
    df.to_hdf('/tmp/test.h5', 'df')
    df = pd.read_hdf('/tmp/test.h5', 'df')
    df
Out[1]:
         One     Two     Three  Four    Five
    A    A       B       C      D       E
    B    F       G       H      I       J
    C    K       L       M      N       O
    3 rows × 5 columns

In [2]:
    df.columns = pd.MultiIndex.from_arrays([list('UUULL'), ['One', 'Two', 'Three', 'Four', 'Five']])
    df['L']['Five'] = df['L']['Five'].apply(lambda x: x.lower())
    df
-c:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead 
Out[2]:
         U                      L
         One    Two     Three   Four    Five
    A    A      B       C       D       E
    B    F      G       H       I       J
    C    K      L       M       N       O
    3 rows × 5 columns

In [3]:
    df.columns = ['One', 'Two', 'Three', 'Four', 'Five']
    df    
Out[3]:
         One    Two     Three   Four    Five
    A    A      B       C       D       E
    B    F      G       H       I       J
    C    K      L       M       N       O
    3 rows × 5 columns

In [4]:
    df['Five'] = df['Five'].apply(lambda x: x.upper())
    df
Out[4]:
         One    Two     Three   Four    Five
    A    A      B       C       D       E
    B    F      G       H       I       J
    C    K      L       M       N       O
    3 rows × 5 columns

如您所见,该功能未应用于列,我猜是因为我收到此警告:

-c:2: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead

奇怪的是,这个错误只是偶尔发生,我一直无法理解它什么时候发生,什么时候不发生。

我设法使用.loc 对数据框进行切片的功能作为警告建议:

In [5]:
    df.columns = pd.MultiIndex.from_arrays([list('UUULL'), ['One', 'Two', 'Three', 'Four', 'Five']])
    df.loc[:,('L','Five')] = df.loc[:,('L','Five')].apply(lambda x: x.lower())
    df

Out[5]:
         U                      L
         One    Two     Three   Four    Five
    A    A      B       C       D       e
    B    F      G       H       I       j
    C    K      L       M       N       o
    3 rows × 5 columns

但我想了解为什么在进行类似 dict 的切片(例如 df['L']['Five'])而不是在使用 .loc 切片时会发生这种行为。

注意:DataFrame 来自未多索引的 HDF 文件,这可能是导致奇怪行为的原因吗?

编辑:我正在使用Pandas v.0.13.1NumPy v.1.8.0

【问题讨论】:

    标签: python pandas apply multi-index


    【解决方案1】:

    df['L']['Five'] 选择值为 'L' 的级别 0 并返回一个 DataFrame,然后选择列 'Five',返回访问的系列。

    Dataframe 的 __getitem__ 访问器([])将尝试做正确的事情,并为您提供正确的列。但是,这是链式索引,see here

    要访问多索引,请使用元组表示法,('a','b').loc,这是明确的,例如df.loc[:,('a','b')]。此外,这允许同时进行多轴索引(例如行和列)。

    那么,当您进行链式索引和分配时,为什么这不起作用,例如df['L']['Five'] = value.

    df['L'] 返回一个单索引的数据框。然后另一个 python 操作df_with_L['Five'] 会按“五”选择系列索引。我用另一个变量表示了这一点。因为 pandas 将这些操作视为单独的事件(例如,对 __getitem__ 的单独调用,所以它必须将它们视为线性操作,它们一个接一个地发生。

    将此与df.loc[:,('L','Five')] 进行对比,后者将(:,('L','Five')) 的嵌套元组传递给对__getitem__ 的单个调用。这允许 pandas 将其作为单个实体来处理(仅供参考,因为它可以直接索引到框架中)。

    为什么这很重要?由于链式索引是 2 次调用,因此任何一次调用都可能返回数据的副本,因为它被切片的方式。因此,在设置此选项时,您实际上是在设置副本,而不是原始帧。 pandas 不可能弄清楚这一点,因为它们是 2 个未连接的独立 python 操作。

    SettingWithCopy 警告是一种“启发式”来检测这种情况(这意味着它倾向于通过简单的轻量级检查来捕获大多数情况)。真正弄清楚这一点非常复杂。

    .loc 操作是单个 python 操作,因此可以选择一个切片(它仍然可能是一个副本),但允许 pandas 在修改后将该切片分配回帧中,从而根据您的设置设置值会想。

    警告的原因是这样的。有时,当您对数组进行切片时,您只会得到一个视图,这意味着您可以毫无问题地设置它。然而,即使是一个 single dtyped 数组也可以在以特定方式切片时生成一个副本。一个多类型的 DataFrame(意味着它有浮点数和对象数据),几乎总是会产生一个副本。是否创建视图取决于数组的内存布局。

    注意:这与数据的来源无关。

    【讨论】:

    • 我真的很喜欢这个解释......我知道我们在文档中有一个类似的,但这个散文更好。我们可以做一个pd.merge(orig_doc, this_explanation, how='right') 吗? :)
    猜你喜欢
    • 2021-02-12
    • 2017-02-10
    • 2017-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 2013-01-14
    相关资源
    最近更新 更多