Pandas DataFrame将列表存储为字符串:如何转换回列表?


74

我有一个n × m的Pandas DataFramedf定义如下。(我知道这不是最好的方法。这对于我在实际代码中尝试做的事情是有道理的,但这将是本文的TMI,所以请相信我,这种方法可以在我的特定情况下使用)

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

我将列表存储在此DataFrame的单元格中,如下所示。

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

由于某种原因,DataFrame将此列表存储为字符串而不是列表。

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

我有两个问题要问你。

  1. 为什么DataFrame将列表存储为字符串,并且有解决此问题的方法?
  2. 如果没有,那么是否有Python方式将这个字符串转换为列表?

更新资料

我正在使用的DataFrame已保存并从CSV格式加载。这种格式而不是DataFrame本身将列表从字符串转换为文字。


这回答了你的问题了吗?将列表的字符串表示形式转换为列表
AMC

Answers:


89

正如您所指出的那样,在将pandas DataFrames保存和加载为.csv文件时,通常会发生这种情况,这是一种文本格式。

在您的情况下,发生这种情况是因为列表对象具有字符串表示形式,从而允许将它们存储为.csv文件。.csv然后加载将产生该字符串表示形式。

如果要存储实际对象,则应使用DataFrame.to_pickle()(注意:对象必须是可腌制的!)。

要回答第二个问题,您可以使用转换回ast.literal_eval

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

1
熊猫数据帧支持存储任何对象对象,因此这应该可以工作
EdChum 2014年

3
@EdChum显然不是,因为我在版本0.17.1中list转换为stringwith,to_csv随后是from_csv
詹姆斯·希尔斯霍恩

尽管这是正确的答案,但我更喜欢下面的@markroxor解决方案,该解决方案在导入时直接使用熊猫来解决此问题,而无需加载其他外部库。
渴求知识

32

您可以直接使用熊猫-
df = pd.read_csv(df_name, converters={'column_name': eval})

这将在python中将该列读为它的对应dtype而不是字符串。


4
我一直在搜索,这就是我一直在寻找的东西。谢谢。
AlanPear

2
我有同样的问题,这个答案解决了原因而不是症状,这就是我投赞成票的原因
AHR

2
这是正确的答案,因为它避免了导入另一个库。
知识的渴求

8

我刚遇到这个问题,有一个非常简单的解决方案(pandas.eval())。我正在使用熊猫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'])

3

1)有一种解决方法。在这里使用loc帮助。

>>> 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)用Python方式将此字符串转换为列表。(这可能是您想要的,因为正在使用的DataFrame已从CSV格式保存和加载,对此有几种解决方案)。这是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]

2
注意,您不需要使用lambda函数。该apply方法将在您传递的函数中使用每一行的输入.apply(literal_eval)。只需编写。将lambda保留用于更复杂的逻辑。
凯文·格林

df.list = df.list.apply(literal_eval)
特伦顿·麦金尼

2

我有同样的问题。使用df.to_csv()将数据框列表列存储到CSV文件时,列表列将转换为字符串,例如“ [42、42、42]”而不是[42、42、42]

亚历克斯答案是正确的,您可以literal_eval用来将字符串转换回列表。这种方法的问题在于,您需要导入其他库,并且需要将函数应用或映射到数据框。更为简单的方法是强制Pandas将列作为Python对象(dtype)读取

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

O用于包含列表的Python对象。更多信息在这里。请注意,如果您分析空列表字符串,则此方法将失败:“ []”

另外,您也可以将函数应用于列(此函数用于整数):

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

仅供参考...大熊猫不会将列表转换为字符串。..

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'

2
正如我所发现的,有时熊猫会将列表转换为字符串。它必须与我定义此DataFrame或向其中插入数据的方式有关。很高兴知道以供将来参考。
Gyan Veda 2014年

我无法重新创建此问题
user1827356

@ user1827356,我知道了!我现在要编辑我的问题。
Gyan Veda 2014年

1

数据输入 test.csv

col1
"[1.23, 2.34]"
"['KB4523205','KB4519569','KB4503308']"

创建csv时转换列

from ast import literal_eval
import pandas as pd

# convert the column during import
df = pd.read_csv('test.csv', converters={'col1': literal_eval})

# display(df)
                                col1
0                       [1.23, 2.34]
1  [KB4523205, KB4519569, KB4503308]

# check type
print(type(df.iloc[0, 0]))
list

print(type(df.iloc[1, 0]))
list

转换现有数据框的列

df.col1 = df.col1.apply(literal_eval)

0

我使用的一个简单技巧是调用一个lambda函数,该函数索引出第一个和最后一个元素(str形式的列表括号),并调用split方法,然后调用另一个方法,该方法用int替换列表元素。

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

0

添加到亚历克斯的答案。这是另一个版本,可用于将单个项目从字符串转换为列表

import pandas as pd
from ast import literal_eval

df = pd.read_csv("some_csvfile.csv")

def item_gen(l):
    for i in l:
        yield(i)

for i in item_gen(df["some_column_with_list_item"]):
    print(literal_eval(i))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.