在多层索引数据框中为pandas添加更低层次的列

3 投票
1 回答
4706 浏览
提问于 2025-04-28 07:23

有人能帮我完成这个任务吗?我通过unstack()操作得到了一个多层的数据框:

Original df:
Density  Length  Range  Count
  15k    0.60  small    555
  15k    0.60    big     17
  15k    1.80  small    141
  15k    1.80    big     21
  15k    3.60  small    150
  15k    3.60    big     26
  20k    0.60  small   5543
  20k    0.60    big     22
  20k    1.80  small    553
  20k    1.80    big     25
  20k    3.60  small    422
  20k    3.60    big     35

df  = df.set_index(['Density','Length','Range']).unstack('Range')

# After unstack:
                  Count       
Range             big  small
Density Length              
15k     0.60       17    555
        1.80       21    141
        3.60       26    150
20k     0.60       22   5543
        1.80       25    553
        3.60       35    422

现在我想在第一层添加一个额外的列,这个列是小值和大值的比率。我尝试了以下几种写法,虽然没有报错,但结果却不一样。

#df[:]['ratio']=df['Count']['small']/df['Count']['big'] ## case 1. no error, no ratio
#df['Count']['ratio']=df['Count']['small']/df['Count']['big'] ## case 2. no error, no ratio
#df['ratio']=df['Count']['small']/df['Count']['big'] ## case 3. no error, ratio on column level 0
df['ratio']=df.ix[:,1]/df.ix[:,0]                    ## case 4. no error, ratio on column level 0

#After execution above code, df:
                  Count         ratio
Range             big  small       
Density Length                     
15k     0.60       17    555  32.65
        1.80       21    141   6.71
        3.60       26    150   5.77
20k     0.60       22   5543 251.95
        1.80       25    553  22.12
        3.60       35    422  12.06

我不明白为什么情况1和2没有报错,但也没有添加新的比率列。而情况3和4中,比率列却出现在了第0层,而不是我期待的第1层。我还想知道有没有更好、更简洁的方法来实现这个目标。情况4是我能做到的最好,但我不喜欢用隐式索引的方式(而不是用名字)来引用列。

谢谢

暂无标签

1 个回答

5

案例 1:

df[:]['ratio']=df['Count']['small']/df['Count']['big'] 

df[:]df 的一个副本。它们是不同的对象,各自有自己的一份数据:

In [69]: df[:] is df
Out[69]: False

所以修改这个副本不会影响原来的 df。因为 df[:] 没有保持引用,所以在赋值后,这个对象会被垃圾回收,导致这个赋值没有意义。


案例 2:

df['Count']['ratio']=df['Count']['small']/df['Count']['big'] 

使用了链式索引。在进行赋值时,尽量避免使用链式索引。这个链接解释了为什么在左侧使用链式索引的赋值可能不会影响 df

如果你设置了

pd.options.mode.chained_assignment = 'warn'

那么 Pandas 会警告你不要在赋值时使用链式索引:

SettingWithCopyError: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy

案例 3:

df['ratio']=df['Count']['small']/df['Count']['big'] 

案例 4:

df['ratio']=df.ix[:,1]/df.ix[:,0]

这两个都可以工作,但可以用更高效的方式来完成:

df['ratio'] = df['Count','small']/df['Count','big']

这里有一个微基准测试,显示使用 df[tuple_index] 比链式索引要快:

In [99]: %timeit df['Count']['small']
1000 loops, best of 3: 501 µs per loop

In [128]: %timeit df['Count','small']
100000 loops, best of 3: 8.91 µs per loop

如果你想让 ratio 成为第一级标签,那么你必须告诉 Pandas 第零级标签是 Count。你可以通过赋值给 df['Count','ratio'] 来做到这一点:

In [96]: df['Count','ratio'] = df['Count']['small']/df['Count','big']

# In [97]: df
# Out[97]: 
#                Count                  
# Range            big small       ratio
# Density Length                        
# 15k     0.6       17   555   32.647059
#         1.8       21   141    6.714286
#         3.6       26   150    5.769231
# 20k     0.6       22  5543  251.954545
#         1.8       25   553   22.120000
#         3.6       35   422   12.057143

撰写回答