新知一下
海量新知
6 6 7 6 2 7 4

【干货+福利】情侣、基友、渣男和狗-基于SynchroTrap+LPA算法的团伙账户挖掘

小詹学Python | 左手Python,右手AI。 2022/11/18 14:24

新知达人, 【干货+福利】情侣、基友、渣男和狗-基于SynchroTrap+LPA算法的团伙账户挖掘

本文目的: 把经常一起行动的人找出来,并划分成一个Group,仅利用时间关系,无需其他介质

上一期的文章,没有解决相隔时间近但是不在同一个5min切片内的的问题,为了解决这个问题,我研究了一些关于时序的关联规则算法,包括GSP、Prefixspan、FreeSpan等,在我们这个场景里面,不能很好的解决。我们用SynchroTrap+LPA这两个,就能非常完美的解决,SynchroTrap算法用来构图,LPA用来分群。有人说,没有介质会不会不准,其实大家可以想象下,在食堂吃饭的时候,有没有连续几天都是同一个你不认识的人排在你的前面?

SynchroTrap+LPA比关联规则算发现较大规模的群体,本文中,我们 仅仅利用校园卡消费明细数据和这两个算法,比如班级、室友等,也能发现情侣、基友、闺蜜、渣男、渣女等非常有意思的模式我们一步步来看看怎么做的。

一、同步关系构建

首先,我们需要把时间序列的数据,处理成关系数据,具体的逻辑参考文章 基于同步行为的反欺诈算法SynchroTrap实现细节 ,里面写的非常详细,下面我们用这个校园卡的消费数据来实现这个过程。 没学明白的可以巩固下。

1、读取数据

# 数据读取

import pandas as pd

import os

pd.set_option('display.max_columns', None)

os.chdir('/Users/wuzhengxiang/Documents/DataSets/students')

data1 = pd.read_csv("data1.csv", encoding="gbk")

data2 = pd.read_csv("data2.csv", encoding="gbk")

data3 = pd.read_csv("data3.csv", encoding="gbk")

data1.columns = ['序号', '校园卡号', '性别', '专业名称', '门禁卡号']

data2.columns = ['流水号', '校园卡号', '校园卡编号', '消费时间', '消费金额', '存储金额', '余额', '消费次数', '消费类型', '消费项目编码', '消费项目序列号', '消费操作编码', '操作编码', '消费地点']

data3.columns = ['序号', '门禁卡号', '进出时间', '进出地点', '是否通过', '描述']

print(data1.head(3))

print(data2.head(3))

print(data3.head(3))

# 数据匹配,匹配上性别数据,分析更直观

data2 = data2.merge(data1[['校园卡号','性别']],on='校园卡号')

data2['校园卡号'] = data2['校园卡号'].apply(lambda x: str(x))+'-'+data2['性别']

我们主要使用的是data2的数据,data1的数据仅仅使用了性别这个字段,data3这个字段在这里没有使用。数据格式长下面这个样子。

新知达人, 【干货+福利】情侣、基友、渣男和狗-基于SynchroTrap+LPA算法的团伙账户挖掘

2、时间切片处理

需要把时间切片,这里使用的是5分钟一个片段,一般来说,两个消费的关系,大概就是排队刷卡的时间,5分之之内,比较合理。

import datetime

'''

函数功能

时间格式调整

'2019/4/20 20:17'=>'2019-04-20 20:17:00'

'''

def st_pt(x):

return str(datetime.datetime.strptime(x, "%Y/%m/%d %H:%M"))

'''

函数功能

时间切片

5分钟一个切片,且每个时间会切成两个片段

Time2Str('2021-11-16 15:51:39' )

'2021-11-16 15:51:39' => '2021111615(10);2021111615(11)'

'''

def Time2Str(tsm):

t0 = datetime.datetime.fromisoformat(tsm)

t1 = t0+datetime.timedelta(days=0, hours=5/60)

str1 = t0.strftime("%Y%m%d%H")+'(' +str(round(int(t0.minute/5))).rjust(2,'0')+')'

str2 = t1.strftime("%Y%m%d%H")+'(' +str(round(int(t1.minute/5))).rjust(2,'0')+')'

return str1+';'+str2

函数好了后,对数据进行处理

# 开始数据处理

df = data2

df['消费时间'] = df['消费时间'].apply(st_pt)

df['tsm']     = df['消费时间'].apply(Time2Str)

# 数据分裂,一行变两行

df = df.set_index(["校园卡号", "消费时间",'消费地点'])["tsm"].str.split(";", expand=True)

