从变量中的值构建pandas DataFrame会出现"ValueError: If using all scalar values, you must pass an index"的错误。

789

这可能是一个简单的问题,但是我无法弄清楚如何做到这一点。假设我有两个变量如下。

a = 2
b = 3

我想从这个构建一个DataFrame:

df2 = pd.DataFrame({'A':a,'B':b})

这会产生一个错误:

ValueError:如果使用所有标量值,必须传递索引

我也尝试了这个:

df2 = (pd.DataFrame({'a':a,'b':b})).reset_index()

这会给出相同的错误信息。


2
我有什么遗漏吗?难道不是微不足道的事情,没有.foo()就可以解决错误,因为异常是在评估DataFrame构造函数时产生的吗? - Lucas Alonso
24个回答

1162
错误信息表示如果您传递的是标量值,则必须传递索引。因此,您可以选择不使用标量值作为列 - 例如使用列表:
>>> df = pd.DataFrame({'A': [a], 'B': [b]})
>>> df
   A  B
0  2  3

或者使用标量值并传递索引:

>>> df = pd.DataFrame({'A': a, 'B': b}, index=[0])
>>> df
   A  B
0  2  3

16
可能是因为 Python 中列表中的项目顺序是持久的,而字典中的项目顺序不是。您可以使用空字典实例化 DataFrame。原则上,我认为像这里显示的单行 DataFrame 也可以从字典构建,因为顺序无关紧要(但这还没有实现)。然而,在多行情况下,Pandas 将无法创建 DataFrame,因为它不知道哪些项目属于同一行。 - Alexander
5
在这种情况下,数据帧行(由给定的字典表示)没有索引(甚至没有隐式索引)。一个简单的解决方案是将字典包装在列表中,这样就会有“自然索引”。有人可能会说,如果只给出一个字典(没有包装列表),则假设index=0,但这可能会导致意外的误用(认为单个字典可以创建多行数据帧)。 - Ori
此链接中有几种解决方案 https://eulertech.wordpress.com/2017/11/28/pandas-valueerror-if-using-all-scalar-values-you-must-pass-an-index/ - Jason Goal
2
这是因为DataFrames旨在保存二维数据(即OP的两个变量的行)。如果您想简单地保存索引->值对(如字典),那么应该像Rob所建议的那样使用Series。 - danuker
为什么这个答案在底部?我以为 Stack Overflow 有一个机制可以将更好的答案移到顶部! - Malik A. Rumi
显示剩余2条评论

233
您可以尝试将您的字典包装到列表中:
my_dict = {'A':1,'B':2}
pd.DataFrame([my_dict])
   A  B
0  1  2

2
只需像@NewBie提到的那样将字典放在方括号[ ]中,即可适用于包含多种数据类型的大型字典。由于需要对所有标量值执行此操作,因此所接受的答案并不是很快,感谢! - Elias
6
哈利路亚,这应该是最好的答案 - 方便至关重要。 - Brndn
2
我更喜欢这个答案,简单而清晰。 - ichthyophile
这很棒。在大多数实际情况下,添加.transpose()非常有用,可以将宽表转换为长表,即pd.DataFrame([my_dict]).transpose() - mellifluous

110

如果您已经有了字典,您也可以使用pd.DataFrame.from_records,这将更加方便:

df = pd.DataFrame.from_records([{ 'A':a,'B':b }])

如果需要,您还可以通过以下方式设置索引:

df = pd.DataFrame.from_records([{ 'A':a,'B':b }], index='A')

1
@DaveKielpinski 请检查是否将列表传递给“from_records”方法;否则它将无法工作,并且您将收到与在字典上调用DataFrame时相同的错误消息。 - mairan
和 @DaveKielpinski 一样的问题,直到我意识到我在单个文档上使用了 from_records,而不是在这些文档的数组上使用。只是发帖提醒你要仔细检查是否做对了。 - Voy
@mingchau:这是标准行为,所以与手头的问题无关。 - user1071847

84

您需要首先创建一个 Pandas Series。第二步是将 Pandas Series 转换为 Pandas DataFrame。

import pandas as pd
data = {'a': 1, 'b': 2}
pd.Series(data).to_frame()

您甚至可以提供列名称。

pd.Series(data).to_frame('ColumnName')

1
这对我有用。我的字典具有整数键和ndarray值。 - StatsSorceress
3
pd.Series(data).to_frame('ColumnName') 可以更简洁地表达,但这个等同形式也可以更直接地表示:pd.DataFrame.from_dict(data, orient='index', columns=['ColumnName']) - Alex F
这对我来说也有效,与@StatsSorceress相同的情况下。 - muammar
这不会创建与要求相同的结构。使用这种方法,我得到了一个具有1列和2行(A和B)的数据框,但结果应该是一个具有1行和2列(A和B)的数据框。 - shlomiLan
@shlomiLan 这就是我想要的结构,也是我根据问题推断出 OP 所寻找的。尽管他们接受了只有一行的答案,这表明情况并非如此... - nealmcb

17

也许 Series 能够提供您所需的所有功能:

pd.Series({'A':a,'B':b})

