Buat Pandas DataFrame dari string

276

Untuk menguji beberapa fungsionalitas, saya ingin membuatnya DataFramedari string. Katakanlah data pengujian saya terlihat seperti:

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

Apa cara paling sederhana untuk membaca data itu menjadi Panda DataFrame?

Emil H
sumber

Jawaban:

498

Cara sederhana untuk melakukan ini adalah dengan menggunakan StringIO.StringIO(python2) atau io.StringIO(python3) dan meneruskannya ke pandas.read_csvfungsi. Misalnya:

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
sumber
7
Jika Anda memerlukan kode yang kompatibel dengan Python 2 dan 3, Anda juga dapat menggunakan from pandas.compat import StringIO, mencatat bahwa itu adalah kelas yang sama dengan yang ada pada Python.
Acumenus
3
FYI - pd.read_table()adalah fungsi setara, hanya sedikit lebih baik nomenklatur: df = pd.read_table(TESTDATA, sep=";").
wkzhu
5
@AntonvBR Mencatat bahwa orang dapat menggunakan pandas.compat.StringIO. Dengan begitu kita tidak perlu mengimpor StringIOsecara terpisah. Namun pandas.compatpaket tersebut dianggap pribadi menurut pandas.pydata.org/pandas-docs/stable/api.html?highlight=compat sehingga meninggalkan jawaban seperti sekarang.
Emil H
Jika Anda membuat TESTDATA dengan df.to_csv(TESTDATA), gunakanTESTDATA.seek(0)
user3226167
18

Metode Split

data = input_string
df = pd.DataFrame([x.split(';') for x in data.split('\n')])
print(df)
shaurya uppal
sumber
2
Jika Anda ingin baris pertama digunakan untuk nama kolom, ubah baris ke-2 ini:df = pd.DataFrame([x.split(';') for x in data.split('\n')[1:]], columns=[x for x in data.split('\n')[0].split(';')])
Mabyn
1
Ini salah, karena pada file CSV karakter baris baru (\ n) dapat menjadi bagian dari bidang.
Antonio Ercole De Luca
Ini tidak terlalu kuat, dan kebanyakan orang akan lebih baik dengan jawaban yang diterima. Ada sebagian daftar hal yang bisa salah dengan ini di thomasburette.com/blog/2014/05/25/…
DanB
10

Solusi cepat dan mudah untuk pekerjaan interaktif adalah menyalin dan menempelkan teks dengan memuat data dari clipboard.

Pilih konten string dengan mouse Anda:

Salin data untuk menempel ke bingkai data Pandas

Dalam penggunaan shell Python 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

Gunakan pemisah yang sesuai:

>>> 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
pengguna2314737
sumber
2
Tidak bagus untuk reproduksibilitas, tetapi sebaliknya solusi yang cukup rapi!
Mabyn
5

Jawaban ini berlaku ketika string dimasukkan secara manual, bukan ketika itu dibaca dari suatu tempat.

CSV lebar variabel tradisional tidak dapat dibaca untuk menyimpan data sebagai variabel string. Khusus untuk digunakan di dalam .pyfile, pertimbangkan data yang dipisahkan dengan pipa dengan lebar tetap. Berbagai IDE dan editor mungkin memiliki plugin untuk memformat teks yang dipisahkan pipa menjadi tabel yang rapi.

Menggunakan read_csv

Simpan yang berikut dalam modul utilitas, mis util/pandas.py. Contoh disertakan dalam dokumentasi fungsi.

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)

Alternatif tidak bekerja

Kode di bawah ini tidak berfungsi dengan baik karena menambahkan kolom kosong di sisi kiri dan kanan.

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

Adapun read_fwf, itu tidak benar-benar menggunakan begitu banyak kwarg opsional yang read_csvmenerima dan menggunakan. Karena itu, tidak boleh digunakan sama sekali untuk data yang dipisahkan oleh pipa.

Acumenus
sumber
1
Saya menemukan (melalui percobaan & kesalahan) yang read_fwfmembutuhkan lebih banyak read_csvargumen daripada yang didokumentasikan, tetapi memang benar bahwa beberapa tidak memiliki efek .
gerrit
-4

Cara paling sederhana adalah menyimpannya ke file temp dan kemudian membacanya:

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

Cara yang benar untuk membuat file temp: Bagaimana saya bisa membuat file tmp dengan Python?

QtRoS
sumber
bagaimana jika tidak ada izin untuk membuat file?
BingLi224
Menurut saya itu bukan kasus yang paling sederhana lagi. Perhatikan bahwa "paling sederhana" dinyatakan secara eksplisit dalam pertanyaan.
QtRoS