一文读懂异常检测 LOF 算法(Python代码)

本篇和大家介绍一个经典的异常检测算法:局部离群因子(Local Outlier Factor),简称LOF算法

背景

Local Outlier Factor(LOF)是基于密度的经典算法(Breuning et. al. 2000), 文章发表于 SIGMOD 2000, 到目前已经有 3000+ 的引用。

在 LOF 之前的异常检测算法大多是基于统计方法的,或者是借用了一些聚类算法用于异常点的识别(比如 ,DBSCAN,OPTICS)。这些方法都有一些不完美的地方:

  • 基于统计的方法:通常需要假设数据服从特定的概率分布,这个假设往往是不成立的。
  • 聚类方法:通常只能给出 0/1 的判断(即:是不是异常点),不能量化每个数据点的异常程度。

相比较而言,基于密度的LOF算法要更简单、直观。它不需要对数据的分布做太多要求,还能量化每个数据点的异常程度(outlierness)。

下面开始正式介绍LOF算法。

LOF 算法

首先,基于密度的离群点检测方法有一个基本假设:非离群点对象周围的密度与其邻域周围的密度类似,而离群点对象周围的密度显著不同于其邻域周围的密度。

什么意思呢?看下面图片感受下。

一文读懂异常检测 LOF 算法(Python代码)

集群 C1 包含了 400 多个点,集群 C2 包含 100 个点。C1C2 都是一类集群点,区别是 C1 位置比较集中,或者说密度比较大。而像 o1o2点均为异常点,因为基于我们的假设,这两个点周围的密度显著不同于周围点的密度。

LOF 就是基于密度来判断异常点的,通过给每个数据点都分配一个依赖于邻域密度的离群因子 LOF,进而判断该数据点是否为离群点。 如果 ,则该点为离群点,如果 ,则该点为正常数据点。

那什么是LOF呢?

了解LOF前,必须先知道一下几个基本概念,因为LOF是基于这几个概念而来的。

1. k邻近距离

在距离数据点 最近的几个点中,第 个最近的点跟点 之间的距离称为点 的 K-邻近距离,记为 k-distance (p),公式如下:

点 为距离点 最近的第 个点。

一文读懂异常检测 LOF 算法(Python代码)

比如上图中,距离点 最近的第 个点是点 。

这里的距离计算可以采用欧式距离、汉明距离、马氏距离等等。比如用欧式距离的计算公式如下:

这里的重点是找到第 个最近的那个点,然后带公式计算距离。

2. k距离领域

以点 为圆心,以k邻近距离 为半径画圆,这个圆以内的范围就是k距离领域,公式如下:

还是上图所示,假设k=4,那么点 1-6 均是邻域范围内的点。

3. 可达距离

这个可达距离大家需要留意点,点 到点 的第 可达距离:

这里计算 到点 的第 可达距离,但是要以点 为中心,取一个最大值,也就是在点 与 的距离、距离点 最近的第 个点距离中取较大的一个,如图下所示。

一文读懂异常检测 LOF 算法(Python代码)

距离 远,那么两者之间的可达距离就是它们的实际距离。如果距离足够近,如点 ,实际距离将被 的 距离代替。所有 接近 的统计波动 可以显著减少,这可以通过参数 来控制, 值越高,同一邻域内的点的可达距离越相似。

4. 局部可达密度

先给出公式。

数据点 的局部可达密度就是基于 的最近邻的平均可达距离的倒数。距离越大,密度越小。

5. 局部异常因子

根据局部可达密度的定义,如果一个数据点跟其他点比较疏远的话,那么显然它的局部可达密度就小。但LOF算法衡量一个数据点的异常程度,并不是看它的绝对局部密度,而是看它跟周围邻近的数据点的相对密度。

这样做的好处是可以允许数据分布不均匀、密度不同的情况。局部异常因子即是用局部相对密度来定义的。数据点 的局部相对密度(局部异常因子)为点 邻域内点的平均局部可达密度跟数据点 的局部可达密度的比值,即:

