AnyMath 文档
Notebook

医疗医疗报告分析

在本演示中,将使用分析工具分析医疗数据。

在分析数据集期间,为医生工作的一致性和准确性计算了几个指标。

必须安装库

您必须手动指定项目所在的路径才能转到工作目录,以及安装必要的依赖项。

In [ ]:
!cd /user/Demo_public/biomedical/analis_medical_result
In [ ]:
 !pip install -r /user/Demo_public/biomedical/analis_medical_result/requirements.txt
In [ ]:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.metrics import cohen_kappa_score
from statsmodels.stats.inter_rater import fleiss_kappa
import numpy as np
from sklearn.metrics import accuracy_score, recall_score, confusion_matrix, balanced_accuracy_score, mean_squared_error
from sklearn.metrics import precision_recall_curve, average_precision_score, f1_score, fbeta_score, roc_auc_score,ConfusionMatrixDisplay, roc_curve, auc
from sklearn.preprocessing import MinMaxScaler
from scipy.stats import sem, t

让我们读取数据并查看dataframe的前5行中包含的内容。

In [ ]:
focus = pd.read_csv('/user/Demo_public/biomedical/analis_medical_result/Date。csv档案源')
In [ ]:
focus.head()
Out[0]:
ID Файла Врач№1 Врач№2 Врач№3 Врач№4 Врач№5 Врач№6 Врач№7 Врач№8 Врач№9 Врач№10 Врач№11 Врач№12 Врач№13 Врач№14 Врач№15
0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
2 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
4 4 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1
In [ ]:
focus = focus.drop('文件ID', axis=1)

这些文件包含图像的标记。 15名医生中的每一位都根据476张照片在没有或存在病理学的情况下做出结论。

您可以估计每张图片对病理学有信心的医生数量,并预先评估哪里真的有病理学,哪里没有病理学。 你也可以在医生的结果中寻找强烈的差异。 有可能确定医生在病理学的定义中有多少相互同意。

我们将评估每位病理医生的标记质量。

In [ ]:
focus_corr = focus.corr(method='spearman')
filtered = focus_corr.where(focus_corr > 0.5).abs()

从相关表中可以看出,关于妇科的决定至少有50%重合的医生并不多。 存在弱相关性。

然而,有两对医生(3和13)(12和10)具有平均相关强度。 这清楚地表明,这两对往往使大多数图片相同的标记。 这可能表明它们之间关于图像中是否存在病理的高度一致性。

In [ ]:
focus_corr_ = focus.corr(method='spearman')
filtered_ = focus_corr_.where(focus_corr < 0.1)

也有一对医生给出完全相反的答案,这意味着他们的意见相差几乎100%。

In [ ]:
focus_corr_mean = focus_corr.mean(axis=1).sort_values(ascending=False)
focus_corr_mean
Out[0]:
医生。1 0.425707
医生。3 0.394424
医生。12 0.392694
医生。10 0.384297
医生。9 0.384255
医生。13 0.376615
医生。14 0.336404
医生。5 0.328782
医生。4 0.322743
医生编号110.317238
医生。15 0.316465
医生。6 0.312953
医生编号20.307039
医生。7 0.297679
医生。8 0.143105
dtype: float64

上表显示了每个医生与其他医生的平均相关性,这些信息清楚地表明每个医生的意见与其他人的认同程度。

In [ ]:
plt.figure(figsize=(8,8))
sns.heatmap(focus_corr.round(2), annot=True, center=0, cmap='inferno')
plt.title('医生标记之间的相关性')
Out[0]:
Text(0.5, 1.0, '医生标记之间的相关性')
In [ ]:
plt.figure(figsize=(8,8))
sns.heatmap(filtered.round(2), annot=True, center=0, cmap='inferno')
plt.title('医生标记与平均相关强度的相关性')
Out[0]:
Text(0.5, 1.0, '医生标记与平均相关强度的相关性')

让我们看看有多少医生对每张图片的病理学百分比有信心。

In [ ]:
confidence = focus.sum(axis=1).sort_values(ascending=False) / focus.shape[1] * 100
confidence.head(20)
Out[0]:
433    100.000000
394     86.666667
28      80.000000
346     80.000000
352     80.000000
359     73.333333
182     73.333333
134     73.333333
113     73.333333
383     73.333333
398     73.333333
153     73.333333
295     66.666667
120     66.666667
342     60.000000
103     60.000000
341     53.333333
387     53.333333
339     53.333333
192     53.333333
dtype: float64

因此,在上表中,您可以观察到相应ID的图片中病理的百分比概率,同时考虑到医生的决定。

