Pandas:根据值在范围内的位置分配类别
Pandas: assign category based on where value falls in range
我有以下范围和一个 pandas DataFrame:
x >= 0 # success
-10 <= x < 0 # warning
X < -10 # danger
df = pd.DataFrame({'x': [2, 1], 'y': [-7, -5], 'z': [-30, -20]})
我想根据值在定义范围内的位置对 DataFrame 中的值进行分类。所以我希望最终的 DF 看起来像这样:
x y z x_cat y_cat z_cat
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
我试过使用 category
数据类型,但似乎无法在任何地方定义范围。
for category_column, value_column in zip(['x_cat', 'y_cat', 'z_cat'], ['x', 'y', 'z']):
df[category_column] = df[value_column].astype('category')
我可以使用 category
数据类型吗?如果没有,我能在这里做什么?
pandas.cut
c = pd.cut(
df.stack(),
[-np.inf, -10, 0, np.inf],
labels=['danger', 'warning', 'success']
)
df.join(c.unstack().add_suffix('_cat'))
x y z x_cat y_cat z_cat
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
numpy
v = df.values
cats = np.array(['danger', 'warning', 'success'])
code = np.searchsorted([-10, 0], v.ravel()).reshape(v.shape)
cdf = pd.DataFrame(cats[code], df.index, df.columns)
df.join(cdf.add_suffix('_cat'))
x y z x_cat y_cat z_cat
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
这是针对此类事物的三元方法。
filter_method = lambda x: 'success' if x >= 0 else 'warning' if (x < 0 and x >= -10) else 'danger' if x < -10 else None
df[category_column] = df[value_column].apply(filter_method)
可以使用pandascut
,但需要逐列应用(只是因为该函数对一维输入进行操作):
labels = df.apply(lambda x: pd.cut(x, [-np.inf, -10, 0, np.inf], labels = ['danger', 'warning', 'success']))
x y z
0 success warning danger
1 success warning danger
所以你可以这样做:
pd.concat([df, labels.add_prefix('_cat')], axis = 1)
x y z cat_x cat_y cat_z
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
您可以编写一个小函数,然后使用 apply 将每个系列传递给该函数:
df = pd.DataFrame({'x': [2, 1], 'y': [-7, -5], 'z': [-30, -20]})
def cat(x):
if x <-10:
return "Danger"
if x < 0:
return "Warning"
return "Success"
for col in df.columns:
df[col] = df[col].apply(lambda x: cat(x))
您可以使用 assign 创建新列。对于每个新列,使用 apply 来过滤系列。
df.assign(x_cat = lambda v: v.x.apply(lambda x: 'Sucess' if x>=0 else None),
y_cat = lambda v: v.y.apply(lambda x: 'warning' if -10<=x<0 else None),
z_cat = lambda v: v.z.apply(lambda x: 'danger' if x<=-10 else None),)
将导致
x y z x_cat y_cat z_cat
0 2 -7 -30 Sucess warning danger
1 1 -5 -20 Sucess warning danger
我有以下范围和一个 pandas DataFrame:
x >= 0 # success
-10 <= x < 0 # warning
X < -10 # danger
df = pd.DataFrame({'x': [2, 1], 'y': [-7, -5], 'z': [-30, -20]})
我想根据值在定义范围内的位置对 DataFrame 中的值进行分类。所以我希望最终的 DF 看起来像这样:
x y z x_cat y_cat z_cat
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
我试过使用 category
数据类型,但似乎无法在任何地方定义范围。
for category_column, value_column in zip(['x_cat', 'y_cat', 'z_cat'], ['x', 'y', 'z']):
df[category_column] = df[value_column].astype('category')
我可以使用 category
数据类型吗?如果没有,我能在这里做什么?
pandas.cut
c = pd.cut(
df.stack(),
[-np.inf, -10, 0, np.inf],
labels=['danger', 'warning', 'success']
)
df.join(c.unstack().add_suffix('_cat'))
x y z x_cat y_cat z_cat
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
numpy
v = df.values
cats = np.array(['danger', 'warning', 'success'])
code = np.searchsorted([-10, 0], v.ravel()).reshape(v.shape)
cdf = pd.DataFrame(cats[code], df.index, df.columns)
df.join(cdf.add_suffix('_cat'))
x y z x_cat y_cat z_cat
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
这是针对此类事物的三元方法。
filter_method = lambda x: 'success' if x >= 0 else 'warning' if (x < 0 and x >= -10) else 'danger' if x < -10 else None
df[category_column] = df[value_column].apply(filter_method)
可以使用pandascut
,但需要逐列应用(只是因为该函数对一维输入进行操作):
labels = df.apply(lambda x: pd.cut(x, [-np.inf, -10, 0, np.inf], labels = ['danger', 'warning', 'success']))
x y z
0 success warning danger
1 success warning danger
所以你可以这样做:
pd.concat([df, labels.add_prefix('_cat')], axis = 1)
x y z cat_x cat_y cat_z
0 2 -7 -30 success warning danger
1 1 -5 -20 success warning danger
您可以编写一个小函数,然后使用 apply 将每个系列传递给该函数:
df = pd.DataFrame({'x': [2, 1], 'y': [-7, -5], 'z': [-30, -20]})
def cat(x):
if x <-10:
return "Danger"
if x < 0:
return "Warning"
return "Success"
for col in df.columns:
df[col] = df[col].apply(lambda x: cat(x))
您可以使用 assign 创建新列。对于每个新列,使用 apply 来过滤系列。
df.assign(x_cat = lambda v: v.x.apply(lambda x: 'Sucess' if x>=0 else None),
y_cat = lambda v: v.y.apply(lambda x: 'warning' if -10<=x<0 else None),
z_cat = lambda v: v.z.apply(lambda x: 'danger' if x<=-10 else None),)
将导致
x y z x_cat y_cat z_cat
0 2 -7 -30 Sucess warning danger
1 1 -5 -20 Sucess warning danger