preloader

JSON

Índice de contenido

JSON (JavaScript Object Notation) es un formato de datos muy utilizado para representar datos estructurados. En Python, el formato JSON se almacena como un string, por ejemplo:

python
subject_json = '{"Asignatura": "Historia", "Aulas": ["A3", "B2"]}'
subject_json
'{"Asignatura": "Historia", "Aulas": ["A3", "B2"]}'

Librería pandas

Pandas incluye la función pd.read_json() que permite convertir una cadena en formato JSON a un objeto de pandas (una Serie o un DataFrame). Sus principales parámetros son los siguientes:

  • path_or_buf es una cadena de JSON válida, un objeto de tipo archivo (que disponga de método .read()) o la ruta de un archivo.
  • orient debe ser una cadena de texto indicando cómo es el formato JSON esperado. Se pueden generar cadenas de texto en formato JSON válido mediante la función to_json() de pandas con una orientación adecuada. Las posibles orientaciones son las siguientes:
    • ‘split’: tipo diccionario {index -> [index], columns -> [columns], data -> [values]}
    • ‘records’: tipo lista [{column -> value}, … , {column -> value}]
    • ‘index’: tipo diccionario {index -> {column -> value}}
    • ‘columns’: tipo diccionario {column -> {index -> value}}
    • ‘values’: simplemente los valores de un vector Los valores permitidos y predeterminados dependen del valor del parámetro typ:
      • Cuando typ == ‘series’, las orientaciones permitidas son {‘split’,‘records’,‘index’}, y por defecto es ‘index’.
      • Cuando typ == ‘frame’,las orientaciones permitidas son {‘split’,‘records’,‘index’, ‘columns’,‘values’, ’table’}, y por defecto es ‘columns’.
  • typ es el tipo de objeto que se desea generar y puede ser uno de los dos siguientes: {‘frame’, ‘series’}. Por defecto es ‘frame’.
  • convert_dates puede ser False o True (este último es el valor por defecto), o bien una lista con nombres de columnas. Si es False, no se tratará de leer ninguna columna como fecha. Si se trata de una lista de nombres de columnas, esas columnas se convertirán y, además, las columnas que aparentemente puedan hacer referencia a fechas también podrán hacerlo (según el parámetro keep_default_dates, explicado a continuación).
  • keep_default_dates también es un booleano y por defecto es True. Si el parámetro convert_dates no está puesto en False, entonces trata de convertir las columnas que aparentemente puedan hacer referencia a fechas. Detecta que una columna podría ser de tipo fecha fijándose en el nombre que tiene dicha columna, en concreto fijándose en los siguientes detalles:
    • El nombre termina en ‘_at’
    • El nombre termina en ‘_time’
    • El nombre empieza con ’timestamp’
    • El nombre incluye la palabra ‘modified’
    • EL nombre incluye la palabra ‘date’
  • encoding es el tipo de codificación de los datos y por defecto es ‘utf-8’.
  • lines es un booleano (por defecto False) y permite indicar si se quiere leer el archivo como un objeto json línea a línea.
  • compression puede ser {‘infer’, ‘gzip’, ‘bz2’, ‘zip’, ‘xz’, None}, y por defecto es ‘infer’. Se utiliza para descomprimir datos sobre la marcha. Si es “infer”, utiliza gzip, bz2, zip o xz si path_or_buf es una cadena que termina en “.gz”, “.bz2”, “.zip” o “xz”, respectivamente. Si se quiere usar “zip”, el archivo ZIP debe contener solo un archivo de datos para ser leído.
  • nrows es un entero que permite poner un límite de líneas a leer. Solo se puede pasar si lines = True.
python
import pandas as pd

Lectura de archivos en formato JSON

python
pd.read_json(path_or_buf = "C:/Users/user/Downloads/201906_Usage_Bicimad.zip",
            encoding = "iso-8859-2",
            lines = True)

