Extraction de données JSON contenues dans une colonne d'un DataFrame

a marqué ce sujet comme résolu.

Bonjour à tous,

Je continue mon apprentissage de Pandas et je me heurte à un problème que l’on peut voir assez souvent.

J’ai récupérer un Fichier csv de ce site c’est un petit fichier contenant qu’une cinquantaine de lignes.

Plusieurs colonnes du dataframe généré contiennent des données JSON. JE voudrais les extraire pour constituer un autre dataframe associé.

a partir des données de bases je lance :

genres_json = pd.json_normalize(data= movies['genres'] , max_level = 0)

j’obtiens l’erreur suivante : AttributeError: 'str' object has no attribute 'values’

Avec les autres colonnes contenant du JSON, j’obtiens la même erreur.

J’avoue que je tourne en rond depuis ce matin et que je n’arrive pas plus a penser.

Est-ce que vous sauriez d’où vient cette erreur et surtout comme faire en sorte de construire mon second DF avec les données contenues (par exemple dans "genres").

Je vous remercie par avance. Bonne soirée

+0 -0

Bonjour,

Le problème c’est que le JSON est erroné. Prenons celui-ci :

{'id': 10194, 'name': 'Toy Story Collection', 'poster_path': '/7G9915LfUQ2lVfwMEEhDsn3kT4B.jpg', 'backdrop_path': '/9FBwqcd9IRruEDUrTdcaafOMKUq.jpg'}

Tous les apostrophes (simple quote) devraient être des guillemets (double quotes) :

{"id": 10194, "name": "Toy Story Collection", "poster_path": "/7G9915LfUQ2lVfwMEEhDsn3kT4B.jpg", "backdrop_path": "/9FBwqcd9IRruEDUrTdcaafOMKUq.jpg"}

On le voit bien avec les couleurs syntaxiques. Il te faut donc transformer les chaînes avant de les parser.

+0 -0

@Yarflam pour ton aide.

Bien la nuit porte conseil. D’après ce que je comprends la méthode json_normalize(), transforme un objet json (une liste) en un dataframe.

Hors dans le dataframe des films, les données sont des objets "string".

Du coup, cela fonctionne avec,par exemple, un

import json
data = json.loads(movies.iloc[0]['genres'])
new_df = pd.json_normalize(data)


#Output:
    id  name
0   16  Animation
1   35  Comedy
2   10751   Family

Je me retrouve bien avec un DF issue d’un élément d’une colonne de mon dataframe initial. Maintenant, il faut que je trouve un moyen de construire un dataframe avec tous les éléments de la même colonne et l’associer au dataframe initial.

Cela serait comme une relation one-to-many en SQL.

Si vous avez des conseils à me donner.

Bonne journée à tous

Hello @netchaiev !

Mon message ne va malheureusement pas t’être très utile car j’ai exactement le même problème que toi. Enfin presque. Le dataset que j’ai possède 5 colonnes sur la trentaine en JSON. J’ai réussi sans problème à en extraire 3 correctement avec le code suivant :

df = df.join(json_normalize(df["category"].map(json.loads).tolist(), sep=",").add_prefix("category.")).drop(["category"], axis=1)

Néanmoins, 2 colonnes me retournent les messages d’erreur suivants :

JSONDecodeError: Expecting ',' delimiter: line 1 column 33 (char 32)

JSONDecodeError: Expecting ',' delimiter: line 1 column 137 (char 136)

J’ai donc essayé ta technique. Cela fonctionne mais seulement pour 1 ligne (et j’en ai 2508729…)

As-tu réussi à trouver un moyen d’obtenir tous les éléments de ton dataframe?

Merci d’avance pour ton retour!

Bonjour à tous,

@TiffanyTD,

Bon dans ma situation, je réussissais à récupérer les infos mais uniquement ligne par ligne, mais pas en global.

Du coup, ce matin j’ai essayé un truc qui fonctionne à peu près. VOici ce que je fais :

