我正在使用MultiIndexed pandas DataFrame,并希望将DataFrame的子集乘以一定数量。
与this相同,但使用MultiIndex。
>>> 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
到目前为止,这么好。但是,让我说我发现星期六的数字只是他们应该的一半!我想将所有sat
销售额乘以2。
我的第一次尝试是:
sat = d.xs('sat', level='day')
sat = sat * 2
d.update(sat)
但这不起作用,因为变量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)
我不知道那个错误意味着什么,但我觉得我正在用一个小山丘制造一座山。有谁知道这样做的正确方法?
提前致谢, 罗布
答案 0 :(得分:11)
注意:即将发布0.13 a drop_level
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(它提取相同数据的子DataFrame(副本),即它具有相同的索引,因此可以正确更新):
In [11]: d.select(lambda x: x[2] == 'sat') * 2
Out[11]:
sales
year flavour day
2008 strawberry sat 20
banana sat 44
2009 strawberry sat 22
banana sat 46
In [12]: d.update(d.select(lambda x: x[2] == 'sat') * 2)
另一个选项是使用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
另一个选项是将“日”级别提升为列,然后使用“应用”。
答案 1 :(得分:6)
您可以使用.loc
索引器从具有MultiIndex的DataFrame中选择数据子集。假设我们有原始问题的数据:
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
此DataFrame的索引中有3个级别,每个级别都有一个名称(year
,flavour
和day
)。这些级别也隐含地给出从外部以0开始的整数位置。因此,year
级别可以引用为0
,flavour
引用1
,day
引用2
。
级别0
是进行选择的最简单级别。例如,如果我们想仅选择2008年,我们可以执行以下操作:
df.loc[2008]
sales
flavour day
strawberry sat 10
sun 12
banana sat 22
sun 23
这会降低外部索引级别。如果你想保持外层,你可以将你的选择作为列表(或切片)传递:
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级以外的任何级别进行选择都比较复杂。我们首先选择特定组合,例如年2008
,banana
和sat
。为此,您将组合作为元组传递给.loc
:
df.loc[(2008, 'banana', 'sat')]
sales 22
Name: (2008, banana, sat), dtype: int64
我总是使用如上所述的括号,但Python会自动将任何以逗号分隔的值集合解释为元组,因此以下内容将得到相同的结果:
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
同样,你不必将整个选择包装在paraentheses中以表示一个元组,并且可以简单地执行:
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