【问题标题】:Pandas sorting by value and then by indexPandas 按值排序,然后按索引排序
【发布时间】:2016-02-15 10:28:58
【问题描述】:

我有以下数据集:

import numpy as np
from pandas import DataFrame
import numpy.random as random

random.seed(12)

df = DataFrame (
    {
        "fac1" : ["a","a","a","a","b","b","b","b"] ,
        "val" : random.choice(np.arange(0,20), 8, replace=False)
    }
)
df2 = df.set_index(["fac1"])
df2

我想要的是在每个fac1 组中按val 排序,以产生这个:

我已经梳理了文档,找不到直接的方法。我能做的最好的就是以下黑客:

df3 = df2.reset_index()
df4 = df3.sort_values(["fac1","val"],ascending=[True,True],axis=0)
df5 = df4.set_index(["fac1"])
df5
# Produces the picture above

(我意识到以上可以从多个inplace 选项中受益,只是这样做是为了使中间产品清晰)。

我确实找到了this SO post,它使用了分组和排序功能。但是,改编自该帖子的以下代码产生了错误的结果:

df2.groupby("fac1",axis=1).apply(lambda x : x.sort_values("val"))

(出于空间考虑,已删除输出)

还有其他方法可以解决这个问题吗?

更新:解决方案

公认的解决方案是:

df2.sort_values(by='val').sort_index(kind='mergesort')

排序算法必须是mergesort,并且必须明确指定,因为它不是默认值。正如the sort_index documentation 指出的那样,“合并排序是唯一的stable 算法。”这是另一个示例数据集,如果您不为 kind 指定 mergesort,则无法正确排序:

random.seed(12)

len = 32 

df = DataFrame (
    {
        "fac1" : ["a" for i in range(int(len/2))] + ["b" for i in range(int(len/2))] ,
        "val" : random.choice(np.arange(0,100), len, replace=False)
    }
)
df2 = df.set_index(["fac1"])
df2.sort_values(by='val').sort_index()

(出于空间考虑,我省略了所有输出)

【问题讨论】:

  • 我一直在尝试缩小故障发生的范围,它与 len 有关 - 因为代码中的其他所有内容都等于建议的解决方案适用于 len

标签: python pandas


【解决方案1】:

编辑:我查看了文档,sort_index 的默认排序算法是快速排序。这不是一个“稳定”的算法,因为它不保留“排序输出中相等元素的输入顺序”(来自维基百科)。但是,sort_index 让您可以选择“mergesort”,这是一种稳定的排序算法。所以我原来的答案,

df2.sort_values(by='val').sort_index()

成功了,只是偶然。这段代码应该每次都能工作,因为它使用了稳定的排序算法:

df2.sort_values(by='val').sort_index(kind = 'mergesort')

【讨论】:

  • 我刚刚在你写最后一个编辑时遇到了同样的事情。是的,这就是答案。话虽如此,我有点惊讶mergesort 不是kind 的默认值。好吧,我想无论哪种方式都可以提出案例。无论如何,我认为这可以解决它
  • 我也很惊讶,但我认为在最坏的情况下可能需要更长的时间。
  • 同意 - 从文档来看,这一切都可以追溯到底层的 numpy ndarray 实现。该库确实是为速度而构建的;同时,在 pandas 层,我的用例是一个常见的用例(我是 pandas 的新手,但已经做了很多年的数据科学/统计,主要是在 SAS 上,这很容易做到。)我认为API 可以通过使用布尔 stable 参数而不是算法选择来改进 - 人们更有可能注意到它。无论如何,现在我们知道了!再次感谢(并享受赏金:-))。
  • 如果对你和我一样有必要首先对列进行排序,然后在索引上更改排序顺序!例如.sort_index().sort_values('A', kind='mergesort')
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-16
  • 2020-04-30
  • 2018-08-29
  • 2018-09-23
  • 2016-11-03
  • 2018-05-12
  • 2021-11-22
相关资源
最近更新 更多