使用带有整数标签的多索引索引对数据帧进行部分更新

时间:2013-03-04 11:34:38

标签: pandas multi-index

我正在使用带有混合索引标签的多索引数据框,即第一级包含字符串标签,第二级和第三级是整数标签,第四级标签是日期。 Dataframe如下所示(master_df)

                                           X1   X2  X3
bucket       Start    Stop       Date           
B1             1       1         1/3/2000   2   2   3
                                 1/4/2000   4   3   3
B1             1       2         1/3/2000   4   2   3
                                 1/4/2000   6   2   2

我想取出sub_df作为master_df.ix ['B1',1,2,:],对sub_df执行一些操作并将其存储回master_df中的相同位置。我可以使用各种方法取出sub_df,但是当把它存回来时,我试过的所有选项似乎都没有用。我想这个问题与'Integer'标签有关(在第2和第3个lavel - start-stop)。我尝试过以下选项/方法但没有成功

    sub_df = master_df.ix['B1'].ix[1].ix[2]

    #do some operations on sub_df

    master_df.xs('B1').xs(1).xs(2).update(sub_df)

    master_df.ix['B1'].ix[1].ix[2].update(sub_df)

    merge(master_df.ix['B1',1,2,:],sub_df)

以上操作均未反映master_df中的更改(我也没有收到任何错误消息。)

你能建议正确的方法吗?

更新:

sub_df和master_df与sub_df expect date index上的操作没有相同的索引。 sub_df如下所示。

          X1   X2  X3
Date           
1/3/2000   2   2   3
1/4/2000   4   3   3

如果我尝试

sub_df = master_df[master_df.index.get_loc(('B1', 1, 2))]

我收到以下错误 -

TypeError:不可用类型:'numpy.ndarray'

此处的主要目的是仅对master_df的一小部分进行操作,并将这些结果存储在master_df中的原始位置。我尝试使用更新方法,但是实现此目的的任何其他替代方法都可以。

5 个答案:

答案 0 :(得分:2)

这并不能完全解决您的问题,但我可能会这样做 提供一些灵感

这是一种直接设置值的方法

In [75]: df
Out[75]: 
  bucket  start  stop                date  x1  x2  x3
0     B1      1     1 2000-10-03 00:00:00   2   2   3
1     B1      1     1 2000-01-04 00:00:00   4   3   3
2     B1      1     2 2000-01-03 00:00:00   4   2   3
3     B1      1     2 2000-01-04 00:00:00   6   2   2

In [76]: df2 = df.set_index(['bucket','start','stop'])

In [77]: df2
Out[77]: 
                                 date  x1  x2  x3
bucket start stop                                
B1     1     1    2000-10-03 00:00:00   2   2   3
             1    2000-01-04 00:00:00   4   3   3
             2    2000-01-03 00:00:00   4   2   3
             2    2000-01-04 00:00:00   6   2   2

In [78]: df2.ix[('B1',1,2)].ix[:,'x1'] = 5

In [79]: df2
Out[79]: 
                                 date  x1  x2  x3
bucket start stop                                
B1     1     1    2000-10-03 00:00:00   2   2   3
             1    2000-01-04 00:00:00   4   3   3
             2    2000-01-03 00:00:00   5   2   3
             2    2000-01-04 00:00:00   5   2   2

这是另一种方法,你选择一个具有多索引的系列,修改它, 然后将其分配回来(仅适用于系列)。

In [89]: df2.ix[:,'x1']
Out[89]: 
bucket  start  stop
B1      1      1       2
               1       4
               2       4
               2       6
Name: x1, dtype: int64

In [90]: new_s = df2.ix[:,'x1'].copy()

In [91]: new_s
Out[91]: 
bucket  start  stop
B1      1      1       2
               1       4
               2       4
               2       6
Name: x1, dtype: int64

# can also do a more complicated selctor than the 0th row
In [92]: new_s[0] = 5

In [93]: new_s
Out[93]: 
bucket  start  stop
B1      1      1       5
               1       4
               2       4
               2       6
Name: x1, dtype: int64

In [94]: df2.ix[:,'x1'] = new_s

In [95]: df2
Out[95]: 
                                 date  x1  x2  x3
bucket start stop                                
B1     1     1    2000-10-03 00:00:00   5   2   3
             1    2000-01-04 00:00:00   4   3   3
             2    2000-01-03 00:00:00   4   2   3
             2    2000-01-04 00:00:00   6   2   2

这是您在0.11

中可以做的事情
# this is sessentially saying give me the first 2 rows (equivalent
# to selecting via complicated tuple)
In [107]: df2.iloc[0:2,:]
Out[107]: 
                                 date  x1  x2  x3
bucket start stop                                
B1     1     1    2000-10-03 00:00:00  10   2   3
             1    2000-01-04 00:00:00   4   3   3

In [108]: df2.iloc[0:2,:].loc[:,'x1']
Out[108]: 
bucket  start  stop
B1      1      1       10
               1        4
Name: x1, dtype: int64

In [109]: df2.iloc[0:2,:].loc[:,'x1'] = 5

In [110]: df2
Out[110]: 
                                 date  x1  x2  x3
bucket start stop                                
B1     1     1    2000-10-03 00:00:00   5   2   3
             1    2000-01-04 00:00:00   5   3   3
             2    2000-01-03 00:00:00   4   2   3
             2    2000-01-04 00:00:00   6   2   2

答案 1 :(得分:1)

sub_dfmaster_df具有相同的索引非常重要。

获取正确索引的一种方法是使用get_loc

sub_df = df[df.index.get_loc(('B1', 1, 2))]
# operations not changing index
master_df.update(sub_df)

答案 2 :(得分:0)

谢谢大家的帮助。最后,我从2级和3级的数字索引切换到charater索引,现在情况正常(这也有助于在级别上进行正确的排序,这是我认为使事情更加明确。)

答案 3 :(得分:0)

对于您给出的示例(选择('B1',1,2,...)),您可以使用xs iso ix。与ix相比,xs可以在使用标签时返回数据视图(有关ix返回视图/副本的更多详细信息,请参阅docs)。 在下面的示例中,sub_df的colum X1是更改,这也会影响master_df。

In [48]: master_df
Out[48]: 
                              X1  X2  X3
bucket Start Stop Date                  
B1     1     1    2000-01-03   2   2   3
                  2000-01-04   4   3   3
             2    2000-01-03   4   2   3
                  2000-01-04   6   2   2

In [49]: sub_df = master_df.xs(['B1', 1, 2], copy=False)

In [50]: sub_df
Out[50]: 
            X1  X2  X3
Date                  
2000-01-03   4   2   3
2000-01-04   6   2   2

In [51]: sub_df.X1 -= 4

In [52]: sub_df
Out[52]: 
            X1  X2  X3
Date                  
2000-01-03   0   2   3
2000-01-04   2   2   2

In [53]: master_df
Out[53]: 
                              X1  X2  X3
bucket Start Stop Date                  
B1     1     1    2000-01-03   2   2   3
                  2000-01-04   4   3   3
             2    2000-01-03   0   2   3
                  2000-01-04   2   2   2

答案 4 :(得分:0)

在0.13参数中,'drop_level'已添加到'xs',这样就可以解决您的问题,因为所有索引级别都将出现在sub_df中:

sub_df = master_df.xs(['B1',1,2],level = ['bucket','Start','Stop'],drop_level = False)

现在合并将有效。

没试过,但它应该有用。

参考:"Large data" work flows using pandas