In [ ]:
average_marking = focus.mean(axis=1)
In [ ]:
average_doctor_deviation = focus.sub(average_marking, axis=0).abs().mean().sort_values(ascending=False)
average_doctor_deviation
Out[0]:
医生编号150.245702
医生编号20.211880
医生6号0.168553
医生7号0.153878
医生。8 0.145073
医生。4 0.144095
医生。12 0.140741
医生。14 0.124948
医生。11 0.122991
医生。 10 0.121454
医生编号10.117540
医生编号50.116841
医生编号90.116143
医生。13 0.110552
医生。3 0.106918
dtype: float64

15号医生的平均偏差最高(0.2457),这意味着他的标记与所有医生的平均标记显着不同。 这可能表明标记中可能存在的错误。

3号医生的平均偏差最低(0.1069),这表明他的标记与所有医生的平均标记的高度一致性。 这位医生最常以与其他大多数医生相同的方式标记照片。

因此,在这里获得了与所有医生的平均标记的平均偏差。

接下来,我们计算医生评估的协方差矩阵

In [ ]:
covariance_matrix = focus.cov()
covariance_matrix
Out[0]:
Врач№1 Врач№2 Врач№3 Врач№4 Врач№5 Врач№6 Врач№7 Врач№8 Врач№9 Врач№10 Врач№11 Врач№12 Врач№13 Врач№14 Врач№15
Врач№1 0.094031 0.046544 0.032090 0.029244 0.031869 0.054032 0.030905 0.004118 0.033649 0.046152 0.026346 0.047610 0.033750 0.041832 0.048782
Врач№2 0.046544 0.181157 0.022775 0.038361 0.020176 0.038414 0.016357 0.008676 0.025206 0.047540 0.023492 0.061801 0.028082 0.033111 0.060079
Врач№3 0.032090 0.022775 0.051645 0.022770 0.020017 0.022466 0.026743 0.007183 0.029262 0.021814 0.021431 0.027699 0.030407 0.027047 0.027972
Врач№4 0.029244 0.038361 0.022770 0.107033 0.018313 0.038643 0.020387 0.011500 0.030209 0.040260 0.016780 0.049346 0.020158 0.015248 0.039612
Врач№5 0.031869 0.020176 0.020017 0.018313 0.053512 0.017917 0.020176 0.004955 0.026994 0.023704 0.012883 0.021088 0.019780 0.020572 0.016846
Врач№6 0.054032 0.038414 0.022466 0.038643 0.017917 0.138479 0.016939 -0.003788 0.030896 0.040022 0.020031 0.047073 0.023871 0.026346 0.055983
Врач№7 0.030905 0.016357 0.026743 0.020387 0.020176 0.016939 0.110195 0.015446 0.025673 0.023030 0.033296 0.034023 0.017811 0.023307 0.034168
Врач№8 0.004118 0.008676 0.007183 0.011500 0.004955 -0.003788 0.015446 0.057220 0.003550 0.000172 0.008390 0.009967 0.004827 0.001321 0.007201
Врач№9 0.033649 0.025206 0.029262 0.030209 0.026994 0.030896 0.025673 0.003550 0.073472 0.036084 0.021788 0.038705 0.026826 0.027086 0.037326
Врач№10 0.046152 0.047540 0.021814 0.040260 0.023704 0.040022 0.023030 0.000172 0.036084 0.090693 0.016133 0.058731 0.023492 0.025369 0.054225
Врач№11 0.026346 0.023492 0.021431 0.016780 0.012883 0.020031 0.033296 0.008390 0.021788 0.016133 0.064531 0.025540 0.023241 0.019542 0.021524
Врач№12 0.047610 0.061801 0.027699 0.049346 0.021088 0.047073 0.034023 0.009967 0.038705 0.058731 0.025540 0.125478 0.029183 0.023691 0.067874
Врач№13 0.033750 0.028082 0.030407 0.020158 0.019780 0.023871 0.017811 0.004827 0.026826 0.023492 0.023241 0.029183 0.055371 0.024602 0.026730
Врач№14 0.041832 0.033111 0.027047 0.015248 0.020572 0.026346 0.023307 0.001321 0.027086 0.025369 0.019542 0.023691 0.024602 0.075234 0.028302
Врач№15 0.048782 0.060079 0.027972 0.039612 0.016846 0.055983 0.034168 0.007201 0.037326 0.054225 0.021524 0.067874 0.026730 0.028302 0.208657
In [ ]:
covariance_matrix_mean = covariance_matrix.mean(axis=1).sort_values(ascending=False)
covariance_matrix_mean
Out[0]:
医生。15 0.049.019
医生。12 0.044520
医生编号20.043451
医生。1 0.040064
医生。6 0.037822
医生。10 0.036495
医生。4 0.033191
医生。9 0.031115
医生。7 0.029897
医生。14 0.027507
医生。3 0.026088
医生。13 0.025875
医生。11 0.023663
医生。5 0.021920
医生。8 0.009383
dtype: float64

