我有一个 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]'
我有两个问题要问你。
更新
我使用的DataFrame已经保存并从CSV格式加载。 此格式(而不是DataFrame本身)将列表从字符串转换为文字。
答案 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)
ast.literal_eval
安全地评估包含Python文字或容器显示的字符串。
它是标准库的一部分
Using python's eval() vs. ast.literal_eval()?解释了为什么literal_eval
比使用eval
更安全。
示例:
literal_eval("[1.23, 2.34]")
有效literal_eval("['KB4523205','KB4519569','KB4503308']")
有效literal_eval("[KB4523205, KB4519569, KB4503308]")
不起作用(str
值周围没有引号)
pandas.read_csv
的converters
参数在读取文件时转换列。test.csv
中的数据col1
"[1.23, 2.34]"
"['KB4523205','KB4519569','KB4503308']"
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))