我从panda DataFrame文档开始:数据结构简介

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

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

我目前使用的代码如下所示,但我觉得这有点难看,必须有一种直接使用DataFrame的方法,或者只是一种更好的方法。

注意:我使用的是Python 2.7。

import datetime as dt
import pandas as pd
import 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

以下是一些建议:

对索引使用date_range:

import datetime
import pandas as pd
import 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]: df
Out[11]:
            A  B  C
2012-11-29  0  0  0
2012-11-30  1  1  1
2012-12-01  2  2  2
2012-12-02  3  3  3
2012-12-03  4  4  4
2012-12-04  5  5  5
2012-12-05  6  6  6
2012-12-06  7  7  7
2012-12-07  8  8  8
2012-12-08  9  9  9

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

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

在本例中,我使用panda文档创建一个新的数据帧,然后使用append将来自oldDF的数据写入newDF。

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

注意:append()自1.4.0版起已弃用。使用concat()


用列名初始化空框架

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填充数据帧,直到其大小达到1000左右,然后将其附加到原始数据帧,并清空临时数据帧。这将使你的表现提高约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([x],index=[x])


决不能按行增长DataFrame!

太长,读不下去了(只需阅读粗体文本)

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

我的建议是:在列表中累积数据,而不是在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。

这种方法的优点:

与创建一个空的DataFrame(或一个NaN)并反复追加到列表中相比,一次性追加到列表并创建DataFrame总是更便宜。列表也占用更少的内存,并且是一种更轻的数据结构,可以处理、附加和删除(如果需要)。数据类型是自动推断的(而不是将对象分配给所有数据类型)。RangeIndex会自动为数据创建,而不必在每次迭代时为要附加的行指定正确的索引。

如果您还不确信,文档中也会提到这一点:

迭代地将行附加到DataFrame可能会更具计算能力比单个连接更密集。更好的解决方案是附加将这些行添加到列表中,然后将列表与原始行连接起来一次完成DataFrame。

***熊猫更新>=1.4:追加现在已弃用***

从panda 1.4开始,append已被弃用!请改用pd.concat。参见发行说明



这些选项太可怕了

在循环内追加或凹进

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

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)

内存会重新分配给您的每个追加或合并操作。再加上一个循环,你就得到了一个二次复杂度运算。

与df.append相关的另一个错误是,用户倾向于忘记append不是一个就地函数,因此必须将结果赋值回。您还必须担心数据类型:

df = pd.DataFrame(columns=['A', 'B', 'C'])
df = df.append({'A': 1, 'B': 12.3, 'C': 'xyz'}, ignore_index=True)

df.dtypes
A     object   # yuck!
B    float64
C     object
dtype: object

处理对象列从来都不是一件好事,因为panda无法对这些列进行矢量化操作。您需要执行以下操作来修复它:

df.infer_objects().dtypes
A      int64
B    float64
C     object
dtype: object

在循环中定位

我还看到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]

与之前一样,您没有预先分配每次所需的内存量,因此每次创建新行时,内存都会重新增长。它和追加一样糟糕,甚至更难看。

NaN的空数据帧

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

df = pd.DataFrame(columns=['A', 'B', 'C'], index=range(5))
df
     A    B    C
0  NaN  NaN  NaN
1  NaN  NaN  NaN
2  NaN  NaN  NaN
3  NaN  NaN  NaN
4  NaN  NaN  NaN

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

df.dtypes
A    object  # you DON'T want this
B    object
C    object
dtype: 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 np
import pandas as pd

df=pd.DataFrame(np.zeros([rows,columns])

然后加满。


# import pandas library
import pandas as pd

# create a dataframe
my_df = pd.DataFrame({"A": ["shirt"], "B": [1200]})

# show the dataframe
print(my_df)