从字符串创建Pandas DataFrame

481
为了测试一些功能,我想从一个字符串创建一个 DataFrame。假设我的测试数据如下:
TESTDATA="""col1;col2;col3
1;4.4;99
2;4.5;200
3;4.7;65
4;3.2;140
"""

什么是将数据读入Pandas DataFrame的最简单方法?
7个回答

807

一种简单的方法是使用StringIO.StringIO(Python 2)io.StringIO(Python 3)将内容传递给pandas.read_csv函数。例如:

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

4
FYI - pd.read_table() 是一个等价的函数,只是命名略有改进:df = pd.read_table(TESTDATA, sep=";") - wkzhu
10
注意到可以使用 pandas.compat.StringIO。这样我们就不需要单独导入 StringIO 了。然而根据http://pandas.pydata.org/pandas-docs/stable/api.html?highlight=compat, pandas.compat 包被认为是私有的,所以现在保留原始答案。 - Emil L
这是我在Colab上传CSV文件时需要做的事情。为了将CSV转换为数据框,我使用了这种方法。 - Joshua Swain
@gdm,“预期字段错误”通常是由于每行中字段数量不一致或分隔符/定界符错误引起的。 - skytaker
1
@Asclepius 建议使用 pandas.compat 的方式仅适用于 pandas 0.25 之前的版本,但现在会引发 ImportError 错误。 - Mike T
显示剩余3条评论

58

分割方法

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

8
如果您希望第一行用作列名,请将第二行更改为:df = pd.DataFrame([x.split(';') for x in data.split('\n')[1:]], columns=[x for x in data.split('\n')[0].split(';')]) - Mabyn
4
这是错误的,因为在 CSV 文件中换行符(\n)可以是字段的一部分。 - Antonio Ercole De Luca
4
这并不是非常健壮的解决方案,许多人最好还是采用被认可的答案。你可以在http://thomasburette.com/blog/2014/05/25/so-you-want-to-write-your-own-CSV-code/这个网址上找到一份可能出现问题的简短列表。 - DanB
1
这是一种薄弱且不必要的方法。这种方法绕过了内置的pd.read_csv()调用,该调用处理任何CSV并经过了实战测试,而采用了一些天真的字符串拆分,这些拆分不能处理引用,并且在许多情况下容易失败。此外,它还更加冗长。请使用Pandas提供的CSV解析器! - ggorlen

56

一行代码实现,但是首先要导入io

import pandas as pd
import io   

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

df = pd.read_csv(io.StringIO(TESTDATA), sep=";")
print(df)

12
这个答案和已接受的答案有什么不同?除了您将IO操作移动到read_csv中,这并没有任何区别...请始终检查是否已经发布了类似的答案,冗余是不必要的。 - Ruli
6
我喜欢这个答案,因为它用一行中的一个例子进行了解释。 - eduardosufan

26

一种快速且简单的交互式工作解决方案是通过从剪贴板加载数据来复制和粘贴文本。

使用鼠标选择字符串的内容:

将数据复制到 Pandas 数据帧中以进行粘贴

在 Python shell 中使用 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

使用适当的分隔符:

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

12
不利于可重现性,但其他方面是相当不错的解决方案! - Mabyn

9
这个答案适用于手动输入字符串的情况,而不是从其他地方读取字符串的情况。
传统的变宽CSV对于将数据存储为字符串变量来说是不可读的。特别是在.py文件中使用时,应考虑使用固定宽度的管道分隔数据。各种IDE和编辑器可能有插件,可以将管道分隔文本格式化为整齐的表格。
使用read_csv
将以下内容存储在实用程序模块中,例如util/pandas.py。函数的docstring中包含了一个示例。
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://dev59.com/aGEh5IYBdhLWcg3wRRqh#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)

无法使用的替代方法

以下代码无法正常工作,因为它在左右两侧都添加了空列。

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

关于read_fwf,它实际上并没有使用read_csv接受和使用的那么多可选的kwargs。因此,在处理管道分隔数据时不应使用它。

1
我发现(通过试错)read_fwf比文档中记录的要使用更多read_csv的参数,但确实有一些参数是没有效果的。参考链接 - gerrit

4
目标:将字符串转换为数据框。
解决方案:
def str2frame(estr, sep = ',', lineterm = '\n', set_header = True):
    dat = [x.split(sep) for x in estr.strip(lineterm).split(lineterm)]
    df = pd.DataFrame(dat)
    if set_header:
        df = df.T.set_index(0, drop = True).T # flip, set ix, flip back
    return df

例子

estr = """
sym,date,strike,genus
APPLE,20MAY20,50.0,Malus
ORANGE,22JUL20,50.0,Rutaceae
"""

df = str2frame(estr)


print(df)
0     sym     date strike     genus
1   APPLE  20MAY20   50.0     Malus
2  ORANGE  22JUL20   50.0  Rutaceae

请使用描述性的变量名称,而不是estr,dat,cdf。 - problemofficer - n.f. Monica
风格是有意的;随意复制此答案并使用您自己的符号。 - Hunaphu
请不要重复造轮子,直接使用 pd.read_csv() - ggorlen
如果您有更好的仅依赖于pandas的解决方案,将不胜感激。 - Hunaphu

0

示例:

text = [ ['This is the NLP TASKS ARTICLE written by Anjum**'] ,['IN this article I”ll be explaining various DATA-CLEANING techniques '], ['So stay tuned for FURther More && '],['Nah I dont think he goes to usf ; he lives around']]
df = pd.DataFrame({'text':text})

输出 在此输入图像描述


这与问题无关。OP想要从字符串中读取CSV,这里完全没有提到。 - ggorlen
@ggorlen。首先看问题:“从字符串创建Pandas DataFrame”,然后再看我的答案。哈哈 - Engr. Khuram Shahzad
抱歉,我已经这样做了,但不明白你的意思。你的回答中没有CSV字符串。你已经硬编码了一个列表,完全绕过了所有其他答案中涉及的转换步骤。这个问题与将列表转换为数据框无关。即使你要硬编码列表,这也是一个糟糕的解决方案,因为它在每个字符串上添加了额外的单元素内部列表包装器,没有明显的原因,使得“text”列成为对象而不是字符串数据类型。 - ggorlen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接