.stack().reset_index(drop=True, level=-1).reset_index().rename(columns={0: "tsm"})

print(df)

# 可以看到,处理后的格式如下

校园卡号 消费时间 消费地点 tsm

0 180641-女 2019-04-01 10:00:00 红太阳超市 2019040110(00)

1 180641-女 2019-04-01 10:00:00 红太阳超市 2019040110(01)

2 181021-女 2019-04-01 10:00:00 第一食堂 2019040110(00)

3 181021-女 2019-04-01 10:00:00 第一食堂 2019040110(01)

4       181036-女  2019-04-01 10:00:00    第一食堂  2019040110(00)

3、匹配构图

切片处理好后,就开始匹配构图了,我们的切片匹配后,还需要加个时间限制,上一步操作仅仅把时间限制在10分钟内,因此为了得到5分钟,还需要作差筛选

# 数据匹配,加入时间约束和地点约束

df_0 = pd.merge(df,df,on =['tsm','消费地点'],how='inner')

df_0.shape

# 排除 自己和自己匹配的数据

df_1 = df_0[df_0['校园卡号_x']!=df_0['校园卡号_y']]

# 时间作差,大于5分钟的排除

df_1['diff'] = (pd.to_datetime(df_1['消费时间_x'])-pd.to_datetime(df_1['消费时间_y'])).dt.seconds/60

df_1 = df_1[df_1['diff']<=5]

# 提取小时 按共同出现的小时计数

df_1['date'] = df_1['tsm'].apply(lambda x :x[0:10])

#统计两两关联的次数,这里比较简单,不按天,也不计算相似度了

df_2 = df_1.groupby(['校园卡号_x','校园卡号_y']).agg({'date': pd.Series.nunique}).reset_index()

# 降序排列

df_2 = df_2.sort_values(by='date',ascending=False)

校园卡号_x 校园卡号_y date

1031801 181293-女 181268-女 68

1008844 181268-女 181293-女 64

343421 180399-女 183665-女 60

309673 180363-女 181876-女 58

1967448 182392-女 182377-女 58

... ... ...

1509502 181840-男 181732-女 1

1509501 181840-男 181731-女 1

1509499 181840-男 181729-女 1

1509497 181840-男 181727-女 1

1645283 181999-男 183585-女 1

df_2.shape

(3290566, 3)

4、阈值确定

图数据好了,但是我们看有300多万,很多一个月就一次,这个肯定就是巧合数据,每次你去食堂排队,排队前后的,和你的时间间隔就比较少,但是偶尔的关联,并不是我们想要的,所以我们要进一步筛选这里我确定20次,数据瞬间从300万到1924了。

# 给关系加阈值,大于20次的算是比较强的关联了

df_3 = df_2[df_2['date']>=20]

df_3.shape

(1924, 3)

df_3

校园卡号_x 校园卡号_y date

1031801 181293-女 181268-女 68

1008844 181268-女 181293-女 64

343421 180399-女 183665-女 60

309673 180363-女 181876-女 58

1967448 182392-女 182377-女 58

... ... ...

156386 180173-女 180109-女 20

271647 180320-女 183546-女 20

2884196 183692-女 180377-女 20

66844 180085-女 180394-女 20

1801477  182194-女  182212-女    20

二、LPA分群

这里我们直接调用networkx库里的asyn_lpa_communities算法,对上面的关系数据进行分群,每个学生都会分布到一个独立的群体里面。为了得到不同程度的关系,我们可以调节关联次数这个阈值。大家可以多测试几个看看。

1、算法分群

import matplotlib.pyplot as plt

import networkx as nx

from networkx.algorithms.community import asyn_lpa_communities as lpa

# 数据格式转换

tuples = [tuple(x) for x in df_3[['校园卡号_x','校园卡号_y']].values]

G = nx.DiGraph()

G.add_edges_from(tuples)

# LPA本身不稳定,因此,社群存在小范围波动

com = list(lpa(G))

print('社区数量',len(com))

449

# 打印分群数据 仅展示部分数据

for i in com:

print(i)

{'181559-男', '181568-男', '181556-男', '181564-男'}

{'181013-女', '181042-女', '180624-男'}

{'180851-女', '181461-男', '180780-女', '180856-女'}

{'180105-女', '180164-女', '180198-女', '180118-女'}

{'183401-女', '183385-女'}

{'181364-男', '181528-男'}

{'182031-男', '182029-男', '182016-男', '182033-男'}

{'182039-男', '182042-男', '182041-男', '182040-男'}

