如何按一列对整个 pandas 数据框进行排序,移动分组为 3s 的行

How do I sort a whole pandas dataframe by one column, moving the rows grouped in 3s

我有一个数据框,其中包含基因(合奏 ID 和通用名称)、同系物、计数和总计,按三个顺序排列:

Index Zebrafish Homolog  Human Homolog    Total
0     ENSDARG00000019949 ENSG00000149257 
1     serpinh1b          SERPINH1
2     2                  2                4
3     ENSDARG00000052437 ENSG00000268975
4     mia                MIA-RAB4B
5     2                  0                2
6     ENSDARG00000057992 ENSG00000134363
7     fstb               FST
8     0                  3                3
9     ENSDARG00000045580 ENSG00000139329
10    lum                LUM
11    15                 15               30

etc...

我想按总数降序对这些行进行排序。这样所有的行都按照显示的顺序以 3 组的形式保持完整。理想的输出是:

Index Zebrafish Homolog  Human Homolog    Total
0     ENSDARG00000045580 ENSG00000139329
1     lum                LUM
2     15                 15               30    
3     ENSDARG00000019949 ENSG00000149257 
4     serpinh1b          SERPINH1
5     2                  2                4
6     ENSDARG00000057992 ENSG00000134363
7     fstb               FST
8     0                  3                3
9     ENSDARG00000052437 ENSG00000268975
10    mia                MIA-RAB4B
11    2                  0                2

etc...

我尝试对所有 3 行中的每一行进行总计,然后使用 dataframe.sort.values() 进行排序,并为每 3 行删除前 2 行,但它没有正常工作。有没有办法将这些行组合成 3 个一组,然后对它们进行排序以保持该结构?提前感谢您的帮助。

更新#1

如果我尝试使用代码:

df['Total'] = df['Total'].bfill().astype(int)
df = df.sort_values(by='Total', ascending=False)

将值添加到每组 3 的总数然后排序,它部分工作,但打乱代码如下:

Index Zebrafish Homolog  Human Homolog    Total
0     ENSDARG00000045580 ENSG00000139329  30
1     lum                LUM              30
2     15                 15               30    
4     serpinh1b          SERPINH1         4
3     ENSDARG00000019949 ENSG00000149257  4
5     2                  2                4
8     0                  3                3
7     fstb               FST              3
6     ENSDARG00000057992 ENSG00000134363  3
9     ENSDARG00000052437 ENSG00000268975  2
11    2                  0                2
10    mia                MIA-RAB4B        2

等...

更糟糕的是,如果多个基因具有相同的总计数,行将在基因之间互换,从而变得混乱

这是死胡同吗?也许我应该以不同的方式重写代码:(

您的总计似乎缺少值,这对这种情况有帮助

  • 方法一
df['Total'] = df['Total'].bfill().astype(int)
df['idx'] = np.arange(len(df)) // 3
df = df.sort_values(by=['Total', 'idx'], ascending=False)
df = df.drop(['idx'], axis=1)
     Zebrafish_Homolog    Human_Homolog  Total
9   ENSDARG00000045580  ENSG00000139329     30
10                 lum              LUM     30
11                  15               15     30
0   ENSDARG00000019949  ENSG00000149257      4
1            serpinh1b         SERPINH1      4
2                    2                2      4
6   ENSDARG00000057992  ENSG00000134363      3
7                 fstb              FST      3
8                    0                3      3
3   ENSDARG00000052437  ENSG00000268975      2
4                  mia        MIA-RAB4B      2
5                    2                0      2

注意索引是如何保持不变的,如果你不想那样,那么 reset_index()

df = df.reset_index(drop=True)

  • 方法二

一种更手动的排序方式。 做法是对索引进行排序,然后loc df。它看起来很复杂,但它只是从列表中减去整数。请注意,该过程直到结束才会在 df 上发生,因此对于更大的 df.

应该没有速度问题
# Sort by total
df = df.reset_index().sort_values('Total', ascending=False)
# Get the index of the sorted values
uniq_index = df[df['Total'].notnull()]['index'].values

# Create the new index
index = uniq_index .repeat(3)
groups = [-2, -1, 0] * (len(df) // 3)

# Update so everything is in order
new_index = index + groups

# Apply to the dataframe
df = df.loc[new_index]
     Zebrafish_Homolog    Human_Homolog  Total
0   ENSDARG00000045580  ENSG00000139329    NaN
1                  lum              LUM    NaN
2                   15               15   30.0
9   ENSDARG00000019949  ENSG00000149257    NaN
10           serpinh1b         SERPINH1    NaN
11                   2                2    4.0
3   ENSDARG00000057992  ENSG00000134363    NaN
4                 fstb              FST    NaN
5                    0                3    3.0
6   ENSDARG00000052437  ENSG00000268975    NaN
7                  mia        MIA-RAB4B    NaN
8                    2                0    2.0
12  ENSDARG00000052437  ENSG00000268975    NaN
13                 mia        MIA-RAB4B    NaN
14                   2                0    2.0

您需要创建第二个键以在排序时将记录保持在一起,请参见下文:

df.Total= df.Total.bfill()                                                                                           
df["helper"]= np.arange(len(df))//3 
df= df.sort_values(["Total","helper"])
df= df.drop(columns="helper")