Après avoir importé mes données dans un Dataframe, je format les données "json" qui sont en string. Puis j’exporte les données en json et je réimporte. Bon là, c’est bancale mais je n’ai pas trouvé mieux. Enfin, je construis mon DataFrame avec les données imbriquées.

voici ce que cela donne :

def injson(x):
    return(json.loads(x))

da['json'] = da['content'].apply(injson)
da.reset_index(drop = True, inplace=True)

results = da.to_json( r'myJsonFile.json', orient='table')
with open('./'myJsonFile.json', "r") as f:
    d = json.load(f)

New_DF = pd.json_normalize(data=d['data'], record_path=['js'], meta=['id'], meta_prefix='_')

Là cela fonctionne, je vois mes données du DF maitre, avec les éléments JSon. Mais, je me rends compte qu’il y a du JSON imbriqué. Donc je reprends mon truc et fais :

works_data = pd.json_normalize(data=d['data'], record_path=['json', 'sousChaineJSon'], meta=['id', 'reference'], meta_prefix='_', max_level =0 )

Mais là, j’obtiens une erreur disant que "sousChaineJSon" n’existe pas . Et là je ne comprends pas car elle existe bien cette balise.

Si tu veux, je nettoie un peu mais données et te fais un cas pratique. Dis moi, si tu trouves des choses, parce que je sens bien que ce que j’ai fait n’est pas très orthodoxe.

Bon fin de WE

Après avoir importé mes données dans un Dataframe, je format les données "json" qui sont en string. Puis j’exporte les données en json et je réimporte. Bon là, c’est bancale mais je n’ai pas trouvé mieux. Enfin, je construis mon DataFrame avec les données imbriquées.

netchaiev

En effet, c’est bancale. Tu as des tableaux une fois le dump récupéré (que tu appelles du json), pourquoi ne pas les merger ensemble ? Puis à la fin tu construis ton Dataframe.

Grosso modo l’algo :

Charger le fichier de données
Définition de la variable cumulative 'genre'
Pour chaque ligne du CSV
  Extraire le dump de la colonne 'genre' si non vide sinon continuer la boucle
  Merger le dump avec la variable cumulative associé à la colonne 'genre'
Charger les Dataframe des variables cumulatives (uniquement 'genre' dans l'exemple)
Et afficher

@Yarflam,

Merci pour cette suggestion, au début je pensais faire quelque chose dans le genre. Mais, après avoir parcouru la doc de Pandas et en particulier pd.json_normalize, il me semblait que c"était possible directement via pandas. C’est pour cela que je me suis lancer la dedans.

Ai-je eu tord ? Voir ai-je complètement compris de travers Pandas ?

Bonne soirée

Ai-je eu tord ? Voir ai-je complètement compris de travers Pandas ?

netchaiev

Je n’en ai aucune idée. Il me faudrait creuser Pandas pour te répondre.

En revanche, je retiens une chose de mon expérience perso/pro/scolaire : Keep It Simple Stupid (méthode KISS), l’idée c’est qu’il vaut mieux toujours appliquer une solution simple que l’on maîtrise bien avant de tenter quoi ce soit de complexe. Le code est peut-être moche, peu efficace mais il est fonctionnel ! Après on peut l’améliorer en suivant une méthode plus propre ; chaque chose en son temps.

Edit : sinon y’a cette page de la doc qui peut-être utile https://pandas.pydata.org/pandas-docs/stable/user_guide/merging.html.

+0 -0

Oui cette page et celles plus spécifique à merge, je les ai parcouru en long en large et en travers pour faire des comparaisons entre des jeux de données. Je crois qu’un de mes posts portait sur le sujet et surtout sur le temps d’exécution d’une comparaison de 5 000 000 de lignes d’un côté et 6 000 000 de l’autre.

Pour tout te dire, c’est aussi un peut pour le sport que je tente cela avec Pandas, histoire d’apprendre un truc. Je me suis mis à python, il y a peu de temps pour cause d’analyse de donnée et excel n’i arrivait plus. Et puis cela m’amuse..

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte