在我通过 pandas.cut() 函数创建 bin 后,如何有效地将每个值标记为 bin?
How to efficiently label each value to a bin after I created the bins by pandas.cut() function?
假设我在数据框中有一列 '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:编辑了措辞,希望问题现在更清楚了。
您可以尝试类似的方法:
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 替换为类似语法的格式。
双列表理解的有点丑陋的方法,但似乎可以完成工作。
设置:
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
您不能将字符串放入模型中,因此您需要创建一个映射并跟踪它或创建一个单独的列供以后使用
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
并删除 user_age_bin_string
在进入模型之前,保存包含两个字段的数据副本。这样您就可以将预测匹配回 bin 字段的字符串版本,如果您想显示这些而不是数字 bin。
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
假设我在数据框中有一列 '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:编辑了措辞,希望问题现在更清楚了。
您可以尝试类似的方法:
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 替换为类似语法的格式。
双列表理解的有点丑陋的方法,但似乎可以完成工作。
设置:
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
您不能将字符串放入模型中,因此您需要创建一个映射并跟踪它或创建一个单独的列供以后使用
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
并删除 user_age_bin_string
在进入模型之前,保存包含两个字段的数据副本。这样您就可以将预测匹配回 bin 字段的字符串版本,如果您想显示这些而不是数字 bin。
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