LOF算法流程

了解了 LOF 的定义以后,整个算法也就显而易见了:

  1. 对于每个数据点,计算它与其它所有点的距离,并按从近到远排序;

  2. 对于每个数据点,找到它的 k-nearest-neighbor,计算 LOF 得分;

  3. 如果LOF值越大,说明越异常,反之如果越小,说明越趋于正常。

一文读懂异常检测 LOF 算法(Python代码)

LOF优缺点

优点

LOF 的一个优点是它同时考虑了数据集的局部和全局属性。异常值不是按绝对值确定的,而是相对于它们的邻域点密度确定的。当数据集中存在不同密度的不同集群时,LOF表现良好,比较适用于中等高维的数据集。

缺点

LOF算法中关于局部可达密度的定义其实暗含了一个假设,即:不存在大于等于 k 个重复的点。

当这样的重复点存在的时候,这些点的平均可达距离为零,局部可达密度就变为无穷大,会给计算带来一些麻烦。在实际应用时,为了避免这样的情况出现,可以把 k-distance 改为 k-distinct-distance,不考虑重复的情况。或者,还可以考虑给可达距离都加一个很小的值,避免可达距离等于零。

另外,LOF 算法需要计算数据点两两之间的距离,造成整个算法时间复杂度为 。为了提高算法效率,后续有算法尝试改进。FastLOF (Goldstein,2012)先将整个数据随机的分成多个子集,然后在每个子集里计算 LOF 值。对于那些 LOF 异常得分小于等于 1 的,从数据集里剔除,剩下的在下一轮寻找更合适的 nearest-neighbor,并更新 LOF 值。

Python 实现 LOF

有两个库可以计算LOF,分别是PyODSklearn,下面分别介绍。

使用pyod自带的方法生成200个训练样本和100个测试样本的数据集。正态样本由多元高斯分布生成,异常样本是使用均匀分布生成的。

训练和测试数据集都有 5 个特征,10% 的行被标记为异常。并且在数据中添加了一些随机噪声,让完美分离正常点和异常点变得稍微困难一些。

from pyod.utils.data import generate_data
import numpy as np
X_train, y_train, X_test, y_test = 
        generate_data(n_train=200,
                      n_test=100,
                      n_features=5,
                      contamination=0.1,
                      random_state=3) 
X_train = X_train * np.random.uniform(01, size=X_train.shape)
X_test = X_test * np.random.uniform(0,1, size=X_test.shape)

PyOD

下面将训练数据拟合了 LOF 模型并将其应用于合成测试数据。

PyOD 中,有两个关键方法:decision_functionpredict

  • decision_function:返回每一行的异常分数
  • predict:返回一个由 0 和 1 组成的数组,指示每一行被预测为正常 (0) 还是异常值 (1)
from pyod.models.lof import LOF
clf_name = 'LOF'
clf = LOF()
clf.fit(X_train)

test_scores = clf.decision_function(X_test)

roc = round(roc_auc_score(y_test, test_scores), ndigits=4)
prn = round(precision_n_scores(y_test, test_scores), ndigits=4)

print(f'{clf_name} ROC:{roc}, precision @ rank n:{prn}')
>> LOF ROC:0.9656, precision @ rank n:0.8

可以通过 LOF 模型方法查看 LOF 分数的分布。在下图中看到正常数据(蓝色)的分数聚集在 1.0 左右。离群数据点(橙色)的得分均大于 1.0,一般高于正常数据。

一文读懂异常检测 LOF 算法(Python代码)

Sklearn

scikit-learn中实现 LOF 进行异常检测时,有两种模式选择:异常检测模式 (novelty=False) 和 novelty检测模式 (novelty=True)

在异常检测模式下,只有fit_predict生成离群点预测的方法可用。可以使用negative_outlier_factor_属性检索训练数据的异常值分数,但无法为未见过的数据生成分数。模型会根据contamination参数(默认值为 0.1)自动选择异常值的阈值。