_iduser_day_codeidplug_baseuser_typeidunplug_basetravel_timeidunplug_stationageRangeidplug_stationunplug_hourTimezip_codetrack
0{'$oid': '5cf83b752f3843a016be4e2f'}e4d55deb9ac172a8d8f5f0a32599815bd51b7c8760d67e...211821990066{'$date': '2019-06-01T00:00:00.000+0200'}NaN
1{'$oid': '5cf83b762f3843a016be4e48'}8a0c4123e924a50a958f51985eb71aea750fb072438035...19119359714136{'$date': '2019-06-01T00:00:00.000+0200'}28039NaN
2{'$oid': '5cf83b762f3843a016be4e4f'}a6a9c1f74a68496000542210abc4fc2eba79e2756ad535...171737539438{'$date': '2019-06-01T00:00:00.000+0200'}28013NaN
3{'$oid': '5cf83b762f3843a016be4e53'}5706c0bd494acc02279d532821c9666b0e506d4f81c838...412126466590{'$date': '2019-06-01T00:00:00.000+0200'}28009NaN
4{'$oid': '5cf83b762f3843a016be4e54'}eb1b6d32bd4add5d5ff91af72a38786d61075c090383a5...31133671524166{'$date': '2019-06-01T00:00:00.000+0200'}28006NaN
.......................................
450806{'$oid': '5d19317fa9cd6441ac49177b'}2ea80cbe37fc790baa40bf26547aee6bef31b77fa3afcc...9312329383490{'$date': '2019-06-26T23:00:00.000+0200'}NaN
450807{'$oid': '5d19317fa9cd6441ac49177c'}97032d3747cb14430b7899cfdfdf17f4f8bb92da7ccb60...12123317515135{'$date': '2019-06-26T23:00:00.000+0200'}28045NaN
450808{'$oid': '5d193180a9cd6441ac49177f'}4b8a5eabbe71df3addcff5ccdec5b7a6b49252f23edb7c...311415581720174{'$date': '2019-06-26T23:00:00.000+0200'}NaN
450809{'$oid': '5d193180a9cd6441ac491780'}a155966b8f5dfaeaac34612d902eab89b8dc590df6b9e9...61621993502{'$date': '2019-06-26T23:00:00.000+0200'}NaN
450810{'$oid': '5d193180a9cd6441ac491781'}a2859c578a940a5b6f9697d37bbb60887b59668b74f4ab...3119301305130{'$date': '2019-06-26T23:00:00.000+0200'}28010NaN

450811 rows × 12 columns

Conversión de un dataframe a JSON

python
df = pd.DataFrame([["a", "b"], ["c", "d"]],
                  index=["row 1", "row 2"],
                  columns=["col 1", "col 2"])
df

col 1col 2
row 1ab
row 2cd
python
# 'split': tipo diccionario {index -> [index], columns -> [columns], data -> [values]}
json_string1 = df.to_json(orient = "split")
json_string1
'{"columns":["col 1","col 2"],"index":["row 1","row 2"],"data":[["a","b"],["c","d"]]}'
python
# 'records': tipo lista [{column -> value}, ... , {column -> value}]
json_string2 = df.to_json(orient = "records")
json_string2
'[{"col 1":"a","col 2":"b"},{"col 1":"c","col 2":"d"}]'

Carga de una cadena JSON en un dataframe

python
pd.read_json(json_string1, orient= "records")

columnsindexdata
0col 1row 1[a, b]
1col 2row 2[c, d]
python
pd.read_json(json_string1, orient= "split")

col 1col 2
row 1ab
row 2cd
python
# 'columns': tipo diccionario {column -> {index -> value}}
pd.read_json(json_string1, orient= "columns")

columnsindexdata
0col 1row 1[a, b]
1col 2row 2[c, d]

Módulo json de la librería estándar de Python

python
import json

Lectura de archivos en formato JSON

Es posible cargar un archivo en formato JSON a un diccionario de Python utilizando el método json.load():

python
data_path = "C:/Users/user/Desktop/201906_Usage_Bicimad.json"
data_path
'C:/Users/user/Desktop/201906_Usage_Bicimad.json'
python
json.load(data_path)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-d3754150bc61> in <module>
----> 1 json.load(data_path)

