Python pandas:逐行填充数据框

182

pandas.DataFrame 对象上添加一行的简单任务似乎很难完成。有三个与此相关的stackoverflow问题,但没有一个给出有效的答案。

我正在尝试的是:我有一个 DataFrame,我已经知道它的形状以及行和列的名称。

>>> df = pandas.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])
>>> df
     a    b    c    d
x  NaN  NaN  NaN  NaN
y  NaN  NaN  NaN  NaN
z  NaN  NaN  NaN  NaN

现在,我有一个用于迭代计算行值的函数。如何使用字典或pandas.Series填充其中一行?以下是若干次失败的尝试:

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df['y'] = y
AssertionError: Length of values does not match length of index

显然,它试图添加一列而不是一行。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.join(y)
AttributeError: 'builtin_function_or_method' object has no attribute 'is_unique'

非常没有信息量的错误消息。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.set_value(index='y', value=y)
TypeError: set_value() takes exactly 4 arguments (3 given)

显然,这只适用于在数据框中单独设置数值。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.append(y)
Exception: Can only append a Series if ignore_index=True

好的,我不想忽略索引,否则这是结果:

>>> df.append(y, ignore_index=True)
     a    b    c    d
0  NaN  NaN  NaN  NaN
1  NaN  NaN  NaN  NaN
2  NaN  NaN  NaN  NaN
3    1    5    2    3

虽然它已经将列名与值对齐,但丢失了行标签。

>>> y = {'a':1, 'b':5, 'c':2, 'd':3} 
>>> df.ix['y'] = y
>>> df
                                  a                                 b  \
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

                                  c                                 d
x                               NaN                               NaN
y  {'a': 1, 'c': 2, 'b': 5, 'd': 3}  {'a': 1, 'c': 2, 'b': 5, 'd': 3}
z                               NaN                               NaN

那次尝试也惨遭失败。

那么你该怎么做呢?


2
请注意,逐行添加数据对于大量数据来说效率非常低下。相反,最好先将数据加载到一个列表中,然后使用df = pd.DataFrame(data, columns=header)一行代码构建DataFrame,这样速度会更快。 - Timothy C. Quinn
1
为什么在列表中创建数据集,然后将整个数据集似乎复制到内存中作为DataFrame更有效率?这在内存使用方面听起来非常低效 - 并且对于非常大的数据集可能会成为问题。 - Demis
@xApple,我认为你遇到了我曾经遇到的同样问题(持续了好几天),那就是我不理解列和索引之间的区别 - 我一直在以数组的方式思考,其中这些基本上可以是行/列或反之亦然,没有区别。我完全同意你的观点,即数据框架的基本理论如何使用以及如何逐行生成DF(从另一个源读取数据时典型的情况)是非常不清楚的! - Demis
5个回答

131

df['y'] 将设置一列

如果你想设置一行,请使用.loc

注意,.ix 在这里是等价的,但你的操作失败了,因为你试图将一个字典分配给行中每个元素的y,这可能不是你想要的。转换为序列会告诉 pandas 你想要对齐输入(例如,然后你不必指定所有的元素)

In [6]: import pandas as pd

In [7]: df = pd.DataFrame(columns=['a','b','c','d'], index=['x','y','z'])

In [8]: df.loc['y'] = pd.Series({'a':1, 'b':5, 'c':2, 'd':3})

In [9]: df
Out[9]: 
     a    b    c    d
x  NaN  NaN  NaN  NaN
y    1    5    2    3
z  NaN  NaN  NaN  NaN

我理解了。因此,数据框的loc属性定义了一个特殊的__setitem__,可以执行所需的操作。 - xApple
5
如果我可以逐行生成数据,那么我应该如何最优地构建数据框? - xApple
2
@xApple 最好构建一个字典列表(或列表),然后将其传递给构造函数,这样会更高效。 - Jeff
@Jeff,如果你没有看到我的回复,那么TOTD的评论也很好笑。 :) - Andy Hayden
2
@amc 是的,你也可以这样做 df = pandas.DataFrame(columns=['a', 'b', 'c', 'd']); df.loc['y'] = [1, 5, 2, 3] - Max Ghenis
显示剩余6条评论

105

更新:由于append已被弃用

df = pd.DataFrame(columns=["firstname", "lastname"])

entry = pd.DataFrame.from_dict({
     "firstname": ["John"],
     "lastname":  ["Johny"]
})

df = pd.concat([df, entry], ignore_index=True)

7
这对我非常有效,我喜欢你明确地将数据“append”到数据框中的做法。 - Jonny Brooks
2
请注意,此答案需要在每一行后附加列名。对于被接受的答案也是如此。 - pashute
1
如果您事先不知道行数,这也适用。 - irene
3
如果逐行构建而且数据集较大,即使使用 ignore_index=True,最好的方法是将数据加载到一个列表中,然后使用 df = pd.DataFrame(data, columns=header) 在一行中构建DataFrame。似乎无论如何 Pandas 在追加行时都进行了一些重要的操作来处理索引。 - Timothy C. Quinn
1
不要使用append,而应该使用concat,具体信息请查看:https://pandas.pydata.org/docs/whatsnew/v1.4.0.html#whatsnew-140-deprecations-frame-series-append - galath
显示剩余2条评论

49

这是一个更简单的版本

import pandas as pd
df = pd.DataFrame(columns=('col1', 'col2', 'col3'))
for i in range(5):
   df.loc[i] = ['<some value for first>','<some value for second>','<some value for third>']`

6
请问,这个CPU和内存使用效率高吗? - czxttkl
2
我怎么知道df的最后一行,以便每次将数据追加到最后一行? - pashute
append() 的另外两个选项相比(可能在每次循环迭代时重复整个数据库(因为您将其重新分配给自己)),以及创建两个相同数据结构(一个 List,然后是一个 DataFrame)的常见选项相比,这种方法在内存使用方面似乎更加“高效”,但速度可能是另一个问题。 - Demis
也许你可以执行 df.loc[-1] - Demis
您可以使用以下代码将数据添加到DataFrame的末尾:df.loc[len(df)] = ["我的", "新", "数据"] - Demis

41

如果你的输入行是列表而不是字典,那么以下是一个简单的解决方案:

import pandas as pd
list_of_lists = []
list_of_lists.append([1,2,3])
list_of_lists.append([4,5,6])

pd.DataFrame(list_of_lists, columns=['A', 'B', 'C'])
#    A  B  C
# 0  1  2  3
# 1  4  5  6

但是如果我有一个多索引怎么办?df1 = pd.DataFrame(list_of_lists, columns['A', 'B', 'C'], index=['A', 'B']) 是不起作用的。形状错误。那该怎么办? - pashute

2
代码背后的逻辑非常简单和直接。
使用字典创建一个包含1行的df。
然后创建一个形状为(1, 4)的仅包含NaN的df,并具有与字典键相同的列。
然后将一个nan df与dict df连接起来,再连接另一个nan df。
import pandas as pd
import numpy as np

raw_datav = {'a':1, 'b':5, 'c':2, 'd':3} 

datav_df = pd.DataFrame(raw_datav, index=[0])

nan_df = pd.DataFrame([[np.nan]*4], columns=raw_datav.keys())

df = pd.concat([nan_df, datav_df, nan_df], ignore_index=True)

df.index = ["x", "y", "z"]

print(df)

提供

a    b    c    d
x  NaN  NaN  NaN  NaN
y  1.0  5.0  2.0  3.0
z  NaN  NaN  NaN  NaN

[Program finished]

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