Pandas 多索引数据框将列中的第一行设置为 0

Gan*_*dar 5 python multi-index pandas split-apply-combine

我在处理 Pandas 中的分组对象时遇到了一些麻烦。具体来说,我希望能够将列中的第一行设置为 0,同时保持其他行不变。

例如:

df = pd.DataFrame({'A': ['foo', 'bar', 'baz'] * 2,
                        'B': rand.randn(6),
                        'C': rand.rand(6) > .5})
Run Code Online (Sandbox Code Playgroud)

给我

    A         B      C
0  foo  1.624345  False
1  bar -0.611756   True
2  baz -0.528172  False
3  foo -1.072969   True
4  bar  0.865408  False
5  baz -2.301539   True
Run Code Online (Sandbox Code Playgroud)

我将它们按 A 分组并按 B 对它们进行排序:

f = lambda x: x.sort('B', ascending=True)
sort_df = df.groupby('A',sort=False).apply(f)
Run Code Online (Sandbox Code Playgroud)

得到这个:

         A         B      C
    A                          
foo 3  foo -1.072969   True
    0  foo  1.624345  False
bar 1  bar -0.611756   True
    4  bar  0.865408  False
baz 5  baz -2.301539   True
    2  baz -0.528172  False
Run Code Online (Sandbox Code Playgroud)

现在我有了组,我希望能够将每个组中的第一个元素设置为 0。我该怎么做?

像这样的事情会起作用,但我想要一种更优化的方法:

for group in sort_df.groupby(level=0).groups:
    sort_df.loc[(group,sort_df.loc[group].index[0]),'B']=0
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激,谢谢!

Jef*_*eff 3

这是执行此操作的矢量化方法。会快得多

In [26]: pd.set_option('max_rows',10)
Run Code Online (Sandbox Code Playgroud)

创建一个2级多索引的框架,按A排序(这里任意)

In [27]: df = DataFrame(dict(A = np.random.randint(0,100,size=N),B=np.random.randint(0,100,size=N),C=np.random.randn(N))).sort(columns=['A'])

In [28]: df
Out[28]: 
        A   B         C
61474   0  40 -0.731163
82386   0  18 -1.316136
63372   0  28  0.112819
49666   0  13 -0.649491
31631   0  89 -0.835208
...    ..  ..       ...
42178  99  28 -0.029800
59529  99  31 -0.733588
13503  99  60  0.672754
20961  99  18  0.252714
31882  99  22  0.083340

[100000 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)

重置索引以捕获索引值。根据B找到第一个值

In [29]: grouped = df.reset_index().groupby('B').first()

In [30]: grouped
Out[30]: 
    index  A         C
B                     
0   26576  0  1.123605
1   38311  0  0.128966
2   45135  0 -0.039886
3   38434  0 -1.284028
4   82088  0 -0.747440
..    ... ..       ...
95  82620  0 -1.197625
96  63278  0 -0.625400
97  23226  0 -0.497609
98  82520  0 -0.828773
99  35902  0 -0.199752

[100 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)

这为您提供了一个进入框架的索引器。

In [31]: df.loc[grouped['index']] = 0

In [32]: df
Out[32]: 
        A   B         C
61474   0   0  0.000000
82386   0   0  0.000000
63372   0   0  0.000000
49666   0   0  0.000000
31631   0   0  0.000000
...    ..  ..       ...
42178  99  28 -0.029800
59529  99  31 -0.733588
13503  99  60  0.672754
20961  99  18  0.252714
31882  99  22  0.083340

[100000 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)

如果你想

In [33]: df.sort_index()
Out[33]: 
        A   B         C
0      40  56 -1.223941
1      24  77 -0.039775
2       7  83  0.741013
3      48  38 -1.795053
4      62  15 -2.734968
...    ..  ..       ...
99995  20  25 -0.286300
99996  27  21 -0.120430
99997   0   4  0.607524
99998  38  31  0.717069
99999  33  63 -0.226888

[100000 rows x 3 columns]
Run Code Online (Sandbox Code Playgroud)

这个方法

In [34]: %timeit df.loc[grouped['index']] = 0
100 loops, best of 3: 7.33 ms per loop
Run Code Online (Sandbox Code Playgroud)

你原来的

In [37]: %timeit df.groupby('A',sort=False).apply(f)
10 loops, best of 3: 109 ms per loop
Run Code Online (Sandbox Code Playgroud)

如果你有更多的组,这种性能差异就会扩大。