R最近我读了一篇介绍neo4j-runway 的文章。根据他们的Github 页面,“Neo4j Runway 是一个 Python 库,它简化了将关系数据迁移到图形中的过程。它提供了抽象与 OpenAI 通信的工具,以对数据运行发现并生成数据模型,以及生成提取代码并将数据加载到 Neo4j 实例中的工具”。翻译一下,通过上传 CSV,LLM 将找到节点和关系并自动生成知识图谱。
医疗保健领域的知识图谱是组织和分析复杂医疗数据的强大工具。这些图谱以一种更容易理解不同实体(例如疾病、治疗、患者和医疗保健提供者)之间关系的方式构建信息。
医疗保健领域的 KG 提供了一些有用的应用:
多种数据源的整合: 知识图谱可以整合来自各种来源的数据,例如电子健康记录 (EHR)、医学研究论文、临床试验结果、基因组数据和患者历史记录。
改善临床决策支持: 通过将症状、诊断、治疗和结果联系起来,知识图谱可以增强临床决策支持系统 (CDSS),因为它们考虑了大量相互关联的医学知识,有可能提高诊断准确性和治疗效果。在本文中,我将探讨这个话题。
个性化医疗: 知识图谱通过将患者特定数据与更广泛的医学知识关联起来,可以制定个性化治疗计划。这包括了解遗传信息、疾病机制和治疗反应之间的关系,从而制定更有针对性的医疗干预措施。
药物发现与开发: 在药物研究中,知识图谱可以通过识别潜在的药物靶点和了解疾病所涉及的生物学途径来加速药物发现。
公共卫生和流行病学: 知识图谱在公共卫生领域非常有用,可以追踪疾病爆发、了解流行病学趋势和规划干预措施,因为它们可以整合来自各种公共卫生数据库、社交媒体和其他来源的数据,提供对公共卫生威胁的实时洞察。
否eo4j Runway是Alex Gilmore创建的开源库。您可以在此处找到该存储库,并在此处找到描述该库的博客。
目前,该库仅支持 OpenAI LLM 解析 CSV,并提供以下功能:
数据发现: 利用 OpenAI LLM 从您的数据中提取有意义的见解。
图形数据建模: 使用 OpenAI 和 Instructor Python 库来开发精确的图形数据模型。
代码生成: 根据您喜欢的数据加载方法创建定制的提取代码。
数据提取: 利用 Runway 内置的 PyIngest 实现(一种广泛使用的 Neo4j 提取工具)来加载您的数据。
不需要 Cypher 写作 ,因为 LLM 可以完成所有工作。
在这里,除了让 LLM 将所有 CSV 转换为知识图谱之外,我还使用了 Langchain 的GraphCypherQAChain 作为最后一步, 从提示中生成密码,以便我们无需编写一行密码即可查询图表(用于查询 Neo4j 图表数据库的类似 SQL 的语言)。
该库的 Github 页面上有一个财务示例,但我想测试它是否适用于医疗保健情况。从 Kaggle 上一个非常简单的数据集(疾病症状和患者资料数据集)开始,只有 10 列(疾病、发烧、咳嗽、疲劳、呼吸困难、年龄、性别、血压、胆固醇水平和结果变量),我希望能够向 LLM 提供医疗报告以获得诊断假设。
大号让我们直接进入代码。首先是库:
sudoapt安装python3-pydotgraphviz pip安装neo4j-runway 导入numpy作为np 导入pandas作为pd 从neo4j_runway导入 Discovery、GraphDataModeler、IngestionGenerator、LLM、PyIngest 从 IPython导入。显示 导入display、Markdown、Image 加载环境变量:您可以阅读我的另一篇文章,了解如何在 Neo4j Aura 中创建实例并进行身份验证。
load_dotenv() OPENAI_API_KEY = os.getenv ( ' sk-openaiapikeyhere' ) NEO4J_URL = os.getenv ( 'neo4j+s://your.databases.neo4j.io ' ) NEO4J_PASSWORD = os.getenv ( ' yourneo4jpassword ' ) 现在,让我们加载医疗数据。从Kaggle 网站下载 CSV并加载到 Jupyter 笔记本中。这是一个非常简单的 数据集,但对于测试概念很有用。
disease_df = pd.read_csv( '/home/user/Disease_symptom.csv' ) disease_df
例如,我们可以创建一个导致呼吸困难的所有疾病的列表,这不仅对于选择图中的节点非常有趣,而且对于制定诊断假设也非常有趣:
disease_df[disease_df['呼吸困难']=='是'] 让我们继续。所有变量都必须是字符串(库就是这样创建的),甚至是整数。然后,我们保存 CSV:
disease_df.columns = disease_df.columns. str .strip() for i in disease_df.columns: disease_df[i] = disease_df[i].astype( str ) disease_df.to_csv( '/home/user/disease_prepared.csv' , index= False ) 现在,我们将描述 LLM 的数据,包括每个字段的可能值:
DATA_DESCRIPTION = { '疾病':'疾病或医疗状况的名称。', '发烧':'表示患者是否发烧(是/否)。', '咳嗽':'表示患者是否咳嗽(是/否)。', '疲劳':'表示患者是否感到疲劳(是/否)。', '呼吸困难':'表示患者是否呼吸困难(是/否)。', '年龄':'患者的年龄。', '性别':'患者的性别(男/女)。', '血压':'患者的血压水平(正常/高)。', '胆固醇水平':'患者的胆固醇水平(正常/高)。' , '结果变量' : '表示特定疾病的诊断或评估结果的结果变量(阳性/阴性)。' } 下一步是要求 LLM 分析表格数据,以识别对生成图形数据模型很重要的数据元素。
disc = Discovery(llm=llm,user_input=DATA_DESCRIPTION,data=disease_df) disc.run() 这将生成数据分析的 Markdown 输出:
太好了。现在,让我们创建初始模型:
# 实例化图形数据建模器 gdm = GraphDataModeler(llm=llm, discovery=disc) # 生成模型 gdm.create_initial_model() # 可视化数据模型 gdm.current_model.visualize()
在这里,我的重点是疾病,因此我们将重新排序一些关系。
gdm.iterate_model(user_corrections= ''' 让我们一步一步思考。 请对数据模型进行以下更新: 1. 删除患者与疾病、患者与症状以及患者与结果之间的关系。 2. 将患者节点更改为人口统计。 3. 创建从疾病到人口统计的关系 HAS_DEMOGRAPHICS。 4. 创建从疾病到症状的关系 HAS_SYMPTOM。如果症状值为否,请删除此关系。 5. 创建从疾病到健康指标的关系 HAS_LAB。 6. 创建从疾病到结果的关系 HAS_OUTCOME。 ''' ) from IPython.display import Image, display gdm.current_model.visualize().render( 'output' , format = 'png' ) # 加载并以特定宽度显示图像 img = Image( 'output.png' , width= 1200 ) # 调整宽度根据需要 显示(img)
现在我们可以生成 Cypher 代码和 YAML 文件来将数据加载到 Neo4j 中。以防万一,如果您只是测试或第二次执行此操作,您可能需要将实例重置为空白(删除所有内容)。
# 实例化摄取生成器 gen = IngestionGenerator(data_model=gdm.current_model, username= "neo4j" , password= 'yourneo4jpasswordhere' , uri= 'neo4j+s://123654888.databases.neo4j.io' , database= "neo4j" , csv_dir= "/home/user/" , csv_name= "disease_prepared.csv" ) # 创建摄取 YAML pyingest_yaml = gen.generate_pyingest_yaml_string() # 保存 YAML 的本地副本 gen.generate_pyingest_yaml_file(file_name= "disease_prepared" ) 一切准备就绪。让我们将数据加载到实例中:
PyIngest(yaml_string=pyingest_yaml,数据框=disease_df) 转到Neo4j Aura 实例,打开 ,添加您的密码并通过密码运行此查询:
匹配(n) 其中n:人口统计数据或n:疾病或n:症状或n:结果或n:健康指标 可选匹配(n) - [r] - > (m) 返回n、r、m
按 CTRL + ENTER 你将得到以下结果:
通过检查节点和关系,我们发现症状、健康指标和人口统计数据之间存在着巨大的相互联系:
让我们看看糖尿病:由于没有应用任何过滤器,因此会出现男性和女性,以及所有的实验室、人口统计和结果可能性。
匹配(n:疾病 {name:'糖尿病' }) 其中n:人口统计资料或n:疾病或n:症状或n:结果或n:健康指标 可选匹配(n) - [r] - > (m) 返回n、r、m
或者可能是所有在临床检查中表现为高血压的疾病:
//匹配疾病节点MATCH (d isease) //将疾病节点的 HAS_LAB关系与实验室节点匹配MATCH (d) - [r:HAS_LAB] - > (l) MATCH (d) - [r2:HAS_OUTCOME] - > (o) //确保实验室节点的 bloodPressure 属性设置为“ High” WHERE l.bloodPressure = 'High' AND o.result = ' ositive' RETURN d, properties(d) AS disease_properties, r, properties(r) AS relationship_properties, l, properties(l) AS lab_properties
否现在我的目标很清楚了:我想向谷歌的 LLM(在本例中为Gemini-1.5-Flash) 提交一份医疗报告,以便它通过 Langchain(GraphCypherQAChain)自动创建密码查询,根据症状、健康指标等返回患者可能患有的疾病。让我们这样做:
导入警告从langchain_community 导入json 。图导入带有警告的Neo4 jGraph。catch_warnings ():警告。simplefilter ('ignore')NEO4J _USERNAME = “neo4j” NEO4J _DATABASE = ' neo4j'NEO4J _URI = 'neo4j+s://1236547.databases.neo4j.io'NEO4J _PASSWORD = ' yourneo4jdatabasepasswordhere ' 从实例和模式中获取知识图谱:这里有节点属性和关系属性。
kg = Neo4jGraph( url=NEO4J_URI,用户名=NEO4J_USERNAME,密码=NEO4J_PASSWORD,数据库=NEO4J_DATABASE ) kg.refresh_schema() 打印(textwrap.fill(kg.schema,60)) schema=kg.schema
让我们初始化 Vertex AI Gemini-1.5-Flash:
从langchain.prompts.prompt导入PromptTemplate 从langchain.chains导入GraphCypherQAChain 从langchain.llms导入VertexAI # 初始化 Vertex AI vertexai.init(project= "your-project" , location= "us-west4" ) llm = VertexAI(model= "gemini-1.5-flash" ) 现在,最难的部分是:为 Gemini-1.5-Flash 创建一个详细的指令,以自动生成密码来查询图形数据库并获取我们需要的结果。我们需要一个 MASTER 提示!???? CoT + 少量提示。
prompt_template = """ 让我们一步一步思考: 步骤1: 任务: 生成一个有效且简洁的 Cypher 语句,该语句少于 256 个字符,用于查询图形数据库 不要注释代码。 步骤2:了解数据库模式:{schema} 步骤3:说明: - 在 Cypher 查询中,仅使用模式中和用户问题中出现的关系类型和属性。 - 在 Cypher 查询中,请勿使用用户问题中未包含在所提供模式中的任何其他关系类型或属性。 - 关于年龄,永远不要使用年龄本身。例如:24 岁,使用间隔:超过 20 岁。 - 对年龄仅使用一个语句,始终使用“大于”,永远不要使用“小于”或“等于”。 - 请勿使用数据库中没有的属性键。 步骤4:示例: 以下是针对特定问题生成的 Cypher 语句的几个示例: 4.1 哪些疾病会导致高血压压力? MATCH (d isease) MATCH (d)-[r:HAS_LAB]->(l) WHERE l.bloodPressure = 'High' RETURN d.name 4.2 哪些疾病的表现为高血压? // 匹配疾病节点 MATCH (d isease) // 将疾病节点与实验室节点的 HAS_LAB 关系匹配 MATCH (d)-[r:HAS_LAB]->(l) MATCH (d)-[r2:HAS_OUTCOME]->(o) // 确保实验室节点的 bloodPressure 属性设置为 'High' WHERE l.bloodPressure = 'High' AND o.result=' ositive' RETURN d, properties(d) AS disease_properties, r, properties(r) AS relationship_properties, l, properties(l) AS lab_properties 4.3 老年患者出现高血压、高胆固醇、发烧、疲劳等症状的疾病名称是什么 MATCH (d isease) MATCH (d)-[r1:HAS_LAB]->(lab) MATCH (d)-[r2:HAS_SYMPTOM]->(symptom) MATCH (symptom)-[r3:HAS_DEMOGRAPHICS]->(demo) WHERE lab.bloodPressure = 'High' AND lab.cholesterolLevel = 'High' AND symptom.fever = 'Yes' AND symptom.fatigue = 'Yes' AND TOINTEGER(demo.age) >40 RETURN d.name 4.4 什么疾病会导致高胆固醇患者发烧、疲劳、不咳嗽、不呼吸短促? 匹配 (d isease)-[r:HAS_SYMPTOM]->(s:Symptom) 其中 s.fever = '是' 并且 s.fatigue = '是' 并且 s.difficultyBreathing = '否' 并且 s.cough = '否' 匹配 (d isease)-[r1:HAS_LAB]->(lab:HealthIndicator) 匹配 (d)-[r2:HAS_OUTCOME]->(o:Outcome) 其中 lab.cholesterolLevel='高' 并且 o.result=' ositive' 返回 d,属性(d)作为 disease_properties,r,属性(r)作为 relationship_properties 步骤 5. 每个实体允许的值如下: - 发烧:表示患者是否发烧(是/否)。 - 咳嗽:表示患者是否咳嗽(是/否)。 - 疲劳:表示患者是否感到疲劳(是/否)。 - 呼吸困难:表示患者是否呼吸困难(是/否)。 - 年龄:患者的年龄。 - 性别:患者的性别(男/女)。 - 血压:患者的血压水平(正常/高)。 - 胆固醇水平:患者的胆固醇水平(正常/高)。 - 结果变量:表示特定疾病的诊断或评估结果的结果变量(阳性/阴性)。 步骤 6. 回答问题 {question}。""" 我们建立了 GraphCypherQAChain……
cypher_prompt = PromptTemplate( input_variables=[ "schema" , "question" ], template=prompt_template ) cypherChain = GraphCypherQAChain.from_llm( VertexAI(temperature= 0.1 ), graph=kg, verbose= True , cypher_prompt=cypher_prompt, top_k= 10 # 这也可以调整 ) …并提交医疗报告:
cypherChain.run( """ 患者信息: Jane Doe,58 岁女性,于 2024 年 6 月 15 日入院。 主诉和现病史: Jane 报告高烧高达 104°F,身体疼痛,皮疹, 从入院前五天开始。 既往病史: Jane 没有重大既往病史,也没有已知的过敏症。 体格检查: Jane 的体温为 102.8°F,心率为 110 bpm,血压为 100/70 mmHg,呼吸频率为 每分钟 20 次。未发现瘀点或紫癜。 她可能患有什么疾病?""" ) 输出:这里Gemini-.5-Flash 生成密码来查询图形数据库,通过 JSON 返回 LLM 的结果,LLM 对其进行解释并返回可读的响应:
这个结果没有考虑Gemini-1.5-Flash 的知识库,而只考虑了它正在查询的知识图谱。想象一下,如果我们有一个包含 300 个特征的漂亮数据集!
请注意,我们可以将GraphCypherQAChain中的top_k 调整为1或任何其他值:
如果我们运行最后一个查询,我们将获得具有这些症状的 77 种疾病的列表,但top_k设置为1:
当前neo4j-runway 项目处于测试阶段,存在以下限制: