手写器

handiter包对手写体执行书写分析有疑问的文件被质疑的文件是由闭集潜在作家。例如,在一间科学教室里发现了一个手写的炸弹威胁,警方能够确定这张纸条可能是由第四期科学课的一名学生写的。手写程序包构建统计模型来估计编写器配置文件从封闭集中每个作家的已知笔迹样本中提取。还根据被质疑的文件估计了作者的简介。统计模型将受质疑文档中的作者简介与潜在作者封闭集中的每个作者简介进行比较,并估计每个封闭集作者撰写受质疑文档的后验概率。

安装

您可以使用以下工具从CRAN安装手写器:

安装.包(“手写体”)

您可以从以下位置安装手写器的开发版本github具有:

#install.packages(“devtools”)
开发工具::安装_工具(“CSAFE-ISU/手写”)

处理手写示例

文件“phrase_example.png”是CSAFE手写数据库中手写体的扫描png。这个PNG图像包含在名为“extdata”的文件夹中的手写程序包中。使用helper函数手写体示例(_example)查找“phraseexample.png”保存在计算机上的路径。

使用处理文档()

  1. 读取PNG文件
  2. 将文字转换为黑白
  3. 将其细化为一个像素宽的骨架
  4. 放置节点以将书写拆分为组件形状,称为
图书馆(手写)
短语<- system.file(系统文件)(“外部数据”“短语示例.png”包装= “手写体”)
文件<- 处理文档(短语)
#>readPNGBinary中的路径:/private/var/folders/1z/jk9bqhdd06j1fxx0_xm2jj980000gn/T/RtmpEaTBth/temp_libpath12a739c097f/handiter/extdata/phrase_example.png
#>正在开始处理。。。
#>正在获取节点。。。并合并它们。。。
#>正在查找直接路径。。。和循环。。。
#>正在查找图形断点。。。丢弃坏的。。。
#>正在隔离图形路径。。。
#>整理信件。。。
#>正在创建信件列表。。。
#>正在添加字符功能。。。
#>文档处理完成。

我们可以查看图像:

打印图像(文档)

我们可以查看细化后的图像:

plotImage变薄(文档)

我们还可以查看节点:

绘图节点(文档)

执行写入分析

本节介绍如何使用手写器对有疑问的文档执行手写分析。特别是,手写人解决了这样一种情况,即调查人员有一份被质疑的手写文件,一组利益相关者已被确定,而被质疑的文件必须由利益相关者之一书写。例如,想象一下,一张手写的炸弹威胁信被放在办公楼的主办公桌上,警察发现这张纸条一定是当天工作的100名员工中的一人写的。有关该方法的更多详细信息,请参阅[克劳福德2022]。

步骤1:创建主目录和子目录

创建名为的新文件夹主目录(_D)保存要分析的手写文档。当我们创建新的集群模板并适合统计模型时,这些文件也将存储在这个文件夹中。在中创建子文件夹主目录(_D)打电话数据。在数据文件夹,创建子文件夹模型文档有问题的文档、和模板_文档。文件夹结构如下所示:

├──主目录(_D)
│   ├──数据  
│   │   ├──模型文档
│   │   ├──有问题的文档
│   │   ├──模板_文档

步骤2:创建群集模板

将要用于训练新集群模板的手写文档保存为中的PNG图像main_dir>data>template_docs。模板培训文档需要来自非感兴趣的作者。使用包含写入程序ID的一致格式命名所有PNG图像。例如,PNG图像可以命名为“writer0001.PNG”、“writeer0002.PNG”和“writer 0003.PNG”等。

接下来,从中的文档创建一个新的集群模板main_dir>data>template_docs使用函数生成群集模板。此功能

  1. 处理中的模板培训文档模板_文档,将手写体分解为组件形状,称为。处理后的图形保存在中的RDS文件中主目录数据模板图.
  2. 删除边数超过指定的最大值的图形最大边数(_E)。
  3. 随机选择K(K)使用种子启动集群中心中心_种子再现性。
  4. 使用运行K-means算法K(K)启动集群中心和所选图形。该算法将所选图形迭代分组为K(K)集群。最后一组K(K)集群是集群模板。
  5. 存储每个培训文档的编写器ID。写入者索引是PNG图像文件名中写入程序ID的开始和停止字符的矢量。例如,如果PNG图像名为“writer0001.PNG”、“writeer0002.PNG”和“writer 0003.PNG”,依此类推,writer_indices=c(7,10)
  6. 并行执行某些进程。使用设置并行处理的内核数num_dist_cores数.
模板<- 生成群集模板(
  模板目录= “路径/到/main_dir”
  模板图像目录= “路径/to/main_dir/data/template_docs”
  写入者索引= c(c)(710),
  最大边数(_E)= 25
  中心_种子= 100
  graphs_seed= 101
  K(K)= 40
  num_dist_cores数= 4
  最大值(_I)= 25)

类型?生成群集模板有关函数参数的更多信息,请参见RStudio控制台。