~\anaconda3\envs\python-385\lib\json\__init__.py in load(fp, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    291     kwarg; otherwise ``JSONDecoder`` is used.
    292     """
--> 293     return loads(fp.read(),
    294         cls=cls, object_hook=object_hook,
    295         parse_float=parse_float, parse_int=parse_int,

AttributeError: 'str' object has no attribute 'read'
python
with open(data_path, "r") as f:
    json.load(f)
---------------------------------------------------------------------------
JSONDecodeError                           Traceback (most recent call last)
<ipython-input-4-571467e78874> in <module>
      1 with open(data_path, "r") as f:
----> 2     json.load(f)

~\anaconda3\envs\python-385\lib\json\__init__.py in load(fp, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    291     kwarg; otherwise ``JSONDecoder`` is used.
    292     """
--> 293     return loads(fp.read(),
    294         cls=cls, object_hook=object_hook,
    295         parse_float=parse_float, parse_int=parse_int,

~\anaconda3\envs\python-385\lib\json\__init__.py in loads(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
    355             parse_int is None and parse_float is None and
    356             parse_constant is None and object_pairs_hook is None and not kw):
--> 357         return _default_decoder.decode(s)
    358     if cls is None:
    359         cls = JSONDecoder

~\anaconda3\envs\python-385\lib\json\decoder.py in decode(self, s, _w)
    338         end = _w(s, end).end()
    339         if end != len(s):
--> 340             raise JSONDecodeError("Extra data", s, end)
    341         return obj
    342 

JSONDecodeError: Extra data: line 2 column 1 (char 364)
python
rows_list = []
for line in open(data_path, "r"):
    rows_list.append(json.loads(line))
rows_list[:3]
[{'_id': {'$oid': '5cf83b752f3843a016be4e2f'},
  'user_day_code': 'e4d55deb9ac172a8d8f5f0a32599815bd51b7c8760d67e42b11adf7c0829341b',
  'idplug_base': 21,
  'user_type': 1,
  'idunplug_base': 8,
  'travel_time': 219,
  'idunplug_station': 90,
  'ageRange': 0,
  'idplug_station': 66,
  'unplug_hourTime': {'$date': '2019-06-01T00:00:00.000+0200'},
  'zip_code': ''},
 {'_id': {'$oid': '5cf83b762f3843a016be4e48'},
  'user_day_code': '8a0c4123e924a50a958f51985eb71aea750fb072438035f149283490cc6bfaf4',
  'idplug_base': 19,
  'user_type': 1,
  'idunplug_base': 19,
  'travel_time': 359,
  'idunplug_station': 71,
  'ageRange': 4,
  'idplug_station': 136,
  'unplug_hourTime': {'$date': '2019-06-01T00:00:00.000+0200'},
  'zip_code': '28039'},
 {'_id': {'$oid': '5cf83b762f3843a016be4e4f'},
  'user_day_code': 'a6a9c1f74a68496000542210abc4fc2eba79e2756ad5355a626632f7783dd418',
  'idplug_base': 17,
  'user_type': 1,
  'idunplug_base': 7,
  'travel_time': 375,
  'idunplug_station': 39,
  'ageRange': 4,
  'idplug_station': 38,
  'unplug_hourTime': {'$date': '2019-06-01T00:00:00.000+0200'},
  'zip_code': '28013'}]

Conversión de un diccionario a JSON

Es posible cargar un diccionario de Python en una cadena en formato JSON utilizando el método json.dumps():

python
subject_dict = {"Asignatura": "Historia", "Aulas": ["A3", "B2"]}
subject_dict
{'Asignatura': 'Historia', 'Aulas': ['A3', 'B2']}
python
json.dumps(subject_dict)
'{"Asignatura": "Historia", "Aulas": ["A3", "B2"]}'

¿Qué pasa si introducimos, por ejemplo, una tilde?

python
subject_dict2 = {"Asignatura": "Matemáticas", "Aulas": ["A3", "B2"]}
subject_dict2
{'Asignatura': 'Matemáticas', 'Aulas': ['A3', 'B2']}
python
json.dumps(subject_dict2)
'{"Asignatura": "Matem\\u00e1ticas", "Aulas": ["A3", "B2"]}'

Por defecto, json.dumps() hace que todo el texto del diccionario de Python se interprete como codificado en ASCII. Si hay caracteres que no son ASCII, se escapan automáticamente. Para mantener los caracteres Unicode sin alterar, se puede introducir el parámetro ensure_ascii = False:

python
json.dumps(subject_dict2, ensure_ascii = False)
'{"Asignatura": "Matemáticas", "Aulas": ["A3", "B2"]}'

Carga de una cadena JSON en un diccionario

Es posible cargar una cadena en formato JSON a un diccionario de Python utilizando el método json.loads():

python
string1 = '{"Asignatura": "Historia", "Aulas": ["A3", "B2"]}'
string1
'{"Asignatura": "Historia", "Aulas": ["A3", "B2"]}'
python
dict1 = json.loads(string1)
dict1
{'Asignatura': 'Historia', 'Aulas': ['A3', 'B2']}

Impresión con formato

Para imprimir datos en formato JSON de forma más apropiada, se pueden pasar parámetros especiales al método json.dumps():

python
subject_dict = json.loads(string1)
subject_dict
{'Asignatura': 'Historia', 'Aulas': ['A3', 'B2']}
python
string2 = json.dumps(subject_dict, indent = 4, sort_keys = True)
print(string2)
{
    "Asignatura": "Historia",
    "Aulas": [
        "A3",
        "B2"
    ]
}
comments powered by Disqus