15号医生的平均协方差最高(0.0525)。 这表明15号医生的标记平均与其他医生的标记更一致。 这位医生最常以与其他医生相同的方式注意到病理的存在或不存在。

8号医生的平均协方差最低(0.0101)。 这表明8号医生的标记平均与其他医生的标记不太一致。 这位医生最常评估病理的存在或不存在与其他医生不同。

可以看出,15号医生的平均协方差最高,平均偏差最高。 这可能是由于医生对图片中病理的看法与大多数意见一致,但是,他可能会比其他人更经常地注意到隐藏的特征,并且稍微高估了它们。

In [ ]:
doctor_13 = focus['13号医生']
doctor_3 = focus['三号医生']
doctor_12 = focus['12号医生']
doctor_10 = focus['十号医生']
In [ ]:
cohen_kappa_score(doctor_13, doctor_3), cohen_kappa_score(doctor_12, doctor_10)
Out[0]:
(np.float64(0.5681836885853017), np.float64(0.5380704515191865))

这确认了根据图像的估计的最高度一致的对的相关表。

In [ ]:
counts = np.zeros((focus.shape[0], 2), dtype=int)
for idx, row in focus.iterrows():
  counts[idx, 0] = (row == 0).sum()
  counts[idx, 1] = (row == 1).sum()
In [ ]:
fleiss_kappa(counts)
Out[0]:
np.float64(0.2591132582884047)

该测试显示所有医生的注释的一致性。 从结果中可以看出,一致性很低,医生对病理的存在有分歧。

In [ ]:
kappa_scores = pd.DataFrame(focus.columns, focus.columns)
In [ ]:
for col in focus.columns:
  for col_ in focus.columns:
    kappa_scores.loc[col, col_] = cohen_kappa_score(focus[col], focus[col_])
kappa_scores = kappa_scores.drop([0], axis=1)

由于这个标志,你可以找出哪些医生彼此更同意。

In [ ]:
kappa_scores_mean = kappa_scores.mean(1).sort_values(ascending=False)
kappa_scores_mean
Out[0]:
医生1号0.411056
医生。12 0.374667
医生。10 0.370726
医生。9 0.370257
医生。3 0.369324
医生。13 0.355202
医生。14 0.324713
医生。4 0.311602
医生。5 0.310791
医生。11 0.304169
医生6号0.296735
医生。7 0.286314
医生编号20.275085
医生编号150.270183
医生。8 0.137958
dtype: float64

从这个板块可以看出,15号医生在医生中具有最低的平均网络一致性之一。

Kappa Cohen系数与相关表不同,调节随机巧合

这可能是由于这样的事实,医生经常同意与其他医生,但他做出更积极或消极的诊断。

让我们从医生的平均值计算医生结果的标准偏差

In [ ]:
standard_deviation_mean=focus.sub(focus.mean(axis=1), axis=0).pow(2).mean().sort_values(ascending=False)
standard_deviation_mean
Out[0]:
医生。15 0.174125
医生编号20.140303
医生。6 0.096976
医生。7 0.082301
医生。8 0.073496
医生。4 0.072518
医生。12 0.069164
医生。 14 0.053371
医生。11 0.051414
医生。10 0.049877
医生。1 0.045963
医生。5 0.045264
医生。9 0.044566
医生。13 0.038975
医生。3 0.035341
dtype: float64

在这种情况下,来自医生平均值的MSE有助于了解哪些医生具有最高偏差,他们最常给出与其他医生不一致的特定快照的估计。

In [ ]:
std_mean=focus.std().sort_values(ascending=False)
std_mean
Out[0]:
医生。15 0.456790
医生编号20.425625
医生。6 0.372128
医生。12 0.354229
医生。7 0.331956
医生。4 0.327159
医生。1 0.306645
医生。10 0.301153
医生。 14 0.274288
医生。9 0.271057
医生编号110.254030
医生。8 0.239208
医生。13 0.235310
医生5号0.231327
医生。3 0.227254
dtype: float64

COEX系统有助于看到变异最大的医生.

接下来,我们将为每张图片获得一个"参考分数",该分数将根据选票总和计算,也就是说,如果大多数医生赞成具有病理,那么我们设置1,否则-0。

