创建一个空的Pandas DataFrame,然后填充它

我从熊猫DataFrame留档开始:数据结构简介

我想迭代地用时间序列计算中的值填充DataFrame。所以基本上,我想用列A、B和时间戳行初始化DataFrame,全部为0或全部为NaN。

然后,我将添加初始值并遍历这些数据,从前一行计算新行,例如row[A][t] = row[A][t-1]+1左右。

我目前正在使用如下代码,但我觉得它有点难看,必须有一种方法直接使用DataFrame来执行此操作,或者只是一般更好的方法。

注意:我使用的是Python 2.7。

import datetime as dtimport pandas as pdimport scipy as s
if __name__ == '__main__':base = dt.datetime.today().date()dates = [ base - dt.timedelta(days=x) for x in range(0,10) ]dates.sort()    
valdict = {}symbols = ['A','B', 'C']for symb in symbols:valdict[symb] = pd.Series( s.zeros( len(dates)), dates )        
for thedate in dates:if thedate > dates[0]:for symb in valdict:valdict[symb][thedate] = 1+valdict[symb][thedate - dt.timedelta(days=1)]            
print valdict
2109488 次浏览

这里有几个建议:

使用date_range作为索引:

import datetimeimport pandas as pdimport numpy as np
todays_date = datetime.datetime.now().date()index = pd.date_range(todays_date-datetime.timedelta(10), periods=10, freq='D')
columns = ['A','B', 'C']

注意:我们可以创建一个空的DataFrame(带有NaN),只需编写:

df_ = pd.DataFrame(index=index, columns=columns)df_ = df_.fillna(0) # With 0s rather than NaNs

要对数据执行这些类型的计算,请使用NumPy数组:

data = np.array([np.arange(10)]*3).T

因此,我们可以创建DataFrame:

In [10]: df = pd.DataFrame(data, index=index, columns=columns)
In [11]: dfOut[11]:A  B  C2012-11-29  0  0  02012-11-30  1  1  12012-12-01  2  2  22012-12-02  3  3  32012-12-03  4  4  42012-12-04  5  5  52012-12-05  6  6  62012-12-06  7  7  72012-12-07  8  8  82012-12-08  9  9  9

如果您只是想创建一个空数据帧并稍后用一些传入数据帧填充它,请尝试以下操作:

newDF = pd.DataFrame() #creates a new dataframe that's emptynewDF = newDF.append(oldDF, ignore_index = True) # ignoring index is optional# try printing some data from newDFprint newDF.head() #again optional

在这个例子中,我使用这个熊猫医生创建一个新的数据帧,然后使用追加将来自oldDF的数据写入newDF。

如果我必须继续将新数据附加到这个newDF中一个旧的DF,我只是使用for循环来迭代pandas.DataFrame.append()

注意:append()自1.4.0版以来已不建议使用。

使用列名初始化空框架

import pandas as pd
col_names =  ['A', 'B', 'C']my_df  = pd.DataFrame(columns = col_names)my_df

将新记录添加到帧

my_df.loc[len(my_df)] = [2, 4, 5]

您可能还想传递字典:

my_dic = {'A':2, 'B':4, 'C':5}my_df.loc[len(my_df)] = my_dic

将另一个框架附加到现有框架

col_names =  ['A', 'B', 'C']my_df2  = pd.DataFrame(columns = col_names)my_df = my_df.append(my_df2)

性能考虑

如果要在循环中添加行,请考虑性能问题。对于前1000条记录,“my_df.loc”性能会更好,但随着循环中记录数量的增加,它会逐渐变慢。

如果你打算在一个大循环中做一些事情(比如10M记录),你最好混合使用这两种方法;用iloc填充一个dataframe,直到大小达到1000左右,然后将其附加到原始dataframe,并清空temp dataframe。这将使你的表现提高10倍左右。

假设一个数据帧有19行

index=range(0,19)index
columns=['A']test = pd.DataFrame(index=index, columns=columns)

将A列保持为常数

test['A']=10

将列b作为循环给定的变量

for x in range(0,19):test.loc[[x], 'b'] = pd.Series([x], index = [x])

您可以将pd.Series([x], index = [x])中的第一个x替换为任何值

永远不要增长一个DataFrame行明智!

TLDR;(只需阅读粗体文本)

