python - 在python中,如何使用精度作为考虑类的标准来离散化连续变量
问题描述
对于一组受试者,我有一个范围为 0-100 的连续变量,表示受试者状态的量化cont_attribute
。对于每个主题,我还有一个序数变量,将主题状态的读者注释表示为四种状态之一(例如 1、2、3、4)class_label
。cont_attribute
类之间重叠的值。我的目标是离散化cont_attribute
,以便优化与类的协议。
当离散化时cont_attribute
,任意阈值x1
, x2
,x3
可以直接应用于连续变量,以产生四个序数类别的 bin,并且可以评估与读者注释类的一致性:
cohen_kappa_score((pd.cut(df['cont_attribute'],bins=[0, x1, x2, x3, 100], labels=['1','2','3','4']).astype('int'))
, df['class_label'].astype('int'))
我发现了几个连续变量离散化的选项,例如Jenks natural break和sklearn Kmeans,尽管这些选项没有考虑到类。
我尝试了什么:
我尝试使用 scipy.optimize.minimize 优化上面的函数以产生最大值。这里对于两个类之间的每个阈值,我使用较大类的最小值和较小类的最大值作为找到这些类之间各自最佳截止点的范围。使用这种方法,我遇到了一个问题,提示:
ValueError: bins 必须单调增加。
def objfunc(grid):
x1, x2, x3 = grid
return (cohen_kappa_score((pd.cut(df.cont_attribute,bins=[0, x1, x2, x3, 100],labels=['1','2','3','4'], duplicates='drop').astype('int'))
, df['class_label'].astype('int'))) * (-1);
grid = (slice(df[(df['class_label'] == 2)]['cont_attribute'].min(), df[(df['class_label'] == 1)]['cont_attribute'].max(), 0.5), (slice(df[(df['class_label'] == 3)]['cont_attribute'].min(), df[(df['class_label'] == 2)]['cont_attribute'].max(), 0.5), (slice(df[(df['class_label'] == 4)]['cont_attribute'].min(), df[(df['class_label'] == 3)]['cont_attribute'].max(), 0.5))
solution = brute(objfunc, grid, finish=None,full_output = True)
solution
在 python 中,是否有一种直接优化阈值的方法,x1
考虑到与类的一致性(监督离散化)?或者,如何使用scipy.optimize.minimize重写上述函数以产生最大值?x2
x3
解决方案
错误信息不是太难。pandascut
方法要求切割向量
[0,x1,x2,x3,100]
是严格单调的。通过有一些机制来确保没有无效值被传递给cut
函数,我们是安全的。这就是我在下面实现的。为了表示一个invalid
设置,习惯上使用,np.inf
因为所有其他值都较低。因此,每个 minizmier 都会说这样的无效作为解决方案是不可取的。实现见下文。我还包括了所有的导入和一些数据生成,因此使用代码很简单。请在以后的问题中这样做。
您可能希望在蛮力搜索中为每个维度使用 10 个以上的 bin。
另外 - 代码效率很低。由于它对 x1、x2、x3 的所有组合进行暴力破解,但其中很多是无效的(例如 x2<=x1),您可能希望在 (x1,x2-x1, x3-x2) 中对问题进行参数化,并在第二个和第三个组件中搜索非负值。
最后,该brute
方法是一个最小化器,因此您应该-cohen_kappa
从目标返回
#%%
import numpy as np
from sklearn.metrics import cohen_kappa_score, confusion_matrix
from scipy.stats import truncnorm
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.optimize import brute
#
# Generate Data
#
n = 1000
np.random.seed(0)
y = np.random.choice(4, p=[0.1, 0.3, 0.4, 0.2], size=n)
x = np.zeros(n)
for i in range(5):
low = 0
high = 100
mymean = 20 * i
myscale = 8
a, b = (low - mymean) / myscale, (high - mymean) / myscale
x[y == i] = truncnorm.rvs(a=a, b=b, loc=mymean, scale=myscale, size=np.sum(y == i))
data = pd.DataFrame({"cont_attribute": x, "class_label": y})
# make a loss function that accounts for the bad orderings
def loss(cuts):
x1, x2, x3 = cuts
if 0 >= x1 or x1 >= x2 or x2 >= x3 or x3 >= 100:
return np.inf
yhat = pd.cut(
data["cont_attribute"],
bins=[0, x1, x2, x3, 100],
labels=[0, 1, 2, 3],
# duplicates="drop",
).astype("int")
return -cohen_kappa_score(data["class_label"], yhat)
# Compute the result via brute force
ranges = [(0, 100)] * 3
Ns=30
result = brute(func=loss, ranges=ranges, Ns=Ns)
print(result)
print(-loss(result))
# Evaluate the final result in a confusion matrix
x1, x2, x3 = result
data["class_pred"] = pd.cut(
data["cont_attribute"],
bins=[0, x1, x2, x3, 100],
labels=[0, 1, 2, 3],
duplicates="drop",
).astype("int")
mat = confusion_matrix(y_true=data['class_label'],y_pred=data['class_pred'])
plt.matshow(mat)
# Loop over data dimensions and create text annotations.
for i in range(4):
for j in range(4):
text = plt.text(j, i, mat[i, j],
ha="center", va="center", color="grey")
plt.xlabel('Predicted class')
plt.ylabel('True class')
plt.show()
# Evaluate result graphically
# inspect the data
fig,ax = plt.subplots(2,1)
sns.histplot(data=data, x="cont_attribute", hue="class_label",ax=ax[0],multiple='stack')
sns.histplot(data=data, x="cont_attribute", hue="class_pred",ax=ax[1],multiple='stack')
plt.show()
关于 的使用scipy.optimize.minimize
,当使用 cohen kappa 作为宾语时,这是不可能的。由于它不可微分,因此不太容易优化。考虑改用交叉熵损失函数。但在这种情况下,您将需要一个(参数)模型来执行分类任务。
标准序数分类器在序数回归包中可用statsmodels
。它将比蛮力方法快得多,但在 cohen kappa 上评估时可能不太准确。如果要更多数量的垃圾箱,那么走那条路可能就是我会做的。
推荐阅读
- r - Extracting tables from pdf in R
- json - Kotlin json parsing where "val $t: String"
- eslint - autoFixOnSave 仅适用于某些文件扩展名
- c# - 跳棋c#每个玩家玩一次不可能
- mysql - phpmyadmin 查询导出问题
- vim - VIM 语言语法
- json - How do I Store JSON data in React Native with setState
- docker - 如何从虚拟机加入在 Docker 主机上初始化的 swarm
- session - Loading Tensorflow Graph in other file not giving the same accuracy
- apache-kafka - KSQL 流输出主题