我正在使用MultiIndexed pandas DataFrame,并希望将DataFrame的子集乘以一定数量.
它与此相同,但具有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
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但是,让我说我发现星期六的数字只是他们应该的一半!我想将所有sat销售额乘以2.
我的第一次尝试是:
sat = d.xs('sat', level='day')
sat = sat * 2
d.update(sat)
Run Code Online (Sandbox Code Playgroud)
但这不起作用,因为变量sat已经失去day了索引的级别:
>>> sat
sales
year flavour
2008 strawberry 20
banana 44
2009 strawberry 22
banana 46
Run Code Online (Sandbox Code Playgroud)
所以熊猫不知道如何将新的销售数据加入旧的数据框架.
我快速刺伤了:
>>> 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)
Run Code Online (Sandbox Code Playgroud)
我不知道这个错误意味着什么,但我觉得我正在用一个小山丘制造一座山.有谁知道这样做的正确方法?
罗伯,提前谢谢
And*_*den 11
注意:在即将发布的0.13中,xs已经添加了一个drop_level参数(感谢这个问题!):
In [42]: df.xs('sat', level='day', drop_level=False)
Out[42]:
sales
year flavour day
2008 strawberry sat 10
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用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)
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用申请:
In [21]: d.apply(lambda x: x*2 if x.name[2] == 'sat' else x, axis=1)
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用get_level_values (这可能是最有效的方法):
In [22]: d[d.index.get_level_values('day') == 'sat'] *= 2
Run Code Online (Sandbox Code Playgroud)
另一种选择是将"日"级别提升为列,然后使用"应用".
您可以使用.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
Run Code Online (Sandbox Code Playgroud)
此DataFrame在其索引中有3个级别,每个级别都有一个名称(year,flavour和day).这些级别也隐含地给出从外部以0开始的整数位置.因此,year级别可以被引用为0,flavourwith 1和dayas 2.
级别0是进行选择的最简单级别.例如,如果我们只想选择2008年,我们可以执行以下操作:
df.loc[2008]
sales
flavour day
strawberry sat 10
sun 12
banana sat 22
sun 23
Run Code Online (Sandbox Code Playgroud)
这会降低外部索引级别.如果要保留外层,可以将选择作为列表(或切片)传递:
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
Run Code Online (Sandbox Code Playgroud)
从0级以外的任何级别进行选择都比较复杂.我们首先选择像当年的特定组合2008,banana和sat.为此,您将组合作为元组传递给.loc:
df.loc[(2008, 'banana', 'sat')]
sales 22
Name: (2008, banana, sat), dtype: int64
Run Code Online (Sandbox Code Playgroud)
我总是使用如上所述的括号,但Python会自动将任何以逗号分隔的值集合解释为元组,因此以下内容将得到相同的结果:
df.loc[2008, 'banana', 'sat']
Run Code Online (Sandbox Code Playgroud)
所有级别都被删除,系列返回.我们可以通过将元组传递到列表中来保持级别:
df.loc[[(2008, 'banana', 'sat')]]
sales
year flavour day
2008 banana sat 22
Run Code Online (Sandbox Code Playgroud)
前面的示例从每个级别进行了单个选择.可以使用列表来包含所需级别的所有值.例如,如果我们想要选择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
Run Code Online (Sandbox Code Playgroud)
同样,您不必将整个选择包装在paraentheses中以表示元组,并且可以简单地执行:
df.loc[[2008, 2009], 'banana', ('sat','sun')]
Run Code Online (Sandbox Code Playgroud)
您可能希望从特定级别中选择所有值.例如,让我们尝试选择所有年份,所有口味和周六.您可能认为以下内容可行:
df.loc[:, :, 'sat']
Run Code Online (Sandbox Code Playgroud)
但是,这会遇到"索引器索引错误太多".有三种不同的方法可以从特定级别选择所有值.
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3519 次 |
| 最近记录: |