在通过pandas.cut()函数创建垃圾箱后,如何有效地将每个值标记到垃圾箱?

时间:2020-02-27 22:13:16

标签: python pandas data-manipulation binning inference

假设我在数据框中有一个“ user_age”列,并且通过类似以下方式创建了“ user_age_bin”:

df['user_age_bin']= pd.cut(df['user_age'], bins=[10, 15, 20, 25,30])

然后,我使用“ user_age_bin”功能构建机器学习模型。

接下来,我得到了一条记录,需要将其放入模型并进行预测。我不想使用user_age,因为模型使用了user_age_bin。因此,如何将user_age值(例如28)转换为user_age_bin?我知道我可以创建这样的函数:

def assign_bin(age):
    if age < 10:
        return '<10'
    elif age< 15:
        return '10-15'
     ... etc. etc.

然后执行:

user_age_bin = assign_bin(28)

但是这种解决方案一点都不优雅。我想一定有更好的方法吧?

编辑:我更改了代码并添加了明确的bin范围。 Edit2:编辑了措辞,希望现在问题更清楚了。

4 个答案:

答案 0 :(得分:1)

双重列表理解有点丑陋,但似乎可以完成工作。

设置:

import pandas as pd
import numpy as np
np.random.seed(42)

bins = [10, 15, 20, 25, 30, np.Inf]
labels = bins[1:]
ages = np.random.randint(10, 35, 10)
df = pd.DataFrame({"user_age": ages})
df["user_age_bin"] = pd.cut(df["user_age"], bins=bins, labels=labels)
print(df)

出局:

   user_age user_age_bin
0        16         20.0
1        29         30.0
2        24         25.0
3        20         20.0
4        17         20.0
5        30         30.0
6        16         20.0
7        28         30.0
8        32          inf
9        20         20.0

分配:

# `new_ages` is what you want to assign labels to, used `ages` for simplicity
new_ages = ages
ids = [np.argmax([age <= x for x in labels]) for age in new_ages]
assigned_labels = [labels[i] for i in ids]
print(pd.DataFrame({"new_ages": new_ages, "assigned_labels": assigned_labels, "user_age_bin": df["user_age_bin"]}))

出局:

   new_ages  assigned_labels user_age_bin
0        16             20.0         20.0
1        29             30.0         30.0
2        24             25.0         25.0
3        20             20.0         20.0
4        17             20.0         20.0
5        30             30.0         30.0
6        16             20.0         20.0
7        28             30.0         30.0
8        32              inf          inf
9        20             20.0         20.0

答案 1 :(得分:1)

tl; dr:np.digitize是一个很好的解决方案。

在阅读了这里的所有评论和答案以及更多谷歌搜索之后,我认为我得到了一个令我非常满意的解决方案。谢谢大家!

设置

import pandas as pd
import numpy as np
np.random.seed(42)

bins = [0, 10, 15, 20, 25, 30, np.inf]
labels = bins[1:]
ages = list(range(5, 90, 5))
df = pd.DataFrame({"user_age": ages})
df["user_age_bin"] = pd.cut(df["user_age"], bins=bins, labels=False)

# sort by age 
print(df.sort_values('user_age'))

输出

 user_age  user_age_bin
0          5             0
1         10             0
2         15             1
3         20             2
4         25             3
5         30             4
6         35             5
7         40             5
8         45             5
9         50             5
10        55             5
11        60             5
12        65             5
13        70             5
14        75             5
15        80             5
16        85             5

分配类别

# a new age value
new_age=30

# use this right=True and '-1' trick to make the bins match
print(np.digitize(new_age, bins=bins, right=True) -1)

输出

4

答案 2 :(得分:0)

您可以尝试类似的操作:

bins=[10, 15, 20, 25, 30]
labels = [f'<{bins[0]}', *(f'{a}-{b}' for a, b in zip(bins[:-1], bins[1:])), f'{bins[-1]}>']
pd.cut(df['user_age'], bins=bins, labels=labels)

请注意,如果您使用的是python<3.7,则应使用类似语法的格式替换f-string。

答案 3 :(得分:0)

您不能将字符串放入模型中,因此需要创建一个映射并跟踪它,或者创建一个单独的columnn以便以后使用

variable = shared_var.get()

对于模型,您将保留def apply_age_bin_numeric(value): if value <= 10: return 1 elif value > 10 and value <= 20: return 2 elif value > 21 and value <= 30: return 3 etc.... def apply_age_bin_string(value): if value <= 10: return '<=10' elif value > 10 and value <= 20: return '11-20' elif value > 21 and value <= 30: return '21-30' etc.... df['user_age_bin_numeric']= df['user_age'].apply(apply_age_bin_numeric) df['user_age_bin_string']= df['user_age'].apply(apply_age_bin_string) 并放下user_age_bin_numeric

在数据进入模型之前,先保存包含两个字段的数据副本。这样,如果您想显示预测而不是数字分类,则可以将预测与分类字段的字符串版本匹配。