import matplotlib.pyplot as plt

detector = LOF()
scores = detector.fit(X_train).decision_function(X_test)

sns.distplot(scores[y_test==0], label="inlier scores")
sns.distplot(scores[y_test==1], label="outlier scores").set_title("Distribution of Outlier Scores from LOF Detector")
plt.legend()
plt.xlabel("Outlier score")

在novelty检测模式下,只有decision_function用于生成异常值可用。fit_predict方法不可用,但predict方法可用于生成异常值预测。

clf = LocalOutlierFactor(novelty=True)
clf = clf.fit(X_train)
test_scores = clf.decision_function(X_test)

test_scores = -1*test_scores

roc = round(roc_auc_score(y_test, test_scores), ndigits=4)
prn = round(precision_n_scores(y_test, test_scores), ndigits=4)

print(f'{clf_name} ROC:{roc}, precision @ rank n:{prn}')

该模式下模型的异常值分数被反转,异常值的分数低于正常值。

一文读懂异常检测 LOF 算法(Python代码)
实战系列的全部完整代码可见我的GitHub:https://github.com/xiaoyusmd/PythonDataScience

转自:https://mp.weixin.qq.com/s/9ANa5QKV65ZEWCaisWDjEA

python统计分析库statsmodels

做回归分析时发现需要安装一个statsmodels库,暂且记录一下,待后续使用研究

statsmodels ,包含假设检验、回归分析、时间序列分析等功能

statsmodels is a Python module that provides classes and functions for the estimation of many different statistical models, as well as for conducting statistical tests, and statistical data exploration.

官网:https://www.statsmodels.org/stable/index.html

安装:

$pip install statsmodels

https://www.statsmodels.org/stable/install.html

python安装whl安装包

python的安装现在已经很方便了,大家都知道用 pip install xxx 就可以安装一个需要的包了

可是在windows下面有一些第三方的库,直接用pip安装时经常会报一些错误,有时是VC的原因,有时是别的原因……

看库的官方网站,大多数情况下,是有提供代码用户可以自行编译后安装

可是对于像我这种小白同学来说,好像还是麻烦

这种情况下推荐大家去 https://www.lfd.uci.edu/~gohlke/pythonlibs/ 寻找一下有没有好心人预编译好的安装包,目前一般是 whl文件

Python .whl文件(或wheels)使安装速度更快、效率更高了。
轮子是Python生态系统的一个组件,它有助于使包的安装工作正常进行。它们允许更快的安装和更稳定的包分发过程。

https://cloud.tencent.com/developer/article/1683436

首先找到对应的包的版本,下载安装文件 .whl

然后本机要安装对wheel的支持(如果没有的话)

$ pip install wheel

最后安装你要安装的包

$ pip install [你下载的whl包文件]

让 Python 起飞的 24 个操作!

Python加速的技巧有很多,这篇文章总结了24个,查缺补漏,每天学会一个新的小技巧让 Python 起飞的 24 个骚操作!

一、分析代码运行时间

第1式:测算代码运行时间

平凡方法
让 Python 起飞的 24 个骚操作!
快捷方法(jupyter环境)
让 Python 起飞的 24 个骚操作!
第2式:测算代码多次运行平均时间
平凡方法
让 Python 起飞的 24 个骚操作!
快捷方法(jupyter环境)
让 Python 起飞的 24 个骚操作!
第3式:按调用函数分析代码运行时间
平凡方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
快捷方法(jupyter环境)
让 Python 起飞的 24 个骚操作!
第4式:按行分析代码运行时间
平凡方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
快捷方法(jupyter环境)
让 Python 起飞的 24 个骚操作!

二、加速你的查找

第5式:用set而非list进行查找
低速方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第6式:用dict而非两个list进行匹配查找
低速方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

三、加速你的循环

第7式:优先使用for循环而不是while循环
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第8式:在循环体中避免重复计算
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

四、加速你的函数

