Créer Pandas DataFrame à partir d'une chaîne

276

Afin de tester certaines fonctionnalités, je voudrais créer un à DataFramepartir d'une chaîne. Disons que mes données de test ressemblent à:

TESTDATA="""col1;col2;col3
1;4.4;99
2;4.5;200
3;4.7;65
4;3.2;140
"""

Quelle est la manière la plus simple de lire ces données dans un Pandas DataFrame?

Emil H
la source

Réponses:

498

Un moyen simple de le faire est d'utiliser StringIO.StringIO(python2) ou io.StringIO(python3) et de le transmettre à la pandas.read_csvfonction. Par exemple:

import sys
if sys.version_info[0] < 3: 
    from StringIO import StringIO
else:
    from io import StringIO

import pandas as pd

TESTDATA = StringIO("""col1;col2;col3
    1;4.4;99
    2;4.5;200
    3;4.7;65
    4;3.2;140
    """)

df = pd.read_csv(TESTDATA, sep=";")
Emil H
la source
7
Si vous avez besoin d'un code compatible avec Python 2 et 3, vous pouvez également l'utiliser en option from pandas.compat import StringIO, notant qu'il s'agit de la même classe que celle fournie avec Python.
Acumenus
3
Pour votre information - pd.read_table()est une fonction équivalente, légèrement meilleure nomenclature: df = pd.read_table(TESTDATA, sep=";").
wkzhu
5
@AntonvBR A noté que l'on pouvait utiliser pandas.compat.StringIO. De cette façon, nous n'avons pas besoin d'importer StringIOséparément. Cependant, le pandas.compatpackage est considéré comme privé selon pandas.pydata.org/pandas-docs/stable/api.html?highlight=compat , laissant ainsi la réponse telle quelle pour l'instant.
Emil H
Il est temps de trier quelle importation: devrions-nous utiliser pandas.compat.StringIO ou Python 2/3 StringIO?
smci
Si vous créez des TESTDATA avec df.to_csv(TESTDATA), utilisezTESTDATA.seek(0)
user3226167
18

Méthode de partage

data = input_string
df = pd.DataFrame([x.split(';') for x in data.split('\n')])
print(df)
shaurya uppal
la source
2
Si vous voulez que la première ligne soit utilisée pour les noms de colonne, changez la 2ème ligne en ceci:df = pd.DataFrame([x.split(';') for x in data.split('\n')[1:]], columns=[x for x in data.split('\n')[0].split(';')])
Mabyn
1
C'est faux, car sur les fichiers CSV, le caractère de nouvelle ligne (\ n) peut faire partie d'un champ.
Antonio Ercole De Luca
Ce n'est pas très robuste, et la plupart des gens seraient mieux avec la réponse acceptée. Il y a une liste très partielle des choses qui peuvent mal tourner avec cela sur thomasburette.com/blog/2014/05/25/…
DanB
10

Une solution rapide et facile pour le travail interactif consiste à copier-coller le texte en chargeant les données depuis le presse-papiers.

Sélectionnez le contenu de la chaîne avec votre souris:

Copiez les données à coller dans une trame de données Pandas

Dans le shell Python, utilisez read_clipboard()

>>> pd.read_clipboard()
  col1;col2;col3
0       1;4.4;99
1      2;4.5;200
2       3;4.7;65
3      4;3.2;140

Utilisez le séparateur approprié:

>>> pd.read_clipboard(sep=';')
   col1  col2  col3
0     1   4.4    99
1     2   4.5   200
2     3   4.7    65
3     4   3.2   140

>>> df = pd.read_clipboard(sep=';') # save to dataframe
user2314737
la source
2
Pas bon pour la reproductibilité, mais sinon une solution assez soignée!
Mabyn
5

Cette réponse s'applique lorsqu'une chaîne est entrée manuellement, pas lorsqu'elle est lue quelque part.

Un CSV traditionnel à largeur variable est illisible pour stocker des données sous forme de variable de chaîne. Surtout pour une utilisation à l'intérieur d'un .pyfichier, pensez plutôt aux données séparées par des tuyaux de largeur fixe. Divers IDE et éditeurs peuvent avoir un plugin pour formater le texte séparé par des tuyaux dans une table soignée.

En utilisant read_csv

Stockez les éléments suivants dans un module utilitaire, par exemple util/pandas.py. Un exemple est inclus dans la docstring de la fonction.

import io
import re

import pandas as pd


def read_psv(str_input: str, **kwargs) -> pd.DataFrame:
    """Read a Pandas object from a pipe-separated table contained within a string.

    Input example:
        | int_score | ext_score | eligible |
        |           | 701       | True     |
        | 221.3     | 0         | False    |
        |           | 576       | True     |
        | 300       | 600       | True     |

    The leading and trailing pipes are optional, but if one is present,
    so must be the other.

    `kwargs` are passed to `read_csv`. They must not include `sep`.

    In PyCharm, the "Pipe Table Formatter" plugin has a "Format" feature that can 
    be used to neatly format a table.

    Ref: https://stackoverflow.com/a/46471952/
    """

    substitutions = [
        ('^ *', ''),  # Remove leading spaces
        (' *$', ''),  # Remove trailing spaces
        (r' *\| *', '|'),  # Remove spaces between columns
    ]
    if all(line.lstrip().startswith('|') and line.rstrip().endswith('|') for line in str_input.strip().split('\n')):
        substitutions.extend([
            (r'^\|', ''),  # Remove redundant leading delimiter
            (r'\|$', ''),  # Remove redundant trailing delimiter
        ])
    for pattern, replacement in substitutions:
        str_input = re.sub(pattern, replacement, str_input, flags=re.MULTILINE)
    return pd.read_csv(io.StringIO(str_input), sep='|', **kwargs)

Alternatives non fonctionnelles

Le code ci-dessous ne fonctionne pas correctement car il ajoute une colonne vide à gauche et à droite.

df = pd.read_csv(io.StringIO(df_str), sep=r'\s*\|\s*', engine='python')

Quant à read_fwf, il n'utilise pas vraiment autant de kwargs optionnels qui read_csvacceptent et utilisent. En tant que tel, il ne devrait pas être utilisé du tout pour les données séparées par des tuyaux.

Acumenus
la source
1
J'ai trouvé (par essais et erreurs) qui read_fwfprend plus d' read_csvarguments que ce qui est documenté, mais il est vrai que certains n'ont aucun effet .
gerrit
-4

Le moyen le plus simple consiste à l'enregistrer dans un fichier temporaire, puis à le lire:

import pandas as pd

CSV_FILE_NAME = 'temp_file.csv'  # Consider creating temp file, look URL below
with open(CSV_FILE_NAME, 'w') as outfile:
    outfile.write(TESTDATA)
df = pd.read_csv(CSV_FILE_NAME, sep=';')

Bonne façon de créer un fichier temporaire: Comment puis-je créer un fichier tmp en Python?

QtRoS
la source
que faire s'il n'y a pas d'autorisation pour créer un fichier?
BingLi224
À mon avis, ce n'est plus le cas le plus simple. Notez que "le plus simple" est indiqué explicitement dans la question.
QtRoS