In [ ]:
diagnosis_major = pd.Series([0 if x > y else 1 for x, y in zip(counts[:, 0], counts[:, 1])])
In [ ]:
accuracy_df = focus.apply(lambda x: accuracy_score(diagnosis_major, x)).sort_values(ascending=False)
accuracy_df
Out[0]:
医生。3 0.955975
医生。5 0.949686
医生。13 0.947589
医生。9 0.943396
医生。1 0.943396
医生。14 0.932914
医生。11 0.928721
医生。10 0.926625
医生。12 0.893082
医生。4 0.888889
医生。7 0.884696
医生。8 0.882600
医生6号0.870021
医生编号20.807128
医生。15 0.761006
dtype: float64

在上表中,医生图像评估的准确性是在与基于多数概念获得的参考估计的比较中获得的,即医生对特定图像的诊断的确认越多,它确实是病理的可能性越高。

In [ ]:
recall_df = focus.apply(lambda x: recall_score(diagnosis_major, x)).sort_values(ascending=False)
recall_df
Out[0]:
医生。15 0.965517
医生。1 0.896552
医生编号20.862069
医生。12 0.827586
医生。6 0.793103
医生。10 0.724138
医生编号90.689655
医生。14 0.620690
医生。7 0.586207
医生。4 0.586207
医生。3 0.586207
医生。5 0.551724
医生。13 0.551724
医生编号110.482759
医生。8 0.034483
dtype: float64

召回可用于评估医生正确识别图像中病理存在的频率。

In [ ]:
columns = focus.columns
confusion_matrices = {}
for column in columns:
  confusion_matrix_ = confusion_matrix(diagnosis_major, focus[column])
  confusion_matrices[column] = confusion_matrix_.sum() - np.diag(confusion_matrix_).sum()
In [ ]:
errors_df = pd.DataFrame(list(confusion_matrices.items()), columns=['医生', '错误数']).sort_values(ascending=False, by='错误数')
errors_df
Out[0]:
Врач Количество ошибок
14 Врач№15 114
1 Врач№2 92
5 Врач№6 62
7 Врач№8 56
6 Врач№7 55
3 Врач№4 53
11 Врач№12 51
9 Врач№10 35
10 Врач№11 34
13 Врач№14 32
0 Врач№1 27
8 Врач№9 27
12 Врач№13 25
4 Врач№5 24
2 Врач№3 21

通过计算FP+FN,我们可以看到哪些医生的错误最多。

In [ ]:
counts[:, 0].sum(), counts[:, 1].sum()
Out[0]:
(np.int64(6316), np.int64(839))

(6316,839)-医生诊断的总数。 6316-医生对病理缺席的投票数量,839-存在。 正如你所看到的,有一个轻微的类不平衡,让我们尝试从sklearn应用accuracy_balanced。

In [ ]:
balanced_df = focus.apply(lambda x: balanced_accuracy_score(diagnosis_major, x)).sort_values(ascending=False)
balanced_df
Out[0]:
医生。1 0.921490
医生。12 0.862454
医生。15 0.856643
医生。6 0.834052
医生编号20.832820
医生。10 0.831935
医生。9 0.824738
医生。14 0.786907
医生。3 0.783059
医生5号0.763585
医生。13 0.762469
医生。4 0.747345
医生。7 0.745112
医生。11 0.720174
医生。8 0.485991
dtype: float64

让我们构建图表,直观地显示关于哪个医生最好地应对诊断的信息。 总共计算了10个指标,我们将构建10个图表。

In [ ]:
colors = ['blue', 'green', 'red', 'purple', 'orange', 'yellow', 'brown', 'pink', 'gray', 'cyan', 'magenta', 'lime', 'teal', 'navy']

