pandas:单独对每列排序

11 投票
5 回答
12239 浏览
提问于 2025-04-18 09:28

我的数据框看起来像这样,只是要大得多。

d = {'Col_1' : pd.Series(['A', 'B']),
 'Col_2' : pd.Series(['B', 'A', 'C']),
 'Col_3' : pd.Series(['B', 'A']),
 'Col_4' : pd.Series(['C', 'A', 'B', 'D']),
 'Col_5' : pd.Series(['A', 'C']),}
df = pd.DataFrame(d)

Col_1  Col_2  Col_3  Col_4  Col_5
  A      B      B      C      A
  B      A      A      A      C
  NaN    C      NaN    B      NaN
  NaN    NaN    NaN    D      NaN

首先,我想单独对每一列进行排序。我试着用类似这样的代码:df.sort([lambda x: x in df.columns], axis=1, ascending=True, inplace=True),但是结果总是出错。我该怎么做才能单独对每一列进行排序,最后得到像这样的结果:

Col_1  Col_2  Col_3  Col_4  Col_5
  A      A      A      A      A
  B      B      B      B      C
  NaN    C      NaN    C      NaN
  NaN    NaN    NaN    D      NaN

其次,我想把每一列中的行连接起来。

 df = pd.concat([df,pd.DataFrame(df.sum(axis=0),columns=['Concatenation']).T])

我可以用上面的代码把所有内容结合起来,前提是把np.nan替换成'',但是结果会变得很混乱(像'AB'这样连在一起),还需要额外的步骤来整理成像'A:B'这样的格式。

5 个回答

1

我不知道这样是否更好,不过这里有几种其他的方法可以做到这一点。

 pd.DataFrame({key: sorted(value.values(), reverse=True) \
    for key, value in df.to_dict().iteritems()})

 pd.DataFrame({key: sorted(values, reverse=True) \
    for key, values in df.transpose().iterrows()})
2

另一种解决方案是:

df.apply(lambda x: x.sort_values().reset_index(drop=True), axis=0)

(感谢 @BrenBarn 提到的 reset_index。)

根据 @Andy Hayden 的评论,使用 values 而不是 reset_index 可以得到:

df.apply(lambda x: x.sort_values().values, axis=0)
3

如果你的数据是数字类型,你可以使用Numpy的排序功能:

df[:] = np.sort(df.values)

但是在你的情况下,这个方法不行,因为它无法处理浮点数和字符串混合的数据。

这里有一个解决办法:

df[:] = np.sort(df.fillna('\xff\xff\xff').values)
df = df.replace('\xff\xff\xff', np.nan)

我把NaN(缺失值)替换成一个ASCII值为255的字符字符串,这样在排序后它们几乎肯定会排到最后。然后再把它们替换回NaN。

输出结果:

  Col_1 Col_2 Col_3 Col_4 Col_5
0     A     A     B     B     C
1     A     A     A     B     C
2     B     C   NaN   NaN   NaN
3     D   NaN   NaN   NaN   NaN
15

pandas.Series.order 从 pandas 0.17 版本开始就不再推荐使用了。 现在应该使用 sort_values,用法如下:

for col in df:
    df[col] = df[col].sort_values(ignore_index=True)
9

这里有一种方法:

>>> pandas.concat([df[col].order().reset_index(drop=True) for col in df], axis=1, ignore_index=True)
11:      0    1    2  3    4
0    A    A    A  A    A
1    B    B    B  B    C
2  NaN    C  NaN  C  NaN
3  NaN  NaN  NaN  D  NaN

[4 rows x 5 columns]

不过,你的做法有点奇怪。DataFrame并不是一堆没有关系的列。在一个DataFrame中,每一代表一条记录,所以一列中的值和同一行中其他列的值是有联系的。如果你独立地对列进行排序,就会丢失这些信息,这样行的数据就变得没有意义了。这就是为什么在我的例子中需要使用reset_index的原因。此外,正因为如此,你的例子中提到的想要就地处理(in-place)也是做不到的。

撰写回答