0%

精准率与召回率

看到的很多文章好像都挺喜欢用正类反类来作为例子进行公式说明。
但我在理解之后,觉得这样好像不是十分妥当。
一是,针对我的业务我可能需要去理解什么是正类,什么是反类,不是label为0就是反类吧。
二是,基于一,就有了问题,何为正?何为反?正反的定义对于指标的理解是否有意义或是帮助?我认为,正反的定义是不必要的。

所以,我觉得。直接使用(某类-另一类)或(某类-[其它类])可以更好的理解指标意义。
总而言之,精准率与召回率指标的定义与所谓正反是无关的,它是基于某类的。
所以:
精准率:某类预测量中实际正确所占比例
召回率:某类实际量中预测正确所占比例

使用某类则可以直接扩展到多类的场景而不需要做什么多余的改变。每个类别都会有自己的精准率与召回率,所以使用某类。
例子就贴一张sklearn.metrics计算的几个指标值以及混淆矩阵,可以手动带入公式看看具体是怎么算的,有助于理解。Markdown

classification report中的avg是使用加权平均计算的,权为样本数量。

合并两个有序数组

思路1:最简单的操作是将nums2直接拼在nums1后面,然后对nums1排序
这样的话会用到python自带的排序算法,也可以自己写一下快排代替。总体来讲是先合并再排序。这样的话就没有使用到给出的有序数组中有序的信息。所以复杂度难免会高一点。

1
2
3
4
def merge(nums1, m, nums2, n):
nums1[m:] = nums2[:n]
nums1.sort()
return nums1

思路2:利用有序信息,依次比较插入nums1中,这种复杂度会低一些,但是边界的判断会复杂一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def merge(nums1, m, nums2, n):
"""
:type nums1: List[int]
:type m: int
:type nums2: List[int]
:type n: int
:rtype: void Do not return anything, modify nums1 in-place instead.
"""
i = m+n-1 # nums1的下标长度
while(i >= 0):
if (len(nums1)==0) or (len(nums2)==0): # 如果有一个数组为空,则直接拼接
nums1[m:] = nums2
elif (m == 0): # 如果nums1已经比较完了,则将nums2的剩余部分赋值到nums1
nums1[i] = nums2[n-1]
n = n - 1
elif (nums1[m-1] >= nums2[n-1]): # 否则比较两数组最后一个元素大小,将大者放入nums1后,并更新下标
nums1[i] = nums1[m-1]
m = m-1
elif (nums1[m-1] < nums2[n-1]) and (n-1>=0): # 判断大小并检查nums2是否判断完毕,如果nums2判断完毕,则不再利用nums中值,避免循环引用
nums1[i] = nums2[n-1]
n = n-1
i = i - 1
return nums1

偶然间,看到当下的陈坤演唱十几年前的《是否还爱我》,被感动。

听了好几遍。

把歌单独找出来又听了几遍。

看到是电视剧主题曲,又把电视剧找来看了。

不由感叹,现在的电视剧都在干些什么啊,不要说情节了,连逻辑都无法自洽,哎。

老剧可能除了画质差一点,其它比现在好太多了。

看完像雾像雨又像风,我真是又有若干感悟,想写下来,算是自己的一点感想吧,其实我也是第一次看,由于年纪大了,不容易感动了,稍微有些感动不容易,也应该记下来。😂

# 珍惜眼前 活在当下
# 男人没本事是不行的
# 没有一技之长便没有立身之地
# 阿坤人家好歹还会修表
# 不要好高骛远觉得自己不得了那是在你自己的小世界里
# 强行跨越阶级会走火入魔水平达不到在其位德不配也会出事
# 滥情就是渣男
# 适合自己的才是最好的

相对于利用二分查找在有序数组中查找目标来说。
在循环有序数组中查找目标会更复杂一点。
循环有序数组指的是数组是分段有序的(且假设只有两段)。

在查阅学习后整理了本版本Python3.6的实现。

具体实现思路:依据定义,循环有序数组具有一个性质就是对原数组进行中间切分之后会形成两个数组,一个是有序数据,另外一个是比原循环有序数组更小的一个循环有序数组。

所有利用这个性质实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 循环有序(递增)序列查找
# 循环有序区间的性质:从中间将原序列进行切分,会得到一个有序序列和一个更小的循环序列。
## 同样采用二分查找的思路,只是多做一步,在采取中间拆分的时候需要多判断一步是否是递增
def cycle_binary_serch(alist, target):
low = 0
high = len(alist) - 1
while low <= high:
mid = (low + high)//2
if alist[mid] == target:
return mid;
if alist[low] <= alist[mid]: # 若前半部分是有序的
if (alist[low] <= target) and (target < alist[mid]): # 判断目标值是否在有序区间
high = mid - 1 # 若目标在有序区间范围,则在有序区间中查找
else:
low = mid + 1 # 若目标不在有序区间范围,则在另一循环有序区间查找
else: # 若后半部分是有序的
if (alist[mid] < target) and (target <= alist[high]): # 判断目标是否在有序区间
low = mid + 1 # 若目标在有序区间,则在有序区间中查找
else:
high = mid - 1 # 若目标不再有序区间,则在另一循环有序区间查找

cycle_binary_serch([5,6,30,1,2,3,4],3)

另附二分查找实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 二分查找
## 注意:需要针对的是有序的序列。
## 流程:截取中间的值与目标值匹配,查看值在那个区间,然后以1/2的速度缩小搜索区间。以达到加快搜索的目的。
def binary_search(alist,target):
low = 0
high = len(alist) - 1
while low <= high:
mid = (low + high)//2
guess = alist[mid]
if guess < target:
low = mid + 1
elif guess > target:
high = mid - 1
else:
return mid
binary_search([1,2,3,4,5,6,30,10],30)