fig, axes = plt.subplots(nrows=5, ncols=2,figsize=(13, 24))
axes = axes.flatten()
axes[0].bar(focus_corr_mean.index.tolist(), focus_corr_mean.values.tolist(), color=colors[0])
axes[0].set_title('医生的平均相关性')
axes[0].set_xlabel('医生')
axes[0].set_ylabel('平均相关性')
axes[0].tick_params(axis='x', rotation=45)
axes[1].bar(average_doctor_deviation.index.tolist(), average_doctor_deviation.values.tolist(), color=colors[1])
axes[1].set_title('医生的平均偏差')
axes[1].set_xlabel('医生')
axes[1].set_ylabel('平均偏差')
axes[1].tick_params(axis='x', rotation=45)
axes[2].bar(covariance_matrix_mean.index.tolist(), covariance_matrix_mean.values.tolist(), color=colors[2])
axes[2].set_title('医生平均协方差')
axes[2].set_xlabel('医生')
axes[2].set_ylabel('平均协方差')
axes[2].tick_params(axis='x', rotation=45)
axes[3].bar(kappa_scores_mean.index.tolist(), kappa_scores_mean.values.tolist(), color=colors[3])
axes[3].set_title('医生的平均Capo-Cohen评分')
axes[3].set_xlabel('医生')
axes[3].set_ylabel('平均Capo-Cohen得分')
axes[3].tick_params(axis='x', rotation=45)
axes[4].bar(standard_deviation_mean.index.tolist(), standard_deviation_mean.values.tolist(), color=colors[4])
axes[4].set_title('根据医生的标准偏差')
axes[4].set_xlabel('医生')
axes[4].set_ylabel('标准偏差')
axes[4].tick_params(axis='x', rotation=45)
axes[5].bar(std_mean.index.tolist(), std_mean.values.tolist(), color=colors[5])
axes[5].set_title('医生平均COE')
axes[5].set_xlabel('医生')
axes[5].set_ylabel('平均COE')
axes[5].tick_params(axis='x', rotation=45)
axes[6].bar(accuracy_df.index.tolist(), accuracy_df.values.tolist(), color=colors[6])
axes[6].set_title('医生的多数准确性')
axes[6].set_xlabel('医生')
axes[6].set_ylabel('多数精度')
axes[6].tick_params(axis='x', rotation=45)
axes[7].bar(recall_df.index.tolist(), recall_df.values.tolist(), color=colors[7])
axes[7].set_title('医生的多数完整性')
axes[7].set_xlabel('医生')
axes[7].set_ylabel('多数完整性')
axes[7].tick_params(axis='x', rotation=45)
axes[8].bar(errors_df['医生'], errors_df['错误数'], color=colors[8])
axes[8].set_title('医生的错误')
axes[8].set_xlabel('医生')
axes[8].set_ylabel('完整性错误')
axes[8].tick_params(axis='x', rotation=45)
axes[9].bar(balanced_df.index.tolist(), balanced_df.values.tolist(), color=colors[9])
axes[9].set_title('医生的多数平衡准确性')
axes[9].set_xlabel('医生')
axes[9].set_ylabel('多数平衡精度')
axes[9].tick_params(axis='x', rotation=45)
plt.subplots_adjust(hspace=0.6)
plt.tight_layout()

让我们分析这些图表:医生之间平均相关性较高的医生通常与其他医生对图像的看法相同。 高协方差负责变异性,即该参数越高,特定医生的结果与图像上所有医生的意见差异越大。 Copa-Cohen评分有助于确定医生与其他医生的决定是否一致。 这个分数与平均相关性不同,考虑了医疗决策的随机性。

平均偏差,标准偏差,有助于查看特定医生的意见与医生的平均意见有多大偏差,但COE给出了医生平均估计的变化的数值指示,也就是说,粗略地说,医生的

计算每个图像的多数评级,即根据多数意见评估病理学。 我们会认为这是一个基准。 准确性表明医生能够正确做出诊断(病理的缺失和存在)的程度,但完整性表明医生在真正存在的情况下发现病理的程度。 平衡准确度是在没有病理时医生预测的病例数倍于存在时的情况下计算的,即轻微的不平衡。

In [ ]:
fig, axes = plt.subplots(figsize=(7, 7))
axes.bar(accuracy_df.index.tolist(), accuracy_df.values.tolist(), color=colors[6], alpha=1, label='多数精度')
axes.set_title('医生的多数准确度和平衡准确度')
axes.set_xlabel('医生')
axes.set_ylabel('多数精度,平衡精度')
axes.tick_params(axis='x', rotation=45)
axes.bar(balanced_df.index.tolist(), balanced_df.values.tolist(), color=colors[9], alpha=0.5, label='多数平衡精度')
axes.legend()
axes.set_ylim(0, 1.25)
plt.tight_layout()
In [ ]:
plt.figure(figsize=(8, 6))
sns.boxplot(data=confidence, orient='v', color='lightblue')
plt.ylabel('病理概率(%)')
plt.title('病理的概率分布')
plt.tight_layout()
plt.show()

正如你可以从上面的图表中看到的,大多数图像没有100percent保证那里有病理。 在一张照片中,所有的医生都说有一个病理。

让我们尝试创建一个综合上述所有指标的单一指标

让我们为每种疾病选择最糟糕的医生。