对于本教程的其余部分,我们使用一个小示例集群模板,示例集群模板包含在手写器中。

模板<- 示例集群模板

集群模板和层次模型背后的思想是,我们可以将手写文档分解为组件图,将每个图分配给最近的簇,即在簇模板中形状最接近的簇,并计算每个簇中的图形数。我们通过分配给每个集群的编剧图的数量来描述编剧。我们称之为作家的簇填充计数它用作作家简介。

我们可以为模板训练集中的每个编写器绘制集群填充计数。首先,我们对模板数据进行格式化,以获得绘制函数所需的正确格式的簇填充计数。

模板_数据<- 格式_模板_数据(模板=模板)
plot_cluster填充计数(模板数据,刻面= 真的)

步骤3:拟合层次模型

我们将使用每个感兴趣的人的手写样本,使用聚类模板计算每个样本的聚类填充计数,并拟合层次模型来估计每个感兴趣人的真实聚类填充计数。

从感兴趣的人那里保存您已知的笔迹样本main_dir\>data\>model_docs作为PNG图像。该模型需要每个感兴趣的人提供三个笔迹样本。每个样本的长度应至少为一段。使用一致的格式命名PNG图像,以便所有文件名都具有相同的长度,并且写入程序ID位于相同的位置。例如,“writer0001_doc1.png”、“writer 0001_doc2.png”,“wroter 0001_doc3.png”和“writers 0002_doc1.png”等等。

我们用函数拟合一个层次模型fit_model(适合模型)。此函数执行以下操作:

  1. 处理中的模型培训文档模型图像目录,将手写体分解为组件图。处理后的图形保存在中的RDS文件中主目录\>数据\>模型图.
  2. 通过将每个图分配给集群模板中最近的集群并计算分配给每个集群的图的数量,计算每个文档的集群填充计数。集群分配保存在main_dir>data>model_clusters.rds中
  3. 使用RJAGS包将层次模型拟合到簇填充计数,并使用尾码包绘制模型参数的后验样本。

在本例中,我们对模型使用了4000次MCMC迭代。输入写入者索引文档_索引是模型培训文档文件名中的开始和停止字符,其中包含编写器ID和文档名称。

模型<- fit_model(适合模型)(模板目录= “路径/to/main_dir”
                   模型图像目录= “路径/to/main_dir/data/model_docs”
                   计数(_I)= 4000
                   num_chains(链数)= 1
                   num_cores数= 2
                   写入者索引= c(c)(710),
                   文档_索引= c(c)(1114))

在本教程中,我们将使用小示例模型,示例模型1链,包含在手写体中。这个模型是从三个文档中训练出来的,每个文档都来自来自CSAFE手写数据库.

模型<- 示例模型1链

我们可以为每个感兴趣的人绘制集群填充计数。(注意:我们必须格式化模板数据才能使用绘图功能,但模型数据的格式已经正确。)

plot_cluster填充计数(格式化数据=模型,刻面= 真的)

每个图形顶部的条形图显示了书写器ID。每个图形都有一条线,表示来自给定书写器的每个已知手写样本。

层次模型变量和老化

如果您对层次模型使用的变量感兴趣,请继续阅读本节。否则,请跳到下一节学习如何分析有疑问的文档。

我们可以列出模型中的变量:

姓名(作为数据框架(尾声::as.mcmc公司(型号$适合的模型[[1]])))
#>[1]“eta[1]”“eta[2]”“eta[3]”“eta-[4]”“esta[5]”“eta/6]”
#>[7]“eta[7]”“eta[0]”“esta[9]”“eta[10]”“gamma[1]”“gama[2]”
#>[13]“伽马[3]”“伽马[4]”“γ[5]”“伽玛[6]”“γ[7]”“gamma[8]”
#>[19]“伽马[9]”“伽马[10]”“mu[1,1]”“mu[2,1]”、“mu[3,1]””“mu[4,1]”
#>[25]“mu[5,1]”“mu[1,2]”“mu[2,2]“mu[3,2]
#>[31]“mu[1,3]”“mu[2,3],”mu[3,3]“”mu[4,3]
#>[37]“mu[2,4]”“mu[3,4]“mu[4,4]
#>[43]“mu[3,5]”“mu[4,5],”mu[5,5]“”mu[1,6]“”mu[2,6]”“”mu[3.6]“”
#>[49]“mu[4,6]”“mu[5,6]“mu[1,7]”
#>[55]“mu[5,7]”“mu[1,8]”“mu[2,8]“mu[3]”“mu[4,8]
#>[61]“mu[1,9]”“mu[2,9],”“mu[3,9]“”mu[4,9]
#>[67]“mu[2.10]”“mu[3,10]”“mu[4,10]“mu[5,10”“pi[1,1]”“pi[2,1]”
#>[73]“pi[3,1]”“pi[4,1]”、pi[5,1]”
#>[79]“pi[4,2]”“pi[5,2]“pi[1,3]”“pi[2,3]“pi[3]”“pi[4,3]
#>[85]“pi[5,3]”“pi[1,4]”“pi[2,4]“pi[3,4]
#>[91]“pi[1,5]”“pi[2,5]“pi[3,5]
#>[97]“pi[2.6]”“pi[3,6]”“π[4,6]“pi[5,6],”“pi[1,7]”“pi[2,7]“”
#>[103]“pi[3,7]”“pi[4,7],”pi[5,7]“”pi[1,8]“”pi[2,8]”“”pi[3.8]“”
#>[109]“π[4,8]”“pi[5,8]“pi[1,9]”“π[2,9]“pi[3,9]
#>[115]“pi[5,9]”“pi[1,10]”“pi[2,10]“pi[3]”“pi[4,10]”“pi[5,10]。”
#>[121]“τ[1,1]”“τ[2,1]”
#>[127]“套[2,2]”“套[3,2]“套[4,2],”“套[2.2]”“套[1,3]”“”套[2,3]“”
#>[133]“陶[3,3]”“陶[4,3]“”陶[5,3]
#>[139]“tau[4,4]”“tau[5,4]”“tau[1,5]”“tau[2,5]”“tau[3,5]”“tau[4,5]”
#>[145]“陶氏[5,5]”“陶氏[1,6]”“陶氏[2,6],”陶氏[3,6]“”陶氏[2,4]“”陶形[5,6]
#>[151]“τ[1,7]”“τ[2,7],”τ[3,7]
#>[157]“τ[2,8]”“τ[3,8]“”τ[4,8]
#>[163]“陶[3,9]”“陶[4,9]“陶[5,9],”“陶[1,10]”“陶[2,10],”陶[3,10]“”
#>[169]“套[4,10]”“套[5,10]“

