如何在for循环中的pandas数据框中追加行?

Blu*_*oon 54 python for-loop dataframe pandas

我有以下for循环:

for i in links:
     data = urllib2.urlopen(str(i)).read()
     data = json.loads(data)
     data = pd.DataFrame(data.items())
     data = data.transpose()
     data.columns = data.iloc[0]
     data = data.drop(data.index[[0]])
Run Code Online (Sandbox Code Playgroud)

如此创建的每个数据框都有大多数列与其他列相同但不是全部.而且,他们都只有一排.我需要的是向数据帧中添加for循环生成的每个数据帧中的所有不同列和每一行

我尝试过连接或类似的熊猫,但似乎没有任何效果.任何的想法?谢谢.

unu*_*tbu 60

假设您的数据如下所示:

import pandas as pd
import numpy as np

np.random.seed(2015)
df = pd.DataFrame([])
for i in range(5):
    data = dict(zip(np.random.choice(10, replace=False, size=5),
                    np.random.randint(10, size=5)))
    data = pd.DataFrame(data.items())
    data = data.transpose()
    data.columns = data.iloc[0]
    data = data.drop(data.index[[0]])
    df = df.append(data)
print('{}\n'.format(df))
# 0   0   1   2   3   4   5   6   7   8   9
# 1   6 NaN NaN   8   5 NaN NaN   7   0 NaN
# 1 NaN   9   6 NaN   2 NaN   1 NaN NaN   2
# 1 NaN   2   2   1   2 NaN   1 NaN NaN NaN
# 1   6 NaN   6 NaN   4   4   0 NaN NaN NaN
# 1 NaN   9 NaN   9 NaN   7   1   9 NaN NaN
Run Code Online (Sandbox Code Playgroud)

然后它可以替换为

np.random.seed(2015)
data = []
for i in range(5):
    data.append(dict(zip(np.random.choice(10, replace=False, size=5),
                         np.random.randint(10, size=5))))
df = pd.DataFrame(data)
print(df)
Run Code Online (Sandbox Code Playgroud)

换句话说,不要为每一行形成新的DataFrame.相反,收集dicts列表中的所有数据,然后df = pd.DataFrame(data)在循环外的最后调用一次.

每次调用都df.append需要为一个额外的行分配新DataFrame的空间,将原始DataFrame中的所有数据复制到新的DataFrame中,然后将数据复制到新行中.所有这些分配和复制都使df.append循环调用非常低效.复制的时间成本随着行数的增加而呈二次方式增长.call-DataFrame-once代码不仅更易于编写,而且性能也会更好 - 复制的时间成本随着行数的增加呈线性增长.

  • 我对性能差异感到非常惊讶:使用dataframe.append添加100行5个值需要336ms(我尝试过dataframe.loc [i],它似乎是相同的)同样的解决方案只需要4.8ms! (6认同)

kzt*_*ztd 50

您可以在循环中追加行有两个原因,1.添加到现有的df,以及2.创建新的df.

为了创建一个新的df,我认为你应该将数据创建为列表,然后创建数据框:

cols = ['c1', 'c2', 'c3']
lst = []
for a in range(2):
    lst.append([1, 2, 3])
df1 = pd.DataFrame(lst, columns=cols)
df1
Out[3]: 
   c1  c2  c3
0   1   2   3
1   1   2   3
Run Code Online (Sandbox Code Playgroud)

或者,使用索引创建数据框,然后添加到该数据框

cols = ['c1', 'c2', 'c3']
df2 = pd.DataFrame(columns=cols, index=range(2))
for a in range(2):
    df2.loc[a].c1 = 4
    df2.loc[a].c2 = 5
    df2.loc[a].c3 = 6
df2
Out[4]: 
  c1 c2 c3
0  4  5  6
1  4  5  6
Run Code Online (Sandbox Code Playgroud)

如果要添加到现有数据框,可以使用上面的任一方法,然后将df附加到一起(带或不带索引):

df3 = df2.append(df1, ignore_index=True)
df3
Out[6]: 
  c1 c2 c3
0  4  5  6
1  4  5  6
2  1  2  3
3  1  2  3
Run Code Online (Sandbox Code Playgroud)

或者,您也可以创建一个字典条目列表,并将其附加到上面的答案中.

lst_dict = []
for a in range(2):
    lst_dict.append({'c1':2, 'c2':2, 'c3': 3})
df4 = df1.append(lst_dict)
df4
Out[7]: 
   c1  c2  c3
0   1   2   3
1   1   2   3
0   2   2   3
1   2   2   3
Run Code Online (Sandbox Code Playgroud)

使用dict(zip(cols,vals)))

lst_dict = []
for a in range(2):
    vals = [7, 8, 9]
    lst_dict.append(dict(zip(cols, vals)))
df5 = df1.append(lst_dict)
Run Code Online (Sandbox Code Playgroud)


Aya*_*kar 12

一种更紧凑和有效的方法可能是:

cols = ['frame', 'count']
N = 4
dat = pd.DataFrame(columns = cols)
for i in range(N):

    dat = dat.append({'frame': str(i), 'count':i},ignore_index=True)
Run Code Online (Sandbox Code Playgroud)

输出将是:

>>> dat
   frame count
0     0     0
1     1     1
2     2     2
3     3     3
Run Code Online (Sandbox Code Playgroud)

  • 为什么这样有效?内存、时间或代码量高效吗?看起来它会使用两倍的内存,因为每次迭代它都必须用相同的 DF 覆盖整个 DF。 (2认同)