In [ ]:
metrics_df = pd.concat([focus_corr_mean, average_doctor_deviation, covariance_matrix_mean, kappa_scores_mean, standard_deviation_mean, std_mean, accuracy_df, recall_df, balanced_df, errors_df.set_index('医生')['错误数']], axis=1)
metrics_df.columns=['focus_corr_mean', 'average_doctor_deviation', 'covariance_matrix_mean', 'kappa_scores_mean', 'standard_deviation_mean', 'std_mean', 'accuracy_df', 'recall_df', 'balanced_df', 'errors_df']
In [ ]:
metrics_df
Out[0]:
focus_corr_mean average_doctor_deviation covariance_matrix_mean kappa_scores_mean standard_deviation_mean std_mean accuracy_df recall_df balanced_df errors_df
Врач№1 0.425707 0.117540 0.040064 0.411056 0.045963 0.306645 0.943396 0.896552 0.921490 27
Врач№3 0.394424 0.106918 0.026088 0.369324 0.035341 0.227254 0.955975 0.586207 0.783059 21
Врач№12 0.392694 0.140741 0.044520 0.374667 0.069164 0.354229 0.893082 0.827586 0.862454 51
Врач№10 0.384297 0.121454 0.036495 0.370726 0.049877 0.301153 0.926625 0.724138 0.831935 35
Врач№9 0.384255 0.116143 0.031115 0.370257 0.044566 0.271057 0.943396 0.689655 0.824738 27
Врач№13 0.376615 0.110552 0.025875 0.355202 0.038975 0.235310 0.947589 0.551724 0.762469 25
Врач№14 0.336404 0.124948 0.027507 0.324713 0.053371 0.274288 0.932914 0.620690 0.786907 32
Врач№5 0.328782 0.116841 0.021920 0.310791 0.045264 0.231327 0.949686 0.551724 0.763585 24
Врач№4 0.322743 0.144095 0.033191 0.311602 0.072518 0.327159 0.888889 0.586207 0.747345 53
Врач№11 0.317238 0.122991 0.023663 0.304169 0.051414 0.254030 0.928721 0.482759 0.720174 34
Врач№15 0.316465 0.245702 0.049019 0.270183 0.174125 0.456790 0.761006 0.965517 0.856643 114
Врач№6 0.312953 0.168553 0.037822 0.296735 0.096976 0.372128 0.870021 0.793103 0.834052 62
Врач№2 0.307039 0.211880 0.043451 0.275085 0.140303 0.425625 0.807128 0.862069 0.832820 92
Врач№7 0.297679 0.153878 0.029897 0.286314 0.082301 0.331956 0.884696 0.586207 0.745112 55
Врач№8 0.143105 0.145073 0.009383 0.137958 0.073496 0.239208 0.882600 0.034483 0.485991 56

让我们总结一下指标

In [ ]:
scaler = MinMaxScaler()
normalized_df = pd.DataFrame(scaler.fit_transform(metrics_df), index=metrics_df.index, columns=metrics_df.columns)
In [ ]:
normalized_df
Out[0]:
focus_corr_mean average_doctor_deviation covariance_matrix_mean kappa_scores_mean standard_deviation_mean std_mean accuracy_df recall_df balanced_df errors_df
Врач№1 1.000000 0.076536 0.774068 1.000000 0.076536 0.345876 0.935484 0.925926 1.000000 0.064516
Врач№3 0.889305 0.000000 0.421469 0.847191 0.000000 0.000000 1.000000 0.592593 0.682131 0.000000
Врач№12 0.883183 0.243706 0.886512 0.866755 0.243706 0.553179 0.677419 0.851852 0.864440 0.322581
Врач№10 0.853470 0.104733 0.684026 0.852324 0.104733 0.321947 0.849462 0.740741 0.794362 0.150538
Врач№9 0.853321 0.066465 0.548299 0.850607 0.066465 0.190834 0.935484 0.703704 0.777837 0.064516
Врач№13 0.826287 0.026183 0.416106 0.795481 0.026183 0.035093 0.956989 0.555556 0.634853 0.043011
Врач№14 0.683997 0.129909 0.457279 0.683842 0.129909 0.204907 0.881720 0.629630 0.690969 0.118280
Врач№5 0.657025 0.071501 0.316315 0.632860 0.071501 0.017741 0.967742 0.555556 0.637416 0.032258
Врач№4 0.635656 0.267875 0.600673 0.635830 0.267875 0.435245 0.655914 0.592593 0.600124 0.344086
Врач№11 0.616178 0.115811 0.360295 0.608615 0.115811 0.116653 0.860215 0.481481 0.537734 0.139785
Врач№15 0.613442 1.000000 1.000000 0.484167 1.000000 1.000000 0.000000 1.000000 0.851096 1.000000
Врач№6 0.601015 0.444109 0.717502 0.581393 0.444109 0.631160 0.559140 0.814815 0.799222 0.440860
Врач№2 0.580087 0.756294 0.859540 0.502117 0.756294 0.864227 0.236559 0.888889 0.796394 0.763441
Врач№7 0.546967 0.338369 0.517571 0.543235 0.338369 0.456147 0.634409 0.592593 0.594998 0.365591
Врач№8 0.000000 0.274924 0.000000 0.000000 0.274924 0.052077 0.623656 0.000000 0.000000 0.376344

