Crea Pandas DataFrame da una stringa


276

Per testare alcune funzionalità vorrei creare un DataFrameda una stringa. Supponiamo che i miei dati di test siano:

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

Qual è il modo più semplice per leggere quei dati in un Panda DataFrame?

Risposte:


498

Un modo semplice per farlo è usare StringIO.StringIO(python2) o io.StringIO(python3) e passarlo alla pandas.read_csvfunzione. Per esempio:

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=";")

7
Se hai bisogno di un codice compatibile con Python 2 e 3, puoi anche opzionalmente usare from pandas.compat import StringIO, notando che è la stessa classe di quella fornita con Python.
Acumenus,

3
CRONACA - pd.read_table()è una funzione equivalente, appena un po 'meglio nomenclatura: df = pd.read_table(TESTDATA, sep=";").
wkzhu,

5
@AntonvBR Notato che si potrebbe usare pandas.compat.StringIO. In questo modo non è necessario importare StringIOseparatamente. Tuttavia, il pandas.compatpacchetto è considerato privato in base a pandas.pydata.org/pandas-docs/stable/api.html?highlight=compat , lasciando quindi la risposta per ora.
Emil H,


Se si crea TESTDATA con df.to_csv(TESTDATA), utilizzareTESTDATA.seek(0)
user3226167

18

Metodo diviso

data = input_string
df = pd.DataFrame([x.split(';') for x in data.split('\n')])
print(df)

2
Se si desidera utilizzare la prima riga per i nomi delle colonne, modificare la seconda riga in questo:df = pd.DataFrame([x.split(';') for x in data.split('\n')[1:]], columns=[x for x in data.split('\n')[0].split(';')])
Mabyn,

1
Questo è sbagliato, poiché sui file CSV il carattere newline (\ n) può far parte di un campo.
Antonio Ercole De Luca,

Questo non è molto robusto e la maggior parte delle persone starebbe meglio con la risposta accettata. C'è un elenco molto parziale di cose che possono andare storto con questo su thomasburette.com/blog/2014/05/25/…
DanB

10

Una soluzione rapida e semplice per il lavoro interattivo è copiare e incollare il testo caricando i dati dagli Appunti.

Seleziona il contenuto della stringa con il mouse:

Copia i dati per incollarli in un frame di dati Pandas

Nella shell di Python usare 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

Utilizzare il separatore appropriato:

>>> 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

2
Non va bene per la riproducibilità, ma per il resto una soluzione abbastanza accurata!
Mabyn,

5

Questa risposta si applica quando una stringa viene inserita manualmente, non quando viene letta da qualche parte.

Un CSV tradizionale a larghezza variabile è illeggibile per l'archiviazione dei dati come variabile stringa. Soprattutto per l'uso all'interno di un .pyfile, considerare invece i dati separati da pipe a larghezza fissa. Vari IDE ed editor possono avere un plug-in per formattare il testo separato da pipe in una tabella ordinata.

utilizzando read_csv

Conservare quanto segue in un modulo di utilità, ad es util/pandas.py. Un esempio è incluso nel docstring della funzione.

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)

Alternative non funzionanti

Il codice seguente non funziona correttamente perché aggiunge una colonna vuota su entrambi i lati sinistro e destro.

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

Per quanto riguarda read_fwf, in realtà non utilizza così tanti dei kwarg opzionali che read_csvaccetta e utilizza. Pertanto, non dovrebbe essere utilizzato affatto per i dati separati da pipe.


1
Ho scoperto (per tentativi ed errori) che read_fwfaccetta più read_csvargomenti di quanti siano documentati, ma è vero che alcuni non hanno alcun effetto .
Gerrit,

-4

Il modo più semplice è salvarlo nel file temporaneo e quindi leggerlo:

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=';')

Modo giusto di creare un file temporaneo: come posso creare un file tmp in Python?


cosa succede se non esiste l'autorizzazione per creare il file?
BingLi224

Secondo me non è più il caso più semplice. Si noti che "più semplice" è esplicitamente indicato nella domanda.
QtRoS
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.