【问题标题】:Pandas MultiIndex slices and indexingPandas MultiIndex 切片和索引
【发布时间】:2018-12-29 16:41:42
【问题描述】:

我刚刚开始使用多帧,我在使用相当稀疏的文档和关于切片和索引的在线示例时遇到了一些麻烦。

考虑以下多帧

import pandas as pd
import numpy as np
levels={
'produce_source':['Vendor A', 'Vendor B'],
'day':['mon','wed','fri'],
'chiller_temp':['low','mid'],
'fruit':['apples','pears','nanas']
}

index = pd.MultiIndex.from_product(levels.values(), names = list(levels.keys()))
df = pd.DataFrame(index=index)
df = df.assign(deliveries=np.random.rand(len(df)))


                                        deliveries
produce_source day chiller_temp fruit             
Vendor A       mon low          apples    0.748376
                                pears     0.639824
                                nanas     0.604342
                   mid          apples    0.160837
                                pears     0.970412
                                nanas     0.301815
               wed low          apples    0.572627
                                pears     0.254242
                                nanas     0.590702
                   mid          apples    0.153772
                                pears     0.180117
                                nanas     0.858085
               fri low          apples    0.535358
                                pears     0.576359
                                nanas     0.893993
                   mid          apples    0.334602
                                pears     0.053892
                                nanas     0.778767
Vendor B       mon low          apples    0.565761
                                pears     0.437994
                                nanas     0.090994
                   mid          apples    0.261041
                                pears     0.028795
                                nanas     0.057612
               wed low          apples    0.808108
                                pears     0.914724
                                nanas     0.020663
                   mid          apples    0.055319
                                pears     0.888612
                                nanas     0.623370
               fri low          apples    0.419422
                                pears     0.938593
                                nanas     0.358441
                   mid          apples    0.534191
                                pears     0.590103
                                nanas     0.753034

实现以下最pythonic的方法是什么

1) 以切片的形式查看所有的 wed 数据

1a) 延伸目标:不关心 'day' 是 index.names[1],而是按索引名称 'day' 进行索引

2) 仅将可迭代的数据写入该 wed 切片

3) 为所有供应商、日子和水果添加一个 high 的 chiller_temp

我看到使用 idx = pd.IndexSlice 发生了一些切片。

idx = pd.IndexSlice
df_wip = df.loc[idx[:,'wed'], ] #1)  
#would love to write to df_wip sliced df here but get slice copy warning with df_wip['deliveries'] = list(range(0,100*len(df_wip),100)) 
df = df.loc[idx[:,'wed'],'deliveries'] = list(range(0,100*len(df_wip),100)) #2)

这会引发错误 AttributeError: 'list' object has no attribute 'loc'

df = df.loc[idx[:,'wed'],'deliveries'] = pd.Series(range(0,100*len(df_wip),100)) #2)

引发 TypeError: unhashable type: 'slice'

【问题讨论】:

  • 我在下面的回答是否符合您的要求?

标签: pandas multi-index


【解决方案1】:

1) 以切片的形式查看所有的 wed 数据

要查看多索引中的数据,使用 .xs(横截面)要容易得多,它允许您为特定索引级别指定值,而不是让您输入所有级别,例如 .loc w/ slice 将让你做:

df.xs('wed', level='day')

Out:
                                        deliveries
produce_source  chiller_temp    fruit   
Vendor A        low             apples  0.521861
                                pears   0.741856
                                nanas   0.245843
                mid             apples  0.471135
                                pears   0.191322
                                nanas   0.153920
Vendor B        low             apples  0.711457
                                pears   0.211794
                                nanas   0.599071
                mid             apples  0.303910
                                pears   0.657348
                                nanas   0.111750

2) 仅将可迭代的数据写入该 wed 切片

如果我理解正确,您正尝试将“交付”列中的值替换为特定的可迭代对象(例如列表),其中当天是“星期三”。不幸的是 .loc-type 替换在这种情况下不起作用。据我所知,pandas 只有简单的语法可以使用 .at 或 .loc 以这种方式替换单个单元格的值(参见SO answer)。但是,我们可以使用 iterrows 来完成:

idx = pd.IndexSlice

# If we don't change the column's type, which was float, this will error
df['deliveries'] = df['deliveries'].astype(object)

# Loop through rows, replacing single values
# Only necessary if the new assigned value is mutable
for index, row in df.loc[idx[:,'wed'], 'deliveries':'deliveries'].iterrows():
    df.at[index, 'deliveries'] = ["We", "changed", "this"]

df.head(10)

Out:
                                            deliveries
produce_source  day  chiller_temp   fruit   
Vendor A        mon  low            apples  0.0287606
                                    pears   0.264512
                                    nanas   0.238089
                     mid            apples  0.814985
                                    pears   0.590967
                                    nanas   0.919351
                wed  low            apples  [We, changed, this]
                                    pears   [We, changed, this]
                                    nanas   [We, changed, this]
                     mid            apples  [We, changed, this]

虽然据我所知需要循环,但在我的选择中使用 df.xs 然后 df.update 而不是 .loc 更容易理解。例如,下面的代码和上面的 .loc 代码做的一样:

df['deliveries'] = df['deliveries'].astype(object)

# Create a temporary copy of our cross section
df2 = df.xs('wed', level='day', drop_level=False)

# The same loop as before
for index, row in df2.iterrows():
    df2.at[index, 'deliveries'] = ["We", "changed", "this"]

# Update the original df for the values we want from df2
df.update(df2, join="left", overwrite=True, filter_func=None, raise_conflict=False)

3) 为所有供应商、日子和水果添加一个高的 chiller_temp

替换多索引现有级别中的值需要替换整个级别。这可以通过 df.index.set_levels(更简单的方式 IMO)或 pd.MultiIndex.from_arrays 来完成。根据确切的用例图和/或替换可能有用。查看this SO answer 了解其他示例。

df.index = df.index.set_levels(['high' for v in df.index.get_level_values('chiller_temp')], level='chiller_temp')

4) 我看到使用 idx = pd.IndexSlice 进行了一些切片...这个 引发错误 AttributeError: 'list' object has no attribute 'loc'...引发 TypeError: unhashable type: 'slice'

对于 AttributeError: 'list' object has no attribute 'loc'TypeError: unhashable type: 'slice' 错误,您只需在这些行中有两个分配。

看起来您的 .loc 语法是正确的,只是您不能以这种方式分配 pd.Series 而不导致单元格值为 NaN(请参阅 2 的答案以获取正确的语法)。这有效:

idx = pd.IndexSlice
df.loc[idx[:,'wed'], 'deliveries':'deliveries'] = "We changed this"

【讨论】:

  • 你能给我一个示例输出吗?您是否只是想为总是显示“高”的索引添加一个额外的级别?是的。希望了解将中级索引添加到所有内容的语法。 (后来学习相反的东西;只为一些添加中级索引)
  • 明白了。我仍然远离电脑,但我会更新 3) 稍后
  • 更新了答案
  • 我刚刚写了这个新的Pandas MultiIndex Tutorial - 可能会有更多的兴趣。
猜你喜欢
  • 1970-01-01
  • 2017-03-28
  • 2015-08-21
  • 2020-06-29
  • 2016-01-07
  • 2014-12-17
  • 2017-05-08
  • 1970-01-01
  • 2015-03-16
相关资源
最近更新 更多