让我们为每个指标设置一个加权因子

In [ ]:
weights = {
    'kappa_scores_mean': 0.3,
    'covariance_matrix_mean': -0.2,
    'average_doctor_deviation': -0.25,
    'focus_corr_mean': 0.25,
    'balanced_accuracy': 0.25,
    'recall': 0.25,
    'accuracy': 0.25,
    'std_mean': -0.15,
    'standard_deviation_mean': -0.10,
    'errors_df': -0.2
}

让我们将组合度量计算为将加权系数乘以归一化度量,并将它们求和

In [ ]:
normalized_df['final_score'] = (normalized_df * pd.Series(weights)).sum(axis=1)
In [ ]:
normalized_df['final_score'].sort_values(ascending=False)
Out[0]:
医生。3 0.392190
医生编号130.338965
医生。1 0.303614
医生。9 0.294062
医生5号0.256713
医生。10 0.217204
医生。14 0.184836
医生。11 0.178581
医生。12 0.070730
医生。4 0.001668
医生编号7-0.063771
医生。6 -0.157113
医生。8 -0.179304
医生编号2-0.423276
医生。15 -0.601389
Name: final_score, dtype: float64

因此,基于现有的指标,我们编写了自己的指标,计算它,并获得了医生的"评级"。

In [ ]:
plt.figure(figsize=(10, 6))
sns.barplot(x=normalized_df['final_score'].sort_values(ascending=False).values, y=normalized_df['final_score'].sort_values(ascending=False).index, palette='coolwarm')
plt.title('医生的评级')
plt.xlabel('评级')
plt.ylabel('医生')
plt.show()
/tmp/ipykernel_201/2568690680.py:2: FutureWarning: 

Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `y` variable to `hue` and set `legend=False` for the same effect.

  sns.barplot(x=normalized_df['final_score'].sort_values(ascending=False).values, y=normalized_df['final_score'].sort_values(ascending=False).index, palette='coolwarm')

正如你可以从上面的图表中看到,最糟糕的医生是- 15, 2, 8, 6, 7

让我们形成最终的标记并计算医生的信心。

你可以考虑到医生的整体评级,也就是说,如果15个医生中有14个放了1个,那么就有病理学等等。 但是,可以考虑医生的评级。

让我们计算最终的诊断

In [ ]:
votes = focus.sum(axis=1)
f = focus * normalized_df['final_score']
final_votes = (f.sum(1) > 0.4).astype(int)
confidence__ = focus.sum(axis=1)
weights_ = {
    'doctor' : 0.4,
    'confidence': 0.6
}

Diagnosis_weights = ((confidence__ / focus.shape[1]) * weights_['confidence'] + (f.sum(1) > 0.4).astype(int) * weights_['doctor'])
Diagnosis = (Diagnosis_weights >= 0.36).astype(int)
In [ ]:
Diagnosis.sum()
Out[0]:
np.int64(25)

让我们计算医生的信心

In [ ]:
normalized_diagnosis_weights = (Diagnosis_weights - np.min(Diagnosis_weights)) / (np.max(Diagnosis_weights) - np.min(Diagnosis_weights))
confidence = normalized_diagnosis_weights * 100
confidence.sort_values(ascending=False)
Out[0]:
433    100.0
394     92.0
28      88.0
346     88.0
352     88.0
       ...  
472      0.0
3        0.0
474      0.0
475      0.0
1        0.0
Length: 477, dtype: float64

我们来计算置信区间

In [ ]:
mean = np.mean(Diagnosis_weights)
std_err = sem(Diagnosis_weights)

confidence_level = 0.95
n = len(Diagnosis_weights)
h = std_err * t.ppf((1 + confidence_level) / 2, n - 1)

lower_bound = mean - h
upper_bound = mean + h

# 置信区间输出
print(f"置信区间:[{lower_bound},{upper_bound}]")
置信区间:[0.07206422989620075,0.1021915353029607]

让我们分析接收到的数据。

Pd。系列诊断包含关于特定图像的确切诊断的摘要标签。 诊断是根据医生的评分计算的,并且还考虑了病理的可能性。 将特定图像的这种概率计算为图像上医生标记的平均值。

图像中是否存在病理的最终概率,基于上述数据,被计算为上述分量的加权和
以0.4的权重计算医生的评级,基于平均值的概率权重为0.6。 选择这些权重是因为,如果15名医生中有14名医生确认没有病理,并且评分最高的1名医生(例如0.4)表示有病理,那么加权总和将很高,结果会出现假阳性。 归一化_diagnosis_weights-加权和。

normalized_diagnosis_weights-图像中是否存在病理的确定性。 她得到了回报。 基于该置信度,选择图像的最终标签。