DataFrame 可以被视为一个 Series 的集合,因此你可以:

  • 将多个 Series 连接成一个数据框(如 这里 所描述的)

  • 将一个 Series 变量添加到现有的数据框中(示例 在这里


这是最佳答案 - 然后将系列重新分配回列(例如,在使用 df.apply() 时)。 - jtlz2

14

熊猫(Pandas)的神奇之处正在发挥作用,所有逻辑都被抛在了脑后。

错误信息"ValueError: If using all scalar values, you must pass an index" 指出您必须传递一个索引。

这并不一定意味着传递一个索引会使熊猫(Pandas)做你想让它做的事情

当您传递一个索引时,熊猫(Pandas)会将您的字典键视为列名,将值视为每个索引中应包含的列的内容。

a = 2
b = 3
df2 = pd.DataFrame({'A':a,'B':b}, index=[1])

    A   B
1   2   3

传递更大的索引:

df2 = pd.DataFrame({'A':a,'B':b}, index=[1, 2, 3, 4])

    A   B
1   2   3
2   2   3
3   2   3
4   2   3

如果未指定,则数据帧通常会自动生成索引。但是,pandas不知道您需要多少行的23。不过,您可以更明确地指定。

df2 = pd.DataFrame({'A':[a]*4,'B':[b]*4})
df2

    A   B
0   2   3
1   2   3
2   2   3
3   2   3

默认的索引是基于0的。

我建议在创建数据框时,始终向数据框构造函数传递一个列表字典。这对其他开发人员更易于阅读。Pandas有很多注意事项,请不要让其他开发人员成为所有问题的专家才能阅读您的代码。


这个解释是我一直在寻找的。 - Anshuman Jayaprakash

12

我通常使用以下代码从字典快速创建一个小表格。

假设你有一个字典,其中键是文件名,值是相应的文件大小,你可以使用以下代码将其放入DataFrame中(注意在字典上调用 .items()):

files = {'A.txt':12, 'B.txt':34, 'C.txt':56, 'D.txt':78}
filesFrame = pd.DataFrame(files.items(), columns=['filename','size'])
print(filesFrame)

  filename  size
0    A.txt    12
1    B.txt    34
2    C.txt    56
3    D.txt    78

1
这很有帮助,但请注意它不适用于pandas 0.23.4。 - for_all_intensive_purposes
对我来说,这很完美!只需在字典中有两行数据,将其转换为数据框应该不难。 - Michel K
谢谢,正是我所寻找的。 - yondchang

11

你可以尝试:

df2 = pd.DataFrame.from_dict({'a':a,'b':b}, orient = 'index')

从“orient”参数的文档中可以看到:如果传递的字典的键应该是生成的DataFrame的列,则传递“columns”(默认)。否则,如果键应该是行,则传递“index”。


1
这并没有解决所提出的问题,它产生了与期望不同的结果。 - Ken Williams
@KenWilliams 我有点困惑。看起来这个提供了我认为原帖作者想要的结果,或者你认为原帖作者想要的结果(以及MLguy认为原帖作者想要的结果)。因此,它是所有答案中最灵活的,而且得票数也很高。 - nealmcb
1
@nealmcb 确实是回答者所声称的,但是当使用 orient='columns' 时,它只会给出与原始问题相同的 如果使用所有标量值,则必须传递索引 错误。我应该在我的评论中澄清这一点。 - Ken Williams

10
为了解决"ValueError",需要理解DataFrame和标量值。
从字典创建DataFrame时,至少需要一个数组。
在我看来,数组本身是有索引的。因此,如果存在类似于数组的值,则不需要指定索引。
例如,['a', 's', 'd', 'f']中每个元素的索引分别为0,1,2,3。
df_array_like = pd.DataFrame({
    'col' : 10086,
    'col_2' : True,
    'col_3' : "'at least one array'",
    'col_4' : ['one array is arbitrary length', 'multi arrays should be the same length']}) 
print("df_array_like: \n", df_array_like)

输出:

df_array_like: 
      col  col_2                 col_3                                   col_4
0  10086   True  'at least one array'           one array is arbitrary length
1  10086   True  'at least one array'  multi arrays should be the same length

如输出所示,DataFrame的索引为0和1。
恰好与数组['一个任意长度的数组','多个数组应该具有相同的长度']的索引相同。
如果注释掉“col_4”,将引发以下错误:

ValueError("If using all scalar values, you must pass an index")

原因是标量值(整数、布尔值和字符串)没有索引。
请注意,Index(...)必须使用某种集合进行调用。
由于索引用于定位DataFrame的所有行,因此索引应该是一个数组。例如:
df_scalar_value = pd.DataFrame({
'col' : 10086,
'col_2' : True,
'col_3' : "'at least one array'"
}, index = ['fst_row','snd_row','third_row']) 
print("df_scalar_value: \n", df_scalar_value)

输出:

df_scalar_value: 
              col  col_2                 col_3
fst_row    10086   True  'at least one array'
snd_row    10086   True  'at least one array'
third_row  10086   True  'at least one array'

我是一名初学者,正在学习Python和英语。


10
您需要提供可迭代的对象作为Pandas DataFrame列的值:
df2 = pd.DataFrame({'A':[a],'B':[b]})

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