马尔可夫逻辑网络 python Pracmln 试用
马尔可夫逻辑网络介绍
一阶逻辑知识库是一阶逻辑公式所构成的集合,亦可看作施加于可能世界集合上的限制集合。在传统的一阶逻辑知识库中,每个可能世界必须满足知识库中的所有公式,否则该世界不可能存在的, 这致使人们很难在实际充满不确定性的世界中进行推理。
马尔可夫逻辑网的基本思想是将一阶逻辑的限制放松,即一个可能的世界中,它违反公式越多,其世界发生概率越小,但未必为零。
用公式权值来表示公式限制强度的大小,权值越大,满足该公式世界的发生概率越高,也与不满足该公式世界的发生概率之间的差就越大。
参考文献
- https://homes.cs.washington.edu/~pedrod/papers/aaai06c.pdf 论文, 内含公式和简例
- https://image.hanspub.org/pdf/SEA20150300000_13676271.pdf Markov逻辑网研究综述
- https://homes.cs.washington.edu/~pedrod/papers/mlj05.pdf 华盛顿大学Markov逻辑网原理论文
- http://www.pracmln.org/ Pracmln 库的文档
- http://aiweb.cs.washington.edu/ai/mln/database.html 大型学生老师关系预测数据集Pracmln
- http://www.wanfangdata.com.cn/details/detail.do?_type=degree&id=Y1781489 Markov逻辑网及其在社会网络中的应用研究 胡谦谦
安装使用
- 在windows 的中, 先安装好python 2.7 或 3.5环境, 及pip install 功能
- 用管理员权限, 以管理员身份打开cmd(Commend Prompt), 输入
pip install pracmln
然而, pracmln 中用到 dnutils库, 而dnutils库中某些函数在windows中没法使用,
参见 https://github.com/danielnyga/pracmln/issues/18
因此, 有以下解决方法:
- 安装以前的pracmln版本:
即以管理员身份打开cmd(Commend Prompt), 输入:
pip install pracmln==1.2.2
- 安装kaivalyar github主的 pracmln库 https://github.com/kaivalyar/pracmln (非必须)
先下载解压文件, 再进行安装:
cd pracmln-gsoc18-cython路径
python setup.py install
再安装dnutils 库
pip install dnutils
注: kaivalyar github主的 pracmln库 用了 Cython 改写, 运算速度增加了15-25%, 亲测真实, 参见
https://kaivalyar.github.io/gsoc18-pracmln/
- (不建议但有效) 手动删去致使程序错误的代码, 并保存运行:
安装完 dnutils 库后, 在dnutils库的安装位置中, 打开 signals.py 档案, 修改成以下内容:
import signal as signal_
import threading
from collections import defaultdict
__usrreg = defaultdict(list)
__sysinit = defaultdict(list)
__systerm = defaultdict(list)
SIGINT = signal_.SIGINT
SIGTERM = signal_.SIGTERM
#SIGKILL = signal_.SIGKILL
SIGABRT = signal_.SIGABRT
#SIGALRM = signal_.SIGALRM
#SIGBUS = signal_.SIGBUS
#SIGCHLD = signal_.SIGCHLD
#SIGCLD = signal_.SIGCLD
#SIGCONT = signal_.SIGCONT
SIGFPE = signal_.SIGFPE
#SIGHUP = signal_.SIGHUP
SIGILL = signal_.SIGILL
SIGINT = signal_.SIGINT
#SIGIO = signal_.SIGIO
#SIGIOT = signal_.SIGIO
#SIGKILL = signal_.SIGKILL
#SIGPIPE = signal_.SIGPIPE
#SIGPOLL = signal_.SIGPOLL
#SIGPROF = signal_.SIGPROF
# ============================================================================
#SIGPWR = signal_.SIGPWR
#SIGQUIT = signal_.SIGQUIT
#SIGRTMAX = signal_.SIGRTMAX
#SIGRTMIN = signal_.SIGRTMIN
SIGSEGV = signal_.SIGSEGV
#SIGSTOP = signal_.SIGSTOP
#SIGSYS = signal_.SIGSYS
SIGTERM = signal_.SIGTERM
#SIGTRAP = signal_.SIGTRAP
#SIGTSTP = signal_.SIGTSTP
#SIGTTIN = signal_.SIGTTIN
#SIGTTOU = signal_.SIGTTOU
#SIGURG = signal_.SIGURG
#SIGUSR1 = signal_.SIGUSR1
#SIGUSR2 = signal_.SIGUSR2
#SIGVTALRM = signal_.SIGVTALRM
#SIGWINCH = signal_.SIGWINCH
#SIGXCPU = signal_.SIGXCPU
#SIGXFSZ = signal_.SIGXFSZ
# =============================================================================
_lock = threading.Lock()
def _run_handlers(signal, args):
'''Executes all handlers that are registered for the given
siganl in the order of registration.'''
# run system handlers for preparing the signal handling
for handler in __sysinit[signal]:
handler(*args)
# run user defined signal handlers
for handler in __usrreg[signal]:
handler(*args)
# run system handlers for cleaning up the signal handling
for handler in __systerm[signal]:
handler(*args)
def add_handler(signal, handler):
'''
Add a handler to be executed on the signal ``signal``
:param signal: the signal to react to.
:param handler: a callable that will be called on the signal.
:return:
'''
_add_handler(signal, handler, __usrreg)
def _add_handler(signal, handler, registry):
'''
Add a handler to be executed on the signal ``signal``
:param signal: the signal to react to.
:param handler: a callable that will be called on the signal.
:return:
'''
with _lock:
handlers_ = registry[signal]
if not handlers_:
signal_.signal(signal, lambda *args: _run_handlers(signal, args))
if handler not in handlers_:
handlers_.insert(0, handler)
def rm_handler(signal, handler):
'''
Remove a handler if it is registered to the given signal.
:param signal: the signal that the handler is registered for
:param handler: the handler function.
:return:
'''
_rm_handler(signal, handler, __usrreg)
def _rm_handler(signal, handler, registry):
'''
Remove a handler if it is registered to the given signal.
:param signal: the signal that the handler is registered for
:param handler: the handler function.
:return:
'''
with _lock:
try:
registry[signal].remove(handler)
except ValueError:
pass
def keyint(*_):
raise KeyboardInterrupt()
def enable_ctrlc():
'''
Allows to interrupt the main thread by pressing Ctrl-C.
:return:
'''
_add_handler(SIGINT, keyint, __systerm)
def disable_ctrlc():
'''
Disables interruption of the main thread by the Ctrl-C key combination.
:return:
'''
_rm_handler(SIGINT, keyint, __systerm)
示例问题描述: 社会链接预测应用
链接预测是以它所链接的社会主体(例如人, 公司, 组织), 和该社会主体已观测到的社会链接关系为条件, 来预测它与其他社会主体的某社会链接或社会关系是否存在。如判断两个社会主体是否存在朋友关系,两者是否会共同参与同一项活动等等。进而在有限的社会讯息中, 估算社会规模及其潜在隐藏的互动关系
利用 Pracmln 库的帮助, 我们首先建立以一阶逻辑所描绘的社会互动关系现象和假设:
data.txt:
data ###
Cancer(Alex)
!Cancer(Douglas)
!Cancer(Nixon)
Friends(Alex,Nixon)
Smokes(Alex)
在data.txt中,
Cancer(Alex) 指 Alex是Cancer的子集, 即Alex患上癌症;
!Cancer(Douglas) 指 Douglas不是Cancer的子集, 即Douglas没有患上癌症;
Friends(Alex,Nixon) 指 Alex 和 Nixon是Friends的二元子集, 即 Alex 和 Nixon存在朋友关系;
Smokes(Alex) 指 Alex有抽烟习惯
predicate.txt:
Cancer(person)
Friends(person,person)
Smokes(person)
谓词命名, 及谓词内变量命名
formula.txt:
Smokes(x) => Cancer(x)
Friends(x,y) => (Smokes(x) <=> Smokes(y))
在formula.txt中, 我们把对社会互动关系的假设和已有或未知真实程度的现象, 以一阶逻辑形式表示:
Smokes(x) => Cancer(x) 指 如果 x 有抽烟习惯, 则 x 患上癌症
Friends(x,y) => (Smokes(x) <=> Smokes(y)) 指 如果 x 和 y 是朋友关系, 则 x 有抽烟习惯 当且仅当 y 有抽烟习惯
在还没有接受数据 data.txt 的训练前, 我们将假定以上公式权重為零, 在训练后补上相应权重。一般而言, 如果data.txt 中的证据越是和公式一致, 其公式权重越高。
推理求解的命题:
Smokes(NIXON)
即在已知事实和相关社会假设下求解, Nixon 有抽烟习惯的概率
代码演示
@author: Alex Yu
"""
import os
import sys
from pracmln.utils.project import PRACMLNConfig
from pracmln.utils import config, locs
from pracmln.utils.config import global_config_filename
import os
from pracmln.mlnlearn import MLNLearn
from pracmln import MLN, Database, query
class social_modelling():
def read_data(paths, predicate): # 读txt数据用
content = []
base_path = os.getcwd()
file = open(base_path + '\\' + paths,'r',encoding = 'utf8')
pre_content = file.read()
pre_content = pre_content.split('###')
pre_content = [x for x in pre_content if x !='']
for i in pre_content:
element = i.split('\n')
element = [x.replace(':','_') for x in element if x !='']
for j in element[1::]:
splited = j.split('(')
content.append((element[0],splited[0]+'('+splited[1].upper()))
# pracmln 要求 证据数据库db中的格式為 Predicate(CONTANT_1), 即谓语首字及谓语内
# 变量contant首字為大写, 还有不可以有空格. 这里单纯方便而把变量大写
# 另外暂不支持中文输入.
return content
def read_formula(paths,predicate):
predicate_list = [x.split('('