我取了0.4的阈值,即如果诊断的权重超过0.4,则存在病理学。 结果:揭示了25个具有病理学的图像。

还计算了诊断确定性的置信区间,其中大多数概率为95%[0.07206422989620075, 0.1021915353029607], 也就是说,大多数图像的最终诊断为0

In [ ]:
df = pd.concat([Diagnosis, confidence], axis=1)
df.columns = ['Diagnosis', 'Probability, %']
df['Probability, %'] = df.apply(lambda row: 100 - row['Probability, %'] if row['Diagnosis'] == 0 else row['Probability, %'], axis=1)
df
Out[0]:
Diagnosis Probability, %
0 0 92.0
1 0 100.0
2 0 96.0
3 0 100.0
4 0 88.0
... ... ...
472 0 100.0
473 0 84.0
474 0 100.0
475 0 100.0
476 0 96.0

477 rows × 2 columns

上面的dataframe包含最终诊断和诊断确实正确的百分比概率。 对于每张图片,记录诊断和诊断正确的概率。

让我们评估每种病理的标记的最终质量。

In [ ]:
mean_probability = np.mean(Diagnosis_weights)
print(f"平均概率:{mean_probability}")

# 概率的标准差
std_deviation = np.std(Diagnosis_weights)
print(f"概率的标准差:{std_deviation}")

# 最大和最小概率
max_probability = np.max(Diagnosis_weights)
min_probability = np.min(Diagnosis_weights)
print(f"最大概率:{max_probability}")
print(f"最小概率:{min_probability}")
平均概率:0.08712788259958072
概率标准差:0.16725534527288208
最大概率:1.0
最小概率:0.0

正如你所看到的,大多数诊断都是阴性的,也就是说,没有病理。

In [ ]:
accuracy_d = accuracy_score(diagnosis_major, Diagnosis)
recall_d = recall_score(diagnosis_major, Diagnosis)
balanced_accuracy_d = balanced_accuracy_score(diagnosis_major, Diagnosis)
F1_d = f1_score(diagnosis_major, Diagnosis)
fbeta_d = fbeta_score(diagnosis_major, Diagnosis, beta=0.5)
roc_auc_d = roc_auc_score(diagnosis_major, Diagnosis)
print(f"精度:{accuracy_d}")
print(f"完整性:{recall_d}")
print(f"平衡精度:{balanced_accuracy_d}")
print(f"F1: {F1_d}")
print(f"Fbeta: {fbeta_d}")
print(f"roc-auc: {roc_auc_d}")
准确度:0.9622641509433962
完整性:0.6206896551724138
平衡精度:0.8025323275862069
F1: 0.6666666666666666
Fbeta: 0.6976744186046512
roc-auc: 0.8025323275862069

高准确度(96.2%)表明大多数预测是正确的。

完整性(62.1%)表明缺少一些阳性病例。

平衡精度(80.3%)和ROC-AUC(80.3%)-良好的阶级辨别能力。

F1评分(66.7%)和Fbeta评分(69.8%)表明最终诊断质量平衡。

In [ ]:
confusion_matrix_ = confusion_matrix(diagnosis_major, Diagnosis)
disp = ConfusionMatrixDisplay(confusion_matrix_)
disp.plot(cmap=plt.cm.Blues)
plt.title('Confusion Matrix')
Out[0]:
Text(0.5, 1.0, 'Confusion Matrix')

误差矩阵清楚地表明,没有很多误诊。

In [ ]:
precision, recall, _ = precision_recall_curve(diagnosis_major, Diagnosis)
average_precision = average_precision_score(diagnosis_major, Diagnosis)

plt.figure()
plt.step(recall, precision, where='post', color='b', alpha=0.2, linestyle='-', linewidth=2, label='Precision-Recall curve')
plt.fill_between(recall, precision, step='post', alpha=0.2, color='b')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.title('Precision-Recall curve: AP={0:0.2f}'.format(average_precision))
plt.legend(loc="lower left")
Out[0]:
<matplotlib.legend.Legend at 0x7f8fa9817790>

从上面的图表中可以看出,准确性比完整性更重要,但是,从图表中可以看出,精度略低于准确性,这表明不准确的阳性诊断。

从上面的标记质量评估可以看出,标记执行得相当好,存在很小的差距。 然而,值得考虑的是,"参考标记",可以这么说,目标,由医生计算为平均分数,可能无法准确反映现实。 这是因为一些医生的评分很低,甚至平均值也可能不准确。 然而,值得考虑的是,医生虽然很低,但具有一致性,这可能表明最终标记一致性的正确性。

结论

在这个例子中,使用数据分析方法对医生的结论进行了分析。