这里的大多数答案都会告诉你如何创建一个空的DataFrame并填写它,但没有人会告诉你这是一件坏事。

以下是我的建议:在列表中累积数据,而不是数据帧。

使用列表收集您的数据,然后在准备好后初始化DataFrame。列表或列表格式都可以,pd.DataFrame都接受。

data = []for row in some_function_that_yields_data():data.append(row)
df = pd.DataFrame(data)

pd.DataFrame将行列表(其中每一行都是标量值)转换为DataFrame。如果您的函数生成DataFrames,请调用pd.concat

这种方法的优点:

  1. 附加到列表并一次性创建DataFrame总是更便宜比创建一个空的DataFrame(或一个NaN)并一遍又一遍地附加到它。

  2. 列表也占用更少的内存,并且是一种更轻的数据结构,追加和删除(如果需要)。

  3. #0是自动推断的(而不是将object分配给所有人)。

  4. 为您的数据自动创建#0,而不是您必须注意将正确的索引分配给您在每次迭代中附加的行。

如果你还不相信,这也在留档中提到:

迭代地将行附加到DataFrame可以更具计算性比单个连接更密集。更好的解决方案是附加将这些行连接到列表中,然后将列表与原始行连接一次完成所有数据帧。

***熊猫更新>=1.4:append现在被废弃了!***

从熊猫1.4开始,append现在已经被弃用!使用pd.concat代替。参见发行说明



这些选择太可怕了

appendconcat在循环中

这是我从初学者那里看到的最大错误:

df = pd.DataFrame(columns=['A', 'B', 'C'])for a, b, c in some_function_that_yields_data():df = df.append({'A': i, 'B': b, 'C': c}, ignore_index=True) # yuck# or similarly,# df = pd.concat([df, pd.Series({'A': i, 'B': b, 'C': c})], ignore_index=True)

内存会为您的每个appendconcat操作重新分配。将其与循环耦合,您将获得二次复杂度运算

df.append相关的另一个错误是用户倾向于忘记append不是一个就地函数,因此必须将结果分配回来。你还必须担心dtype:

df = pd.DataFrame(columns=['A', 'B', 'C'])df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)
df.dtypesA     object   # yuck!B    float64C     objectdtype: object

处理对象列从来都不是一件好事,因为熊猫不能对这些列进行矢量化操作。你需要这样做来修复它:

df.infer_objects().dtypesA      int64B    float64C     objectdtype: object

loc在一个循环中

我还看到loc用于附加到创建为空的DataFrame:

df = pd.DataFrame(columns=['A', 'B', 'C'])for a, b, c in some_function_that_yields_data():df.loc[len(df)] = [a, b, c]

和以前一样,您没有预先分配每次所需的内存量,所以每次创建新行时,内存都会重新增长。它和append一样糟糕,甚至更丑陋。

NaN的空数据帧

然后,创建NaN的DataFrame,以及与之相关的所有警告。

df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))dfA    B    C0  NaN  NaN  NaN1  NaN  NaN  NaN2  NaN  NaN  NaN3  NaN  NaN  NaN4  NaN  NaN  NaN

它创建一个对象列的DataFrame,就像其他列一样。

df.dtypesA    object  # you DON'T want thisB    objectC    objectdtype: object

追加仍然存在与上述方法相同的所有问题。

for i, (a, b, c) in enumerate(some_function_that_yields_data()):df.iloc[i] = [a, b, c]


证据就在布丁里

对这些方法进行计时是查看它们在内存和效用方面有多大差异的最快方法。

在此处输入图片描述

基准代码以供参考。

这是我用循环从几个列表中创建动态数据框的方法

x = [1,2,3,4,5,6,7,8]y = [22,12,34,22,65,24,12,11]z = ['as','ss','wa', 'ss','er','fd','ga','mf']names = ['Bob', 'Liz', 'chop']

一个循环

def dataF(x,y,z,names):res = []
for t in zip(x,y,z):res.append(t)
return pd.DataFrame(res,columns=names)

结果

dataF(x,y,z,names)

输入图片描述

简单地说:

import numpy as npimport pandas as pd
df=pd.DataFrame(np.zeros([rows,columns])

然后填满它。

# import pandas libraryimport pandas as pd
# create a dataframemy_df = pd.DataFrame({"A": ["shirt"], "B": [1200]})
# show the dataframeprint(my_df)