【问题标题】:Convert pandas dataframe to dict to JSON, unflatten nested subkeys, drop None/NaN keys将 pandas 数据框转换为 dict 为 JSON,展开嵌套子键,删除 None/NaN 键
【发布时间】:2019-09-28 04:10:43
【问题描述】:

是否可以在 Pandas 中一次性使用比下面更多的 Pythonic 代码完成以下操作?

我有来自 pandas-dataframe 的一行:

  • 某些值可能是 NaN 或空字符串或类似内容
  • 我想将此信息映射到一个字典(然后将其转换为 JSON 并传递给另一个应用程序)
  • 但是,字典中不应包含 NaN。 (默认情况下,它们以None 传递)
  • 字典子键 'c.x', 'c.y', 'c.z' 应该是未展平的,即转换为带有键 x, y, z 的子字典 c。同样,应该删除每一行中的 NaN 键。

示例输入:我使用row = next(df.iterrows()) 遍历数据框中的行,示例行如下所示:

a        3
b      NaN
c.x      4
c.y      5
c.z    NaN

期望的输出

{"A": 3,
"C": {"X": 4, "Y": 5}}

(对我而言)最自然的方式是这样的:

outdict={"A": row['a'] if not pandas.isna(row['a']) else None,
    "B": row['b'] if not pandas.isna(row['b']) else None,
    "C": {"X": row['c.x'] if not pandas.isna(row['c.x']) else None,
        "Y": row['c.y'] if not pandas.isna(row['c.y']) else None,
        "Z": row['c.z'] if not pandas.isna(row['c.z']) else None
}}

但是,这仍然将None 分配给我想保持为空的插槽(接收应用程序难以处理nulls)。

一种解决方法是使用此代码,然后在第二遍中删除所有 None 值,或者我可以为每个值使用outdict.update(如果值为NaN,则不更新)。但是这两种解决方案对我来说似乎都不是很有效。

【问题讨论】:

  • 您的数据框中是否有一行包含该文本的行或数据框中的两列?所以 a、b 等在一列中,而值在另一列中?
  • 递归函数我猜你在找什么。
  • 您的标题非常具有误导性:严格来说,您不只是想“分配给 dict 中的某些键”,您问题的更大部分是您想创建 subdicts 'c'对于 'cx, cy, c.z',pandas 和 json 代码通常不会处理。您还想删除 NaN 键。
  • 对于非扁平化子字典,请参阅10 questions on [python] unflatten dict。如果 JSON 也丢弃 None 键,可能对 JSON 有帮助。

标签: python json pandas dictionary nested


【解决方案1】:

要将您的 DataFrame 转换为没有 NaN 的字典,有一种简单的方法:

df.dropna().to_dict()

但是您还想从组合键创建子字典,我发现除了循环之外别无他法:

df = DataFrame({"col": [3, None, 4, 5, None]}, index=["a", "b", "c.x", "c.y", "c.z"])
d = df.dropna().to_dict()

d 是:

{'col': {'a': 3.0, 'c.x': 4.0, 'c.y': 5.0}}

然后:

d2 = dict()
for k, v in d['col'].items(): 
     if k.count('.'): 
         a, b = k.split('.') 
         d2.setdefault('a', {}) 
         d2[a][b] = v 
     else: 
         d2[k] = v

d2 是:

{'a': 3.0, 'c': {'y': 5.0, 'x': 4.0}}

【讨论】:

    【解决方案2】:

    如果 rowSeries 对象,则以下代码不会为 NaN 创建任何条目:

    outdict = {row.index[i]: row[i]
               for i in range(data.shape[1])
               if not pandas.isna(row[i])}
    

    但是,它不会创建您想要的嵌套结构。我可以想到几种方法来解决这个问题,但没有一种是非常优雅的。我能想到的最好方法是在创建outdict 时排除带有a.b 形式标签的列;

    outdict = {row.index[i]: row[i]
               for i in range(data.shape[1])
               if not (pandas.isna(row[i]) or '.' in row.index[i])}
    

    然后单独创建 subdicts 并在 outdict 中分配它们。

    【讨论】:

      猜你喜欢
      • 2017-03-21
      • 2020-12-16
      • 1970-01-01
      • 2019-11-24
      • 1970-01-01
      • 2013-08-03
      • 2022-01-21
      相关资源
      最近更新 更多