web-dev-qa-db-ja.com

forループで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]])

そのように作成された各データフレームには、他の列とほとんど共通する列がありますが、すべてではありません。さらに、すべて1行だけです。私がする必要があるのは、forループによって生成された各データフレームのすべての個別の列と各行をデータフレームに追加することです

pandasの連結または類似の方法を試しましたが、何も機能しないようです。何か案が?ありがとう。

48
Blue Moon

データが次のようになっているとします:

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

その後、次のように置き換えることができます

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)

つまり、行ごとに新しいDataFrameを形成しないでください。代わりに、すべてのデータを辞書のリストに収集し、ループの外側で最後にdf = pd.DataFrame(data)を1回呼び出します。

df.appendを呼び出すたびに、余分な行が1つある新しいDataFrameにスペースを割り当て、元のDataFrameからすべてのデータを新しいDataFrameにコピーしてから、新しい行にデータをコピーする必要があります。これらすべての割り当てとコピーは、ループ内でのdf.appendの呼び出しを非常に非効率的にします。コピーの時間コスト 二次関数で成長 行数。 call-DataFrame-onceコードが記述しやすいだけでなく、パフォーマンスが大幅に向上します。コピーの時間コストは行数に比例して増加します。

52
unutbu

ループに行を追加できる理由は2つあります。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

または、インデックス付きのデータフレームを作成してから追加します

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

既存のデータフレームに追加する場合は、上記のいずれかの方法を使用してから、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

または、辞書エントリのリストを作成し、上記の回答のようにそれらを追加することもできます。

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

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)
49
kztd

一時的な空のデータフレームを使用して、forループでデータフレームを作成しました。 forループの反復ごとに、新しいデータフレームが作成され、それによって前の反復の内容が上書きされるためです。

したがって、データフレームの内容を、既に作成されている空のデータフレームに移動する必要があります。それはそれと同じくらい簡単です。以下に示すように、.append関数を使用するだけです。

temp_df = pd.DataFrame() #Temporary empty dataframe
for sent in Sentences:
    New_df = pd.DataFrame({'words': sent.words}) #Creates a new dataframe and contains tokenized words of input sentences
    temp_df = temp_df.append(New_df, ignore_index=True) #Moving the contents of newly created dataframe to the temporary dataframe

Forループの外側で、一時データフレームの内容をマスターデータフレームにコピーし、必要がなければ一時データフレームを削除できます。

4
JKC

よりコンパクトで効率的な方法は、おそらく次のとおりです。

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)

出力は次のようになります。

>>> dat
   frame count
0     0     0
1     1     1
2     2     2
3     3     3
1
Ayanava Sarkar