{'183706-女', '183691-女'}

{'180449-女', '180491-女', '180489-女', '180455-女', '180456-女', '180476-女'}

{'181013-女', '181042-女', '180624-男'}

{'182283-女', '182244-女'}

{'181623-男''183847-女''181597-男'}

2、明细数据获取

为了进行比较明细的分析,我们可以挑一些我们比较感兴趣的关系对,进行明细数据分析

# 渣女组合

result = data2[(data2['校园卡号']=='181623-男') | (data2['校园卡号']=='183847-女') |

(data2['校园卡号']=='181597-男')]

# 情侣组合

result = data2[(data2['校园卡号']=='181774-男') | (data2['校园卡号']=='183898-女')]

result = result.sort_values(by='消费时间')

# 用户 -时间-地点关系数据

result = df_1[((df_1['校园卡号_x']=='181774-男') & (df_1['校园卡号_y']=='183898-女')) |

((df_1['校园卡号_y']=='181774-男') & (df_1['校园卡号_x']=='183898-女'))]

# 数据整理保存备用

result.to_csv('resualt.csv',index=False,header=True)

新知达人, 【干货+福利】情侣、基友、渣男和狗-基于SynchroTrap+LPA算法的团伙账户挖掘

3、数据可视化

其实数据不够直观,我们可以进一步去做可视化

我们可以构建一个 学生-时间地点-学生 的 图,如下面,表示【 181774-男】 和  【183898-女】 在20190415的11点出现过,如果你看明细数据,他们出现的时间 2019/4/15 11:39

新知达人, 【干货+福利】情侣、基友、渣男和狗-基于SynchroTrap+LPA算法的团伙账户挖掘

在看看下面,是两个人所有的在5分钟之内的链接,非常紧密和频繁,一看就是很恩爱的情侣。

新知达人, 【干货+福利】情侣、基友、渣男和狗-基于SynchroTrap+LPA算法的团伙账户挖掘

我们再看一个渣男渣女组合,大家可以自己去看看呢,上面的绘图,可以使用https://app.flourish.studio这个网站。

用matplotlib.pyplot绘图试试,简直没法看

# 下面是画图 

pos = nx.spring_layout(G) # 节点的布局为spring型

NodeId = list(G.nodes())

node_size = [G.degree(i)**1.2*90 for i in NodeId] # 节点大小

plt.figure(figsize = (8,6)) # 图片大小

nx.draw(G,pos, with_labels=True,

node_size =node_size,

node_color='w',

node_shape = '.'

)

'''

node_size表示节点大小

node_color表示节点颜色

with_labels=True表示节点是否带标签

'''

color_list = ['pink','orange','r','g','b','y','m','gray','black','c','brown']

for i in range(len(com)):

nx.draw_networkx_nodes(G, pos, nodelist = com[i],

node_color=color_list[i+2],

label=True)

plt.show()

新知达人, 【干货+福利】情侣、基友、渣男和狗-基于SynchroTrap+LPA算法的团伙账户挖掘

三、数据结论

1、反欺 诈应用

通过上面的案例,我们可以看到SynchroTrap+LPA算法,对于无介质的欺诈用户进行关联和分群,是非常完美的一个组合,大家可以在自己的数据里面试试,可能有意外惊喜。

2、一个题外话

由此,我们可以联想到滴滴数据泄露为什么受到如此重视?滴滴拥有大量的行程数据,特别是再加上时序,结合前沿的大数据的分析方法,可以发现让人震惊的结论。

一个人长期往返于军工学校的实验室和某个建筑物,且建筑在地图上没有标名字,那很可能是个重要的军事基地

一个人经常往返于某发射基地和某建筑物,那某个建筑,可能是导弹生产工厂,再进行重点监控

将车流、人流、现状用地信息叠加,地图空白处,可能是国家重要的军火粮食仓库

分析保密单位工作性质,以及员工或访客上下班的滴滴数据,那么就可以推算其工作性质

某个人物,和另一个人经常同行,那同行人重点监控,可能发现大秘密

A-B,B-C,C-D存在大规模的连接,推断出他们是一个单位的,关键时刻进行一锅端


诸如此类,大家可以举出无穷的例子,利用已知推导出疑似的未知,这会暴露很多涉及国家安全的基础设施,还会暴露很多涉及国家安全的人物,非常可怕,并且出行数据,都是真实轨迹,推断具有极大的准确性。



更多“算法”相关内容

更多“算法”相关内容

新知精选

更多新知精选