使用关于变量功能。

关于变量(可变的= “mu[1,1]”模型=型号)
#>[1]“Mu是wrapped-Cauchy分布的位置参数,用于writer ID 9和cluster 1”

查看变量的跟踪图。

绘图跑道(变量= “mu[1,1]”模型=型号)

如果需要,我们可以删除开始的MCMC迭代以进行老化

模型<- 滴烧(_B)(型号,燃烧_in= 25)

如果要将更新的模型保存为此项目的当前模型,请替换模型.rds在中数据文件夹

保存RDS(型号,文件='数据/模型.rds')

分析有疑问的文档

将有疑问的文档保存在主目录>数据>问题文档作为PNG图像。为有疑问的文档分配一个新的作者ID,并一致地命名文档。例如“unknown1000_doc1.png”、“unknows1001_doc1.png”等。

我们使用函数估计每个被质疑文档的后验写作者概率分析有问题的文档。此功能执行以下操作:

  1. 流程问题文档:处理中的质疑文档有问题的图像目录,将手写体分解为组件图。处理后的图形保存在RDS文件中main_dir\>data\>questized_graphs(主目录数据图).
  2. 评估问题文档的作者简介:通过将每个图分配给集群模板中最近的集群,并计算分配给每个集群的图的数量,计算每个受质疑文档的集群填充计数。集群分配保存在main_dir\>data\>questioned_clusters.rds.
  3. 估算作家的后验概率:使用步骤3中的拟合模型估计每个受质疑文档和每个感兴趣的人的写作后验概率。结果保存在main_dir\>数据\>分析.rds.
分析<- 分析有问题的文档(
  模板目录= “路径/to/main_dir”
  有问题的图像目录= “路径/to/main_dir/questioned_docs”
  模型=模型,
  写入者索引= c(c)(811),
  文档_索引= c(c)(1316),
  num_cores数= 2)

让我们假设来自5个“感兴趣的人”中每个人的笔迹样本是一份有疑问的文件。这些文件也来自CSAFE手写数据库并且已经用示例模型1链结果包含在手写体中示例分析1链.

分析<- 示例分析1链

查看每个有疑问的文档的群集填充计数。直观地说,该模型评估了哪些作者的集群填充计数看起来最像每个受质疑文档中观察到的集群填充数。

plot_cluster填充计数(分析,刻面= 真的)

查看写作的后验概率。

分析$后验概率
#>已知_写入器w0009_s03_pWOZ_r01.png w0030_s03_pWAZ_r01-png
#>1名已知作者_9 1 0
#>2 known_writer_30 0 1
#>3已知作者_203 0
#>4已知写入者_238 0
#>5已知写入者_400 0 0
#>w0203_s03_pWOZ_r01.png w0238_s03_pWOZ_r01.png w0400_s03_pWOZ_r01.png
#> 1                    0.0                      0                      0
#> 2                    0.0                      0                      0
#> 3                    0.3                      0                      0
#> 4                    0.7                      1                      0
#>5 0.0 0 1

仅供研究

实际上,我们不知道谁写了一份有疑问的文件,但在研究中,我们经常使用我们知道基本事实的数据进行测试,以评估模型。因为在这个例子中,我们知道每个被质疑文档的真实作者,我们可以测量模型的准确性。我们将准确性定义为分配给真实作者的平均后验概率。我们模型的准确性是

calculate_准确性(分析)
#> [1] 0.86