在 Neo4j 和 Python 中处理节点创建的 NaN 值

Handling NaN values for node creation in Neo4j and Python

当遍历 DataFrame 时,neo4j 创建 "NaN" 属性的节点时遇到这个小问题。基本上我有一个如下所示的 DataFrame:

member_id | attributed_provider
--------- | -------------------
1234      | 00A1A
5628      | G1378
2452      | NaN
1683      | 42419
9572      | NaN

然后我遍历我的 DataFrame 来创建我的节点和关系。我的节点将是成员和提供者。该关系将是 "attribution" 关系。这是我的代码:

for row in df.itertuples():
    session.run("MERGE (mbr:Member {memberID: {memberID}) \
                 MERGE (pvdr:Provider {providerID: {provID} \
                 MERGE (mbr)-[:ATTRIBUTED]-(pvdr)",
                {"memberID": row[1], "provID": row[2]})

现在,当我去我的 Neo4j 浏览器检查数据是如何创建的时,我注意到创建了带有 NaN 的提供者,但更奇怪的是这些 NaN 提供者的多个节点被创建了,而实际上只有一个应该因为我正在使用 MERGE 命令而被创建。理想情况下,我什至不希望创建这些 NaN 提供程序节点,因此我尝试使用以下方法在 Neo4j 端删除它们:

MATCH (pvdr:Provider) WHERE pvdr.providerID = "NaN" DELETE pvdr

然而,尽管在浏览器中将 "NaN" 显示为 providerID 值,但 Neo4j 根本无法匹配它们。然后我尝试了:

MATCH (pvdr:Provider) WHERE pvdr.providerID is NULL DELETE pvdr

同样,没有这样的比赛。

因此,我有两个问题:

1) 我如何使用 Cypher QL 匹配这些 NaN 提供程序?

2) 在 Python 的 node/relationship 创作部分有没有更好的方法来编写我的代码?

作为我第二个问题的后续,我使用 pd.notnull 检查来更改我的脚本,但我可以想象当我为 NaN 求值时我必须编写的 if 语句的数量扩展到更大的数据集,所以再一次,有没有更好的方法来做到这一点:

# Is there a better way to do this without doing the pd.notnull check?
for row in df.itertuples():
    if pd.notnull(row[2]):
        session.run("MERGE (mbr:Member {memberID: {memberID}) \
                     MERGE (pvdr:Provider {providerID: {provID} \
                     MERGE (mbr)-[:ATTRIBUTED]-(pvdr)",
                    {"memberID": row[1], "provID": row[2]})
    else:
        session.run("MERGE (mbr:Member {memberID: {memberID})",
                    {"memberID": row[1]})

仅供参考,我使用的是官方 Neo4j Python 驱动程序。

似乎没有有效处理 NaN 的解决方案。我想出的最接近的解决方案是定义一个自定义函数,如果值为 np.nan,则 returns 和 None。但是,当将其传递到 Neo4j 会话时,它仍然创建了一个 属性,但该 属性.

的字符串为空

最后,我只是创建了一个 CSV 文件并使用了 Neo4j 的 LOAD CSV 命令。我不得不做多次传球。前 2 次通过创建我的成员和提供者节点。然后最后一次执行条件 NULL 检查以创建关系。 LOAD CSV 运行 也比使用 Python 方法更快。

// Create members
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///dbt_enr_unique.csv" AS row
CREATE (mbr:Member {memberID: row.member_id})

// Create providers
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///dbt_enr_unique.csv" AS row
CREATE (mbr:Provider {providerID: row.attributed_provider})

// Create member-provider relationships
USING PERIODIC COMMIT
LOAD CSV WITH HEADERS FROM "file:///dbt_enr_unique.csv" AS row
FOREACH (x IN CASE WHEN row.attributed_provider IS NULL THEN [] ELSE [1] END | 
    MERGE (mbr:Member {memberID: row.member_id})
    MERGE (pvdr:Provider {providerID: row.attributed_provider})
    MERGE (mbr)-[:ATTRIBUTED_WITH]-(pvdr)
)