【问题标题】:Reorder subset of columns in pandas dataframe with natural sorting使用自然排序对 pandas 数据框中的列子集进行重新排序
【发布时间】:2022-10-13 02:10:39
【问题描述】:

我有以下数据框:

df = pd.DataFrame({
   'tmp': ['A', 'A', 'B', 'Z', 'D', 'C'],
   'F1': [2, 1, 9, 8, 7, 4],
   'F20': [0, 1, 9, 4, 2, 3],
   'F3': ['a', 'B', 'c', 'D', 'e', 'F'],
   'aabb': ['a', 'B', 'c', 'D', 'e', 'F']
})
---
  tmp  F1  F20 F3 aabb
0   A   2    0  a    a
1   A   1    1  B    B
2   B   9    9  c    c
3   Z   8    4  D    D
4   D   7    2  e    e
5   C   4    3  F    F

我想以这种方式只对带有 F 的列进行排序:

   tmp  F1  F3  F20 aabb
0   A   2    a   0    a
1   A   1    B   1    B
2   B   9    c   9    c
3   Z   8    D   4    D
4   D   7    e   2    e
5   C   4    F   3    F

我该怎么办?

(编辑) 带有“F”的列的数量和 F 后面的值可能会有所不同(在我的情况下,我有大约 100 个这样的列) 带有 F 的列总是分组,但前后的数字是可变的

【问题讨论】:

  • F 列是否总是分组?之前/之后的列数是否可变?
  • 是的,带有 F 的列总是分组,但之前和之后的数字是可变的

标签: python pandas dataframe multiple-columns


【解决方案1】:

您可以使用 natsort 进行自然排序,并使用掩码仅处理 F 列:

# pip install natsort
from natsort import natsorted

cols = df.columns.to_numpy(copy=True)
m = df.columns.str.fullmatch('Fd+')
cols[m] = natsorted(cols[m])

df_sorted = df[cols]

没有natsort的替代方案:

num = df.columns.str.extract('F(d+)', expand=False).astype(float)
cols = df.columns.to_numpy(copy=True)
m = num.notna()
order = np.argsort(num[m])
cols[m] = cols[m][order]

df_sorted = df[cols]

输出:

  tmp  F1 F3  F20 aabb
0   A   2  a    0    a
1   A   1  B    1    B
2   B   9  c    9    c
3   Z   8  D    4    D
4   D   7  e    2    e
5   C   4  F    3    F

【讨论】:

    【解决方案2】:

    你可以简单地做:

    df = df[["tmp", "F1", "F3", "F20", "aabb"]]
    

    更新:对 F 列进行排序。

    # find all F columns
    f_cols = df.columns[df.columns.str.startswith("F")].tolist()
    # ["F1", "F20", "F3"]
    
    # sort them using a lambda key
    f_cols_sorted = sorted(f_cols, key=lambda s: int(s[1:]))
    # ['F1', 'F3', 'F20']
    
    # sort
    df = df[["tmp"] + f_cols_sorted + ["aabb"]]
    

    更新:F组之前/之后的任意列名/列数。

    # find cols of pattern `Fd+`
    m = [re.match(r"Fd+", s) is not None for s in cols]
    # -> [False, True, True, True, False]
    
    # find first/last index of F column
    first_f = m.index(True)                    # 1
    last_f = len(m) - m[::-1].index(True) - 1  # 3
    
    # sort column names
    sorted_cols = cols[:first_f] + sorted(cols[first_f:last_f+1], key=lambda s: int(s[1:])) + cols[last_f+1:]
    # -> ['tmp', 'F1', 'F3', 'F20', 'aabb']
    
    # finally
    df = df[sorted_cols]
    

    【讨论】:

      【解决方案3】:

      这解决了编辑问题:

      df=df[["tmp"]+[f"F{x}" for x in sorted([int(y[1:]) for y in  df.columns if y[0]=="F"]) ]+["aabb"]]
      

      输出:

        tmp  F1 F3  F20 aabb
      0   A   2  a    0    a
      1   A   1  B    1    B
      2   B   9  c    9    c
      3   Z   8  D    4    D
      4   D   7  e    2    e
      5   C   4  F    3    F
      

      【讨论】:

      • 谢谢!但是在这种情况下,与前面的答案一样,存在F列前后可变列的问题
      猜你喜欢
      • 2018-06-25
      • 2017-02-13
      • 2020-07-22
      • 1970-01-01
      • 2019-02-21
      • 2013-06-05
      • 1970-01-01
      • 1970-01-01
      • 2021-09-08
      相关资源
      最近更新 更多