Python pandas:逐行填充数据框

Posted

技术标签:

【中文标题】Python pandas:逐行填充数据框【英文标题】:Python pandas: fill a dataframe row by row 【发布时间】:2013-06-10 02:47:10 【问题描述】:

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

这就是我想要做的。我有一个 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

那也惨败了。

那么你是怎么做到的呢?

【问题讨论】:

请注意,逐行添加数据和大型数据集的效率非常低。相反,首先将数据加载到列表列表中,然后使用 df = pd.DataFrame(data, columns=header) 在一行中构造 DataFrame 会快得多 为什么在 Lists 中创建数据集效率更高,并且看似将内存中的整个数据集复制为 DataFrame?这在内存使用方面听起来非常低效 - 对于非常庞大的数据集来说可能是一个问题。 @xApple,我想你遇到了同样的问题(好几天),我不明白 Columns 和 Index 之间的区别 - 我在考虑数组,这些可以基本上是 row/col 或反之亦然,没有区别。我完全同意你的观点,关于如何使用数据帧以及如何逐行生成 DF(从其他来源读取数据时很典型)的基本理论非常不清楚! 【参考方案1】:

df['y'] 会设置一列

既然要设置一行,就用.loc

注意 .ix 在这里是等价的,你的失败是因为你试图分配一个字典 到行y 的每个元素可能不是您想要的;转换为系列告诉熊猫 您想要对齐输入(例如,您不必指定所有元素)

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__,它可以发挥我的作用。 你能一次性构造它吗(即使用列、索引和 y)? 那么如果我可以一次生成一行,我将如何优化构建数据框? @xApple prob 最适合您构造一个 dicts 列表(或列表),然后只需传递给构造函数,效率会高得多 @amc 是的,你也可以df = pandas.DataFrame(columns=['a', 'b', 'c', 'd']); df.loc['y'] = [1, 5, 2, 3]【参考方案2】:

我的方法是,但我不能保证这是最快的解决方案。

df = pd.DataFrame(columns=["firstname", "lastname"])
df = df.append(
     "firstname": "John",
     "lastname":  "Johny"
      , ignore_index=True)

【讨论】:

这对我来说非常有效,我喜欢你明确地 append 数据到数据框的事实。 请注意,此答案需要每一行都附加列名。接受的答案相同。 如果您事先不知道行数,这也可以。 如果逐行构建但使用大型数据集,即使使用ignore_index=True,这是您可以做的最好的事情,将数据加载到列表列表中然后构造使用 `df = pd.DataFrame(data, columns=header) 在一行中的 DataFrame。无论索引处理如何,pandas 在追加行时似乎都做了一些相当繁重的工作。 @Ben - 我没有测试过,但连接两个数据库应该快得多,正如你所展示的,而不是一次添加一行。但是,对于小型数据集,时间差异可能不会被肉眼注意到。【参考方案3】:

这是一个更简单的版本

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>']`

【讨论】:

只想问,这个CPU和内存效率高吗? 我怎么知道df的最后一行,所以我每次都追加到最后一行? append() 的其他两个选项(可能在每次循环迭代时复制整个数据库(当您重新分配给自己))以及创建两个相同数据结构的另一个常见选项(a List 然后是 DataFrame) 相同的数据,这在内存使用方面似乎更“有效”,但速度可能完全是另一个问题。 也许你可以做df.loc[-1] 您可以将数据添加到 DataFrame 的末尾:df.loc[ len(df) ] = ["My", "new", "Data"]【参考方案4】:

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

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']) 不起作用。形状不对。那怎么办?【参考方案5】:

代码背后的逻辑非常简单直接

使用字典制作 1 行的 df

然后创建一个形状为 (1, 4) 的 df,它只包含 NaN 并且与字典键具有相同的列

然后将一个 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]

【讨论】:

以上是关于Python pandas:逐行填充数据框的主要内容,如果未能解决你的问题,请参考以下文章

Python、Pandas 和 for 循环:根据与列表值的匹配填充数据框行

使用 Python 用稀疏的 CSV 数据填充 Pandas 数据框

python postgresql从pandas数据框创建数据库并填充表

用 Pandas 数据框中的行填充嵌套字典

Python pands和matplotlib常用命令

用 pandas 数据框中另一列的值填充多列中的 Na