web-dev-qa-db-fra.com

Pandas DataFrame stocké la liste sous forme de chaîne: comment reconvertir en liste?

J'ai un n - par - m Pandas DataFrame df défini comme suit. (Je sais que ce n'est pas la meilleure façon de le faire. Cela a du sens pour ce que j'essaie de faire dans mon code actuel, mais ce serait TMI pour ce poste, prenez donc simplement mon mot que cette approche fonctionne dans mon scénario particulier.)

>>> df = DataFrame(columns=['col1'])
>>> df.append(Series([None]), ignore_index=True)
>>> df
Empty DataFrame
Columns: [col1]
Index: []

J'ai stocké des listes dans les cellules de ce DataFrame comme suit.

>>> df['column1'][0] = [1.23, 2.34]
>>> df
     col1
0  [1, 2]

Pour une raison quelconque, le DataFrame a stocké cette liste sous forme de chaîne au lieu d'une liste.

>>> df['column1'][0]
'[1.23, 2.34]'

J'ai 2 questions pour vous.

  1. Pourquoi le DataFrame stocke-t-il une liste sous forme de chaîne et existe-t-il un moyen de contourner ce comportement?
  2. Sinon, existe-t-il un moyen Pythonique de convertir cette chaîne en liste?

Mise à jour

Le DataFrame que j'utilisais avait été enregistré et chargé à partir d'un format CSV. Ce format, plutôt que le DataFrame lui-même, convertissait la liste d'une chaîne en un littéral.

38
Gyan Veda

Comme vous l'avez souligné, cela peut généralement se produire lors de l'enregistrement et du chargement de pandas DataFrames en tant que fichiers .csv, Qui est un format texte.

Dans votre cas, cela s'est produit car les objets de liste ont une représentation sous forme de chaîne, ce qui leur permet d'être stockés sous forme de fichiers .csv. Le chargement de .csv Produira alors cette représentation sous forme de chaîne.

Si vous souhaitez stocker les objets réels, vous devez utiliser DataFrame.to_pickle() (remarque: les objets doivent être picklables!).

Pour répondre à votre deuxième question, vous pouvez la reconvertir avec ast.literal_eval :

>>> from ast import literal_eval
>>> literal_eval('[1.23, 2.34]')
[1.23, 2.34]
46
Alex Thornton

Je viens de rencontrer ce problème et il existe une solution très simple ( pandas.eval () ). J'utilise pandas 0.20.0.

# SETUP
import pandas as pd
import io

csv = io.StringIO(u'''
id  list
A1  [1,2]
A2  [3,4]
A3  [5,6]
''')

df = pd.read_csv(csv, delim_whitespace = True)

# TYPE CHECK <type 'str'>
print type(df.at[0, 'list'])

# MAIN CONVERSION
df['list'] = pd.eval(df['list'])

# TYPE CHECK <type 'list'>
print type(df.at[0, 'list'])
4
elPastor

1) Il existe un moyen de contourner ce comportement. Utilisez loc aide ici.

>>> import pandas as pd

>>> df = pd.DataFrame(columns=['column1'])
>>> df = df.append(pd.Series(data = {'column1':[None]}), ignore_index = True)

   column1
0  [None]

>>> # Add list to index 0 in column1
>>> df.loc[0,'column1'] = [1.23, 2.34]
>>> print(df.loc[0, 'column1'])
[1.23, 2.34]

2) Manière pythonique de convertir cette chaîne en liste. (C'est probablement ce que vous voulez car le DataFrame que vous utilisez a été enregistré et chargé à partir d'un format CSV, il existe quelques solutions pour cela). Ceci est un ajout à la réponse de pshep123.

from ast import literal_eval
import pandas as pd

csv = io.StringIO(u'''
id  list
A1  [1,2]
A2  [3,4]
A3  [5,6]
''')
df = pd.read_csv(csv, delim_whitespace = True)

# Output is a string
df.loc[0, 'list']
'[1,2]'

# Convert entire column to a list
df.loc[:,'list'] = df.loc[:,'list'].apply(lambda x: literal_eval(x))

# Output is a list
df.loc[0, 'list']
[1, 2]

J'ai eu le même problème. Lors du stockage d'une colonne de liste de trames de données dans un fichier CSV à l'aide de df.to_csv (), les colonnes de liste sont converties en chaîne, par exemple "[42, 42, 42]" au lieu de [42, 42, 42]

La réponse d'Alex est correcte et vous pouvez utiliser literal_eval Pour reconvertir la chaîne en liste. Le problème avec cette approche est que vous devez importer une bibliothèque supplémentaire et que vous devez appliquer ou mapper la fonction à votre trame de données. Le moyen le plus simple est de forcer Pandas pour lire la colonne comme un objet Python (dtype)

df["col1"].astype('O')

Le O est utilisé pour Python objets y compris les listes. Plus d'informations ici . Veuillez noter que cette méthode échoue si vous analysez des chaînes de liste vides: "[]"

Alternativement, vous pouvez également appliquer une fonction à votre colonne (celle-ci est pour les entiers):

def stringToList(string):
    # input format : "[42, 42, 42]" , note the spaces after the commas, in this case I have a list of integers
    string = string[1:len(string)-1]
    try:
        if len(string) != 0: 
            tempList = string.split(", ")
            newList = list(map(lambda x: int(x), tempList))
        else:
            newList = []
    except:
        newList = [-9999]
    return(newList)

df["col1"] = df["col1"].apply(lambda x: stringToList(x))
1
Rutger Hofste

pour référence seulement ... pandas ne convertit pas les listes en chaîne. ..

In [29]: data2 = [{'a': [1, 5], 'b': 2}, {'a': 5, 'b': 10, 'c': 20}]                                                                                        

In [30]: df = pd.DataFrame(data2)                                                                                                                           

In [31]: df                                                                                                                                                 
Out[31]: 
        a   b   c
0  [1, 5]   2 NaN
1       5  10  20

In [32]: df['a'][0], type(df['a'][0])                                                                                                                       
Out[32]: ([1, 5], list)

In [33]: pd.__version__
Out[33]: '0.12.0'
1
namit

Vous pouvez utiliser directement pandas -
df = pd.read_csv(df_name, converters={'column_name': eval})

Cela lira cette colonne comme un dtype correspondant dans python au lieu d'une chaîne.

0
markroxor

Un simple hack que j'ai utilisé consiste à appeler une fonction lambda qui indexe les premier et dernier éléments (les crochets de liste sous forme de str) et appelle la méthode split suivie d'une autre qui remplace les éléments de liste par des entiers.

df['column1'] = df['column1'].apply(lambda x:x[1:-1].split(',')).apply(lambda x:[int(i) for i in x])
0
Hassen Morad