第9式:用循环机制代替递归函数
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第10式:用缓存机制加速递归函数
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第11式:用numba加速Python函数
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

五、使用标准库函数进行加速

第12式:使用collections.Counter加速计数
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第13式:使用collections.ChainMap加速字典合并
低速方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

六,使用numpy向量化进行加速

第14式:使用np.array代替list
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第15式:使用np.ufunc代替math.func
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第16式:使用np.where代替if
低速方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

七、加速你的Pandas

第17式:使用np.ufunc函数代替applymap
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第18式:使用预分配存储代替动态扩容
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第19式:使用csv文件读写代替excel文件读写
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第20式:使用pandas多进程工具pandarallel
低速方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

八、使用Dask进行加速

第21式:使用dask加速dataframe
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第22式:使用dask.delayed进行加速
低速方法
让 Python 起飞的 24 个骚操作!
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

九、应用多线程多进程加速

第23式:应用多线程加速IO密集型任务
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!
第24式:应用多进程加速CPU密集型任务
低速方法
让 Python 起飞的 24 个骚操作!
高速方法
让 Python 起飞的 24 个骚操作!

– EOF –

转自:https://mp.weixin.qq.com/s/7-5rQrVKhT_YW4XCayE_Cg

5 个方便好用的 Python 自动化脚本

相比大家都听过自动化生产线、自动化办公等词汇,在没有人工干预的情况下,机器可以自己完成各项任务,这大大提升了工作效率。

编程世界里有各种各样的自动化脚本,来完成不同的任务。

尤其Python非常适合编写自动化脚本,因为它语法简洁易懂,而且有丰富的第三方工具库。

这次我们使用Python来实现几个自动化场景,或许可以用到你的工作中。

1、自动化阅读网页新闻

这个脚本能够实现从网页中抓取文本,然后自动化语音朗读,当你想听新闻的时候,这是个不错的选择。

代码分为两大部分,第一通过爬虫抓取网页文本呢,第二通过阅读工具来朗读文本。

需要的第三方库:

Beautiful Soup – 经典的HTML/XML文本解析器,用来提取爬下来的网页信息

requests – 好用到逆天的HTTP工具,用来向网页发送请求获取数据

Pyttsx3 – 将文本转换为语音,并控制速率、频率和语音

import pyttsx3
import requests
from bs4 import BeautifulSoup
engine = pyttsx3.init('sapi5')
voices = engine.getProperty('voices')
newVoiceRate = 130                       ## Reduce The Speech Rate
engine.setProperty('rate',newVoiceRate)
engine.setProperty('voice', voices[1].id)
def speak(audio):
  engine.say(audio)
  engine.runAndWait()
text = str(input("Paste articlen"))
res = requests.get(text)
soup = BeautifulSoup(res.text,'html.parser')

articles = []
for i in range(len(soup.select('.p'))):
    article = soup.select('.p')[i].getText().strip()
    articles.append(article)
text = " ".join(articles)
speak(text)
# engine.save_to_file(text, 'test.mp3') ## If you want to save the speech as a audio file
engine.runAndWait()

2、自动生成素描草图

这个脚本可以把彩色图片转化为铅笔素描草图,对人像、景色都有很好的效果。

而且只需几行代码就可以一键生成,适合批量操作,非常的快捷。

需要的第三方库:

Opencv – 计算机视觉工具,可以实现多元化的图像视频处理,有Python接口

  """ Photo Sketching Using Python """
  import cv2
  img = cv2.imread("elon.jpg")

  ## Image to Gray Image
  gray_image = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

  ## Gray Image to Inverted Gray Image
  inverted_gray_image = 255-gray_image

  ## Blurring The Inverted Gray Image
  blurred_inverted_gray_image = cv2.GaussianBlur(inverted_gray_image, (19,19),0)

  ## Inverting the blurred image
  inverted_blurred_image = 255-blurred_inverted_gray_image

  ### Preparing Photo sketching
  sketck = cv2.divide(gray_image, inverted_blurred_image,scale= 256.0)

  cv2.imshow("Original Image",img)
  cv2.imshow("Pencil Sketch", sketck)
  cv2.waitKey(0)
