web-dev-qa-db-fra.com

recherche de colonnes imbriquées dans pandas dataframe

J'ai un grand ensemble de données avec de nombreuses colonnes au format JSON (compressé). J'essaie de le convertir en parquet pour un traitement ultérieur. Certaines colonnes ont une structure imbriquée. Pour l'instant, je veux ignorer cette structure et simplement écrire ces colonnes sous forme de chaîne (JSON).

Donc, pour les colonnes que j'ai identifiées, je fais:

df[column] = df[column].astype(str)

Cependant, je ne sais pas quelles colonnes sont imbriquées et lesquelles ne le sont pas. Quand j'écris avec du parquet, je vois ce message:

<stack trace redacted> 

  File "pyarrow/_parquet.pyx", line 1375, in pyarrow._parquet.ParquetWriter.write_table
  File "pyarrow/error.pxi", line 78, in pyarrow.lib.check_status
pyarrow.lib.ArrowInvalid: Nested column branch had multiple children: struct<coordinates: list<item: double>, type: string>

Cela signale que je n'ai pas réussi à convertir l'une de mes colonnes d'un objet imbriqué en chaîne. Mais quelle colonne est à blâmer? Comment le découvrir?

Lorsque j'imprime le .dtypes de mon pandas dataframe, je ne peux pas faire la différence entre la chaîne et les valeurs imbriquées car les deux apparaissent sous la forme object.

EDIT: l'erreur donne un indice sur la colonne imbriquée en affichant les détails de la structure, mais cela prend du temps à déboguer. De plus, il n'imprime que la première erreur et si vous avez plusieurs colonnes imbriquées, cela peut devenir assez ennuyeux

7
Daniel Kats

J'ai eu un problème simialir en travaillant avec Pyspark et un jeu de données en streaming, certaines colonnes étaient imbriquées et d'autres pas.

Étant donné que votre dataframe peut ressembler à ceci:

df = pd.DataFrame({'A' : [{1 : [1,5], 2 : [15,25], 3 : ['A','B']}],
                   'B' : [[[15,25,61],[44,22,87],['A','B',44]]],
                   'C' : [((15,25,87),(22,91))],
                   'D' : 15,
                   'E' : 'A'
                  })


print(df)

                                         A  \
0  {1: [1, 5], 2: [15, 25], 3: ['A', 'B']}   

                                          B                         C   D  E  
0  [[15, 25, 61], [44, 22, 87], [A, B, 44]]  ((15, 25, 87), (22, 91))  15  A  

Nous pouvons empiler votre dataframe et utiliser apply avec type pour obtenir le type de chaque colonne et le transmettre à un dictionnaire.

df.head(1).stack().apply(type).reset_index(0,drop=True).to_dict()
out:
{'A': dict, 'B': list, 'C': Tuple, 'D': int, 'E': str}

avec cela, nous pouvons utiliser une fonction pour renvoyer un Tuple des colonnes imbriquées et non imbriquées.


Fonction

def find_types(dataframe):

    col_dict = dataframe.head(1).stack().apply(type).reset_index(0,drop=True).to_dict()
    unnested_columns = [k for (k,v) in col_dict.items() if v not in (dict,set,list,Tuple)]
    nested_columns = list(set(col_dict.keys()) - set(unnested_columns))
    return nested_columns,unnested_columns
    

En action.

nested,unested = find_types(df)

df[unested]

   D  E
0  15  A

print(df[nested])

                          C                                        A  \
0  ((15, 25, 87), (22, 91))  {1: [1, 5], 2: [15, 25], 3: ['A', 'B']}   

                                          B  
0  [[15, 25, 61], [44, 22, 87], [A, B, 44]]  
1
Manakin

Si vous voulez juste savoir quelle (s) colonne (s) est (sont) le (s) coupable (s), alors écrivez simplement une boucle qui écrit une colonne à la fois et stocke celles qui échouent ...

bad_cols = []
for i in range(df.shape[1]):
    try:
        df.iloc[:, [i]].to_parquet(...)
    except KeyboardInterrupt:
        raise
    except Exception:  # you may want to catch ArrowInvalid exceptions instead
        bad_cols.append(i)
print(bad_cols)
0
Aaron

En utilisant une fonction utilitaire générale comme infer_dtype() in pandas, vous pouvez déterminer si la colonne est imbriquée ou non.

from pandas.api.types import infer_dtype

for col in df.columns:
  if infer_dtype(df[col]) == 'mixed' : 
    # ‘mixed’ is the catchall for anything that is not otherwise specialized
    df[col] = df[col].astype('str')

Si vous ciblez des types de données spécifiques, consultez Dtype Introspection

0
Saurabh P Bhandari