Cómo construir un archivo JSON usando Pandas

Estoy tratando de tomar un archivo CSV y construir un archivo JSON con los valores. El archivo JSON debe tener un formato muy específico para importarlo a Azure.

Soy muy nuevo en Python, de hecho, esta es la primera vez que uso Python correctamente.

Comencé a usar Pandas para convertir el csv en un marco de datos y luego formateé un poco antes de convertirlo a Json. Este es un buen comienzo, pero no está formateado correctamente. Por favor ver más abajo.

import pandas as pd

df=pd.read_csv("C:\\Users***Required_data.csv")

filtered = df['Work Item Type'].str.contains('Task')

dftest = df[filtered]
dftest = dftest.rename(columns={"Work Item    
Type":"System.WorkItemType","Title":"System.Title","AssignedTo":"System.AssignedTo","State":"System.State","Tags":"System.Tags","Description":"System.Description"})
dftest["System.AreaPath"] = "**********"

dftest.to_json(r"C:\\Users****\\Required_datatest.json",indent=4,orient="records")`

Esto me da el siguiente formato en Json: una matriz de objetos

datos fuente:

fuente

Resultado de mi intento:

[
    {
        "ID":15898,
        "System.WorkItemType":"Task",
        "System.Title":"TK 1.2.1 -  Example data",
        "System.AssignedTo":null,
        "System.State":"New",
        "System.Tags":null,
        "Parent":15887,
        "System.Description":"Example data",
        "System.AreaPath":"Example data"
    }
]

Sin embargo, estoy tratando de construir la siguiente estructura:

Datos de destino en formato Json:

{
      "count": 36,
      "value": [
        {
          "id": 487,
          "rev": 1,
          "fields": {
            "System.AreaPath": "Example data",
            "System.TeamProject": "Example data",
            "System.IterationPath": "Example data",
            "System.WorkItemType": "Task",
            "System.State": "New",
            "System.Reason": "New",
            "System.CreatedDate": "2021-02-22T19:13:24.81Z",
            "System.CreatedBy": "Example data",
            "System.ChangedDate": "2021-02-22T19:13:24.81Z",
            "System.ChangedBy": "Example data",
            "System.Title": "Example data",
            "Microsoft.VSTS.Scheduling.Effort": 0.0,
            "System.Description": "Example data",
            "System.AssignedTo": null,
            "Microsoft.VSTS.Scheduling.RemainingWork": 0.0,
            "Microsoft.VSTS.Common.Priority": 2.0,
            "System.BoardLane": null,
            "System.Tags": null,
            "Microsoft.VSTS.TCM.Steps": null,
            "Microsoft.VSTS.TCM.Parameters": null,
            "Microsoft.VSTS.TCM.LocalDataSource": null,
            "Microsoft.VSTS.TCM.AutomationStatus": null,
            "System.History": null
          },
          "relations": [
            {
              "rel": "System.LinkTypes.Hierarchy-Reverse",
              "url": "Example data",
              "attributes": {
                "isLocked": "false",
                "name": "Parent"
              }
            }
          ],
          "url": "Example data"
        }
    ]
    }

Como puede ver, la matriz se envuelve dentro de otro objeto que tiene 'recuento' y 'valor'. Mi marco de datos se almacena dentro de los 'campos' en la segunda imagen que se requiere.

¿Alguien puede ofrecer orientación aquí? Estoy un poco atascado. Si Pandas no es la herramienta correcta, házmelo saber. Proporcione también la solución más fácil, ya que todavía estoy aprendiendo y me gustaría entenderla.

Gracias de antemano.

Answer

Podría usar una función como tranform_datala siguiente para hacer la transformación adicional que necesita.

import pandas as pd


REVISION = 1


def exclude_keys(to_exclude: dict, *excluded_keys) -> dict:
    def predicate(key_val):
        key, val = key_val
        return key not in excluded_keys
    return dict(filter(predicate, to_exclude.items()))


def transform_data(to_transform: pd.DataFrame) -> dict:
    records = to_transform.to_dict("records")
    values = [
        {
            "id": record["ID"],
            "rev": REVISION,
            "fields": exclude_keys(record, "ID")
        }
        for record in records
    ]
    return {
        "count": len(records),
        "value": values
    }

La llamada transform_datadebería tener este resultado:

>>> transform_data(dftest)
{'count': 1,
 'value': [{'id': 15898,
   'rev': 1,
   'fields': {'System.WorkItemType': 'Task',
    'System.Title': 'TK 1.2.1 -  Example data',
    'System.AssignedTo': None,
    'System.State': 'New',
    'System.Tags': None,
    'Parent': 15887,
    'System.Description': 'Example data',
    'System.AreaPath': 'Example data'}}]}
>>> import json
>>> with open("~/path/to/output.json", "w") as fd: json.dump(transform_data(dftest), fd)

Debería poder adaptar ese código para cualquier transformación o información adicional que necesite agregar a los datos.

Podría haber sido posible hacer lo que hice con Python sin procesar usando Pandas, pero hasta donde yo sé, Pandas se adapta mejor a los datos tabulares planos en lugar de los datos anidados que necesita. Marshmallow también podría valer la pena, ya que maneja bien JSON anidado: https://marshmallow.readthedocs.io/en/stable/quickstart.html