【问题标题】:pandas cut with infinite upper/lower bounds具有无限上/下界的熊猫切割
【发布时间】:2021-10-27 20:55:25
【问题描述】:

pandas cut() documentation 声明:“超出范围的值将在生成的分类对象中为 NA。”当上限不一定清晰或重要时,这会变得很困难。例如:

cut (weight, bins=[10,50,100,200])

将产生垃圾箱:

[(10, 50] < (50, 100] < (100, 200]]

所以cut (250, bins=[10,50,100,200]) 将产生NaNcut (5, bins=[10,50,100,200]) 也将产生。我要做的是为第一个示例生成类似&gt; 200 的内容,为第二个示例生成&lt; 10

我意识到我可以使用cut (weight, bins=[float("inf"),10,50,100,200,float("inf")]) 或类似的方法,但我遵循的报告风格不允许使用(200, inf] 之类的东西。我也意识到我实际上可以通过cut() 上的labels 参数指定自定义标签,但这意味着每次调整bins 时都要记住调整它们,这可能经常发生。

我是否已经用尽了所有可能性,或者cut()pandas 的其他地方有什么可以帮助我做到这一点?我正在考虑为cut() 编写一个包装函数,它会自动从垃圾箱中生成所需格式的标签,但我想先在这里检查一下。

【问题讨论】:

  • 您是在询问如何设置 bin 边界,或者如何将一个标记为“200+”?您可以将上限设置为 the_data.max()+1 或其他内容,但我认为如果您需要特定格式,则必须手动设置标签。
  • 是的,我开始认为这是唯一的方法。

标签: python pandas


【解决方案1】:

您可以在 bin 列表中使用 float("inf") 作为上限,-float("inf") 作为下限。它将删除 NaN 值。

【讨论】:

  • 被低估的答案!
  • 这绝对应该是公认的答案!
  • pd.cut(df.duration, [0,5,10,20,float("inf")],right=True)
  • 姗姗来迟,我正在接受这个答案!
【解决方案2】:

等了几天后,仍然没有答案 - 我认为这可能是因为除了编写 cut() 包装函数之外真的没有办法解决这个问题。我在这里发布我的版本并将问题标记为已回答。如果有新的答案出现,我会改变这一点。

def my_cut (x, bins,
            lower_infinite=True, upper_infinite=True,
            **kwargs):
    r"""Wrapper around pandas cut() to create infinite lower/upper bounds with proper labeling.

    Takes all the same arguments as pandas cut(), plus two more.

    Args :
        lower_infinite (bool, optional) : set whether the lower bound is infinite
            Default is True. If true, and your first bin element is something like 20, the
            first bin label will be '<= 20' (depending on other cut() parameters)
        upper_infinite (bool, optional) : set whether the upper bound is infinite
            Default is True. If true, and your last bin element is something like 20, the
            first bin label will be '> 20' (depending on other cut() parameters)
        **kwargs : any standard pandas cut() labeled parameters

    Returns :
        out : same as pandas cut() return value
        bins : same as pandas cut() return value
    """

    # Quick passthru if no infinite bounds
    if not lower_infinite and not upper_infinite:
        return pd.cut(x, bins, **kwargs)

    # Setup
    num_labels      = len(bins) - 1
    include_lowest  = kwargs.get("include_lowest", False)
    right           = kwargs.get("right", True)

    # Prepend/Append infinities where indiciated
    bins_final = bins.copy()
    if upper_infinite:
        bins_final.insert(len(bins),float("inf"))
        num_labels += 1
    if lower_infinite:
        bins_final.insert(0,float("-inf"))
        num_labels += 1

    # Decide all boundary symbols based on traditional cut() parameters
    symbol_lower  = "<=" if include_lowest and right else "<"
    left_bracket  = "(" if right else "["
    right_bracket = "]" if right else ")"
    symbol_upper  = ">" if right else ">="

    # Inner function reused in multiple clauses for labeling
    def make_label(i, lb=left_bracket, rb=right_bracket):
        return "{0}{1}, {2}{3}".format(lb, bins_final[i], bins_final[i+1], rb)

    # Create custom labels
    labels=[]
    for i in range(0,num_labels):
        new_label = None

        if i == 0:
            if lower_infinite:
                new_label = "{0} {1}".format(symbol_lower, bins_final[i+1])
            elif include_lowest:
                new_label = make_label(i, lb="[")
            else:
                new_label = make_label(i)
        elif upper_infinite and i == (num_labels - 1):
            new_label = "{0} {1}".format(symbol_upper, bins_final[i])
        else:
            new_label = make_label(i)

        labels.append(new_label)

    # Pass thru to pandas cut()
    return pd.cut(x, bins_final, labels=labels, **kwargs)

【讨论】:

  • 太棒了!您是否为下一个 Pandas 版本提出了代码?
  • 哇,我从没想过这样做。我想我会尝试 - 谢谢!
【解决方案3】:

只需添加np.inf,例如:

pd.cut(df['weight'], [0, 50, 100, np.inf], labels=['0-50', '50-100', '100-'])

【讨论】:

  • 只是一个提示,您可能需要考虑include_lowest=True 来制作第一个间隔[0, 50] 而不是(0, 50]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-30
  • 2022-07-09
  • 2018-05-01
  • 1970-01-01
  • 2021-08-31
  • 2022-10-07
相关资源
最近更新 更多