5 个方便好用的 Python 自动化脚本,拿来即用!

3、自动发送多封邮件

这个脚本可以帮助我们批量定时发送邮件,邮件内容、附件也可以自定义调整,非常的实用。

相比较邮件客户端,Python脚本的优点在于可以智能、批量、高定制化地部署邮件服务。

需要的第三方库:

Email – 用于管理电子邮件消息

Smtlib – 向SMTP服务器发送电子邮件,它定义了一个 SMTP 客户端会话对象,该对象可将邮件发送到互联网上任何带有 SMTP 或 ESMTP 监听程序的计算机

Pandas – 用于数据分析清洗地工具

import smtplib 
from email.message import EmailMessage
import pandas as pd

def send_email(remail, rsubject, rcontent):
    email = EmailMessage()                          ## Creating a object for EmailMessage
    email['from'] = 'The Pythoneer Here'            ## Person who is sending
    email['to'] = remail                            ## Whom we are sending
    email['subject'] = rsubject                     ## Subject of email
    email.set_content(rcontent)                     ## content of email
    with smtplib.SMTP(host='smtp.gmail.com',port=587)as smtp:     
        smtp.ehlo()                                 ## server object
        smtp.starttls()                             ## used to send data between server and client
        smtp.login("deltadelta371@gmail.com","delta@371"## login id and password of gmail
        smtp.send_message(email)                    ## Sending email
        print("email send to ",remail)              ## Printing success message

if __name__ == '__main__':
    df = pd.read_excel('list.xlsx')
    length = len(df)+1

    for index, item in df.iterrows():
        email = item[0]
        subject = item[1]
        content = item[2]

        send_email(email,subject,content)

4、自动化数据探索

数据探索是数据科学项目的第一步,你需要了解数据的基本信息才能进一步分析更深的价值。

一般我们会用pandas、matplotlib等工具来探索数据,但需要自己编写大量代码,如果想提高效率,Dtale是个不错的选择。

Dtale特点是用一行代码生成自动化分析报告,它结合了Flask后端和React前端,为我们提供了一种查看和分析Pandas数据结构的简便方法。

我们可以在Jupyter上实用Dtale。

需要的第三方库:

Dtale – 自动生成分析报告

### Importing Seaborn Library For Some Datasets
import seaborn as sns

### Printing Inbuilt Datasets of Seaborn Library
print(sns.get_dataset_names())


### Loading Titanic Dataset
df=sns.load_dataset('titanic')

### Importing The Library
import dtale

#### Generating Quick Summary
dtale.show(df)
5 个方便好用的 Python 自动化脚本,拿来即用!

5、自动桌面提示

这个脚本会自动触发windows桌面通知,提示重要事项,比如说:您已工作两小时,该休息了

我们可以设定固定时间提示,比如隔10分钟、1小时等

用到的第三方库:

win10toast – 用于发送桌面通知的工具

from win10toast import ToastNotifier
import time
toaster = ToastNotifier()

header = input("What You Want Me To Remembern")
text = input("Releated Messagen")
time_min=float(input("In how many minutes?n"))

time_min = time_min * 60
print("Setting up reminder..")
time.sleep(2)
print("all set!")
time.sleep(time_min)
toaster.show_toast(f"{header}", f"{text}", duration=10, threaded=True)
while toaster.notification_active(): time.sleep(0.005)     
5 个方便好用的 Python 自动化脚本,拿来即用!

小结

Python能实现的自动化功能非常丰富,如果你可以“偷懒”的需求场景不妨试试。

参考:

https://medium.com/pythoneers/10-handy-automation-scripts-you-should-try-using-python-fc9450116938 

 

– EOF

转自:https://mp.weixin.qq.com/s/EtYBHCmgSqIL0eWDHjVTcw