如何在pandas DataFrame中设置给定索引级别的值

时间:2018-11-29 07:50:22

标签: python pandas dataframe slice

我试图在多索引熊猫DataFrame中设置列的所有值,仅为单个索引级别指定数据。 到目前为止,我提出的解决方案并不令人满意,但这可能最好用代码来解释:

from pandas import MultiIndex, DataFrame
idx = MultiIndex.from_product([['A', 'B'], [1, 2, 3]],
                              names=['Cases', 'Time'])
parameters = DataFrame(index=idx)
parameters['CaseAndTimeInvariant'] = 1
parameters['CaseAndTimeVariant'] = 1, 2, 3, 4, 5, 6
# Set the values in 'Time' for all cases to 1, 2, 3
parameters['CaseInvariantTimeVariant'] = 1, 2, 3
# ValueError: Length of values does not match length of index

错误非常明显,因为我没有在任何地方指定数据应该达到的级别。如果我有另一个“情况”,数据的长度不足以确定我对上面代码的最后一行的意思。

我显然需要做的是告诉parameters我要传递的数据是针对“时间”索引级别的。但是,我发现所有使用loc-indexing的尝试都导致:

  • 其他具有完整长度的数据框或系列或
  • 需要各个方案的规范

当前我正在执行以下操作:

for c in parameters.index.levels[0]:
    parameters.loc[(c, slice(None)), 'CaseInvariantTimeVariant'] = 1, 2, 3

导致:

enter image description here

虽然这样做符合我的期望,但在两个方面都感到不满意:

  • 它需要两条相当神秘的线来完成看似简单的事情: (请使用我给您的迭代方法设置Time的所有值!)
  • 我们需要在所有被视为相同的索引级别上进行显式迭代,因此这不能很好地推广到两个以上级别

似乎'groupby'在这里可能会有所帮助,但直到现在我仍无法编写大量文档。

1 个答案:

答案 0 :(得分:0)

如果我们总是想将序列与最内层对齐,则可以:

sequence = [1, 2, 3]
inner_level = parameters.index.get_level_values(len(parameters.index.levels) - 1)
n = inner_level.size // inner_level.nunique()

parameters['CaseInvariantTimeVariant'] = sequence * n

*请注意,在分配序列sort之前,我们仍然需要parameters.sort_index(inplace=True)索引。


以下,如果我们要使用外部级别:

我会sort_index,然后重复序列n次,其中n是唯一索引的长度(数据中的Cases)。

parameters.sort_index(inplace=True)

my_sequence = (1, 2, 3)

# below by level: parameters.index.get_level_values(0).nunique()
n = parameters.index.get_level_values('Cases').nunique()

parameters['CaseInvariantTimeVariant'] = my_sequence * n

如果您希望某个函数始终按最外部的索引重复序列:

def repeat_seq_by_outer_index(index, sequence):
    return sequence * index.get_level_values(0).nunique()

repeat_seq_by_outer_index(parameters.index, (1, 2, 3))

如果您希望函数始终按索引中的nth级别重复序列:

def repeat_seq_by_nth_index(index, level, sequence):
    return sequence * index.get_level_values(level).nunique()

repeat_seq_by_nth_index(parameters.index, 0, (1, 2, 3))