如何更新多索引Pandas数据帧的子集

2024-06-16 13:10:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用一个多索引的pandas数据帧,并希望将数据帧的一个子集乘以一定的数字。在

它与this相同,但有一个多重索引。在

>>> d = pd.DataFrame({'year':[2008,2008,2008,2008,2009,2009,2009,2009], 
                      'flavour':['strawberry','strawberry','banana','banana',
                      'strawberry','strawberry','banana','banana'],
                      'day':['sat','sun','sat','sun','sat','sun','sat','sun'],
                      'sales':[10,12,22,23,11,13,23,24]})

>>> d = d.set_index(['year','flavour','day'])                  

>>> d
                     sales
year flavour    day       
2008 strawberry sat     10
                sun     12
     banana     sat     22
                sun     23
2009 strawberry sat     11
                sun     13
     banana     sat     23
                sun     24

到目前为止,还不错。不过,我发现所有周六的数据都只有应有的一半!我想把所有的销售额乘以2。在

我的第一次尝试是:

^{pr2}$

但这不起作用,因为变量sat失去了索引的day级别:

>>> sat
                 sales
year flavour          
2008 strawberry     20
     banana         44
2009 strawberry     22
     banana         46

所以熊猫不知道如何将新的销售数据加入到旧的数据框中。在

我很快就想:

>>> sat = d.xs('sat', level='day', copy=False)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\site-packages\pandas\core\frame.py", line 2248, in xs
    raise ValueError('Cannot retrieve view (copy=False)')
ValueError: Cannot retrieve view (copy=False)

我不知道那个错误意味着什么,但我觉得我是小题大做。有人知道正确的方法吗?在

提前谢谢你, 罗布


Tags: 数据falsepandaslineyearsatfilesun
2条回答

详细的多索引说明

您可以使用.loc索引器从具有多重索引的数据帧中选择数据子集。假设我们有原始问题的数据:

                     sales
year flavour    day       
2008 strawberry sat     10
                sun     12
     banana     sat     22
                sun     23
2009 strawberry sat     11
                sun     13
     banana     sat     23
                sun     24

这个数据帧在其索引中有3个级别,每个级别都有一个名称(yearflavour和{})。级别还隐式地从外部给定以0开头的整数位置。因此,year级别可以被引用为0flavour和{},而{}可以作为2。在

从0级选择-最外层

级别0是最容易进行选择的级别。例如,如果我们只想选择2008年,我们可以执行以下操作:

^{pr2}$

这会降低外部索引级别。如果要保持外部级别,可以将选择作为列表(或切片)传递:

df.loc[[2008]]  # df.loc[2008:2008] gets the same result

                     sales
year flavour    day       
2008 strawberry sat     10
                sun     12
     banana     sat     22
                sun     23

从其他级别进行选择

从级别0以外的任何级别进行选择更为复杂。让我们首先选择一个特定的组合,比如年份2008banana和{}。为此,将组合作为元组传递给.loc

df.loc[(2008, 'banana', 'sat')]

sales    22
Name: (2008, banana, sat), dtype: int64

我总是像上面那样使用括号,但是Python会自动将任何逗号分隔的值集解释为tuple,因此下面的结果将相同:

df.loc[2008, 'banana', 'sat']

所有的级别都被降低了,一系列的数据被返回。我们可以通过在列表中传递元组来保持级别:

df.loc[[(2008, 'banana', 'sat')]]

                  sales
year flavour day       
2008 banana  sat     22

从特定级别选择多个值

上一个示例从每个级别进行了单个选择。可以使用列表来包含所需级别的所有值。例如,如果我们想选择2008年和2009年的所有行,带有香蕉味,周六和周日,我们可以执行以下操作:

df.loc[([2008, 2009], 'banana', ('sat','sun'))]

                  sales
year flavour day       
2008 banana  sat     22
             sun     23
2009 banana  sat     23
             sun     24

同样,您不必用paraenthes包装整个选择来表示元组,只需执行以下操作:

df.loc[[2008, 2009], 'banana', ('sat','sun')]

从特定级别选择所有值。

相反,您可能希望从特定级别选择所有值。例如,让我们试着选择所有年份、所有口味和周六。您可能认为以下方法可行:

df.loc[:, :, 'sat']

但是,这会遇到“太多索引器的索引器错误”。从特定级别选择所有值有三种不同的方法。在

  • df.loc[(slice(None), slice(None), 'sat'), :]
  • df.loc(axis=0)[:, :, 'sat']
  • df.loc[pd.IndexSlice[:, :, 'sat'], :]

三者都产生了以下结果:

                     sales
year flavour    day       
2008 strawberry sat     10
     banana     sat     22
2009 strawberry sat     11
     banana     sat     23

注意:在即将发布的0.13a ^{} argument has been added to xs感谢这个问题!):

In [42]: df.xs('sat', level='day', drop_level=False)
Out[42]:
                     sales
year flavour    day
2008 strawberry sat     10

另一个选项是使用select(它提取相同数据的子数据帧(副本),即它具有相同的索引,因此可以正确更新):

^{pr2}$

另一个选项是使用apply:

In [21]: d.apply(lambda x: x*2 if x.name[2] == 'sat' else x, axis=1)

另一个选择是使用get_level_values(这可能是其中最有效的方法):

In [22]: d[d.index.get_level_values('day') == 'sat'] *= 2

另一个选项是将“day”级别提升到列,然后使用apply。在

相关问题 更多 >