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

时间:2014-04-16 14:12:56

标签: python string list pandas dataframe

我有一个 n -by- m Pandas DataFrame df定义如下。 (我知道这不是最好的方法。对于我在实际代码中尝试做的事情,这是有意义的,但这个帖子的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. 如果没有,那么有没有Pythonic方式将此字符串转换为列表?

  3. 更新

    我使用的DataFrame已经保存并从CSV格式加载。 此格式(而不是DataFrame本身)将列表从字符串转换为文字。

9 个答案:

答案 0 :(得分:40)

正如您所指出的,将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 :(得分:4)

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

答案 2 :(得分: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)将此字符串转换为列表的Pythonic方法。 (这可能是你想要的,因为你正在使用的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]

答案 3 :(得分:1)

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

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'

答案 4 :(得分:1)

我遇到了同样的问题。使用df.to_csv()将数据帧列表列存储到CSV文件时,列表列将转换为字符串,例如&#34; [42,42,42]&#34;而不是[42,42,42]

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

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

O用于Python对象,包括列表。更多信息here。请注意,如果您解析空列表字符串,此方法将失败:&#34; []&#34;

或者你也可以在你的专栏中应用一个函数(这个是整数):

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

答案 5 :(得分: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)

答案 6 :(得分:0)

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

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

答案 7 :(得分: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])

答案 8 :(得分:0)

添加到Alex's答案中。这是另一个版本,可用于将单个项目从字符串转换为列表

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