空のPandas DataFrameを作成して、それを埋めますか?


461

私はここでpandas DataFrameドキュメントから始めています:http ://pandas.pydata.org/pandas-docs/stable/dsintro.html

DataFrameに、時系列の計算の値を繰り返し入力します。したがって、基本的には、DataFrameを列A、B、およびタイムスタンプ行ですべて0またはすべてNaNで初期化したいと思います。

次に、初期値を追加し、このデータを調べて、前の行から新しい行を計算します。 row[A][t] = row[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

6
DataFrameを拡張しないでください。メモリとパフォーマンスの両面で、Pythonリストに追加して、最後にそれをDataFrameに変換する方が常に安価です。
cs95

@ cs95 .appendpdとリストの追加の機能的な違いは何ですか?私.appendはパンダでデータセット全体を新しいオブジェクトにコピーすることを知っています ´、pythonの追加は異なる動作をしますか?
ラマ

@Lammaは以下の私の答えで詳細を見つけてください。dfに追加する場合、既存のデータフレームを使用する代わりに、毎回新しいDataFrameがメモリに作成されますが、これは率直に言って無駄です。
cs95

回答:


330

ここにいくつかの提案があります:

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(NaNs付き)を作成するには、次のように記述します。

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

2
pd.date_range()は動作しません。(Eclipseのオートコンプリートからの)DateRangeを試してみましたが、日付形式として文字列で機能しますよね?全体的なアプローチは機能します(インデックスを別のものに変更しました)。
Matthias Kauer

2
date_rangeは、日時インデックスを作成するためのファクトリ関数であり、0.8.0の新機能でした。多くのバグ修正と新機能がある最新の安定リリース(0.9.1)にアップグレードすることをお勧めします。:)
アンディ・ヘイデン

26
私の経験では、NaNで満たされた必要なサイズのデータ​​フレームを作成し、次に値で満たす方が、indexx 0次元(columns = [])でデータフレームを作成し、ループの各ターンに1つの列をアタッチするよりもはるかに遅くなります。私が意味するdf[col_name] = pandas.Series([...])、列名を反復ループで。前者の場合、メモリ割り当てに時間がかかるだけでなく、NaNを新しい値で置き換えるのは非常に遅いようです。
deeenes

5
@deeenes間違いなく。この答えはおそらくそれをより明確にするはずです-(NaNの)空のDataframeを作成することはほとんどありません(あるとしても)。
アンディヘイデン

1
この回答に従ってstackoverflow.com/a/30267881/2302569フィルナの結果を割り当てるか、param
inplace

169

空のデータフレームを作成し、後でいくつかの受信データフレームで埋めるだけの場合は、次のことを試してください。

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 

この例では、このパンダドキュメントを使用して新しいデータフレームを作成してから、appendを使用してoldDFからのデータでnewDFに書き込みます。

複数のoldDFからこのnewDFに新しいデータを追加し続ける必要がある場合は、forループを使用してpandas.DataFrame.append()を反復します


14
append(そして同様にconcat)毎回新しいデータセットに完全なデータセットをコピーすることに注意してください。したがって、反復と追加はパフォーマンスに大きな影響を与える可能性があり、大きな影響を与えます。詳細については、次を参照してください:pandas.pydata.org/pandas-docs/stable/merging.html
MoustafaAAtta

4
@MoustafaAAttaデータフレームに繰り返しデータを追加する代替手段は何ですか?
MysteryGuy 2018

2
@MoustafaAAttaフレッドはこの投稿で答えていますか:stackoverflow.com/questions/10715965/…この観点ではより良いですか?
MysteryGuy 2018

@MoustafaAAtta行だけをデータフレームに追加することもできますが、それでも新しいオブジェクトが作成されますが、小さいデータセットの場合は便利です。pandas.pydata.org/pandas-docs/stable/user_guide/...
geekidharsh

135

データフレームを作成する正しい方法™

TLDR; (太字のテキストを読むだけです)

ここでのほとんどの答えは、空のDataFrameを作成してそれを埋める方法を教えてくれますが、それが悪いことであると誰も教えてくれません。

これが私のアドバイスです:作業に必要なすべてのデータが揃うまで待ちます。リストを使用してデータを収集し、準備ができたらDataFrameを初期化します。

data = []
for a, b, c in some_function_that_yields_data():
    data.append([a, b, c])

df = pd.DataFrame(data, columns=['A', 'B', 'C'])

リストに追加してDataFrameを一度に作成する方が、空のDataFrame(またはNaNの1つ)を作成して何度も追加するより常に安上がりです。また、リストはメモリ使用量が少なく、(必要な場合)の操作、追加、削除を行うためのデータ構造がはるかに軽量です。

この方法のもう1つの利点はdtypes、自動的に推測されることですobjectすべてに割り当てるのではなく)。

最後の利点はRangeIndexがデータ用に自動的に作成されるため、心配する必要が1つ少なくappendなりlocます(以下の貧しい人々とメソッドを見てください。インデックスを適切に処理する必要がある両方の要素が表示されます)。


してはいけないこと

appendまたは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)

メモリーはappendconcat操作ごとに再割り当てされます。これをループと組み合わせると、2次の複雑さの演算ができます。df.appendドキュメントページから:

DataFrameに繰り返し行を追加すると、単一の連結よりも計算負荷が高くなる可能性があります。より良い解決策は、それらの行をリストに追加し、リストを元のDataFrameと一度に連結することです。

関連するもう1つの間違いdf.appendは、ユーザーが追記を忘れがちなのがインプレース関数ではないため、結果を割り当て直す必要があることです。また、dtypeについても考慮する必要があります。

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

オブジェクト列を処理することは、パンダがそれらの列に対する操作をベクトル化できないため、決して良いことではありません。あなたはそれを修正するためにこれを行う必要があります:

df.infer_objects().dtypes
A      int64
B    float64
C     object
dtype: 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の空のDataFrame

次に、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]

証拠はプリンにあります

これらのメソッドのタイミングは、メモリとユーティリティの点でどれだけ異なるかを確認する最も速い方法です。

ここに画像の説明を入力してください

参照用のベンチマークコード。


6
リストの追加は、このタイプの質問に最適な方法です
YOBEN_S

9
これは100万倍以上賛成する必要があります。データフレームを拡大しないでください!
バギー

3
@ user3293236古い質問に答えるたびに下から始めなければならないので残念です;)
cs95

2
これが一番嫌いなことのひとつです。これらの多くの場合、投票数が少ないためにどこかにとどまり、決して受け入れられないことがわかります。空のパンダデータフレームを作成するために、with =𝚙𝚍.𝙳𝚊𝚝𝚊𝙵𝚛𝚊𝚖𝚎([])のコードがありません。この回答に賛成。素晴らしい説明、@ cs95!
ジョナサン

1
これは文字通りドキュメントにあります。「DataFrameに行を繰り返し追加すると、単一の連結よりも計算負荷が高くなる可能性があります。これらの行をリストに追加してから、リストを元のDataFrameと一度に連結することをお勧めします。」pandas.pydata.org/pandas-docs/version/0.21/generated/...
endolith

132

列名で空のフレームを初期化する

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‌レコードなど)の内部でシンを実行する場合は、これら2つを組み合わせて使用​​することをお勧めします。サイズが約1000になるまでデータフレームにilocを入力し、それを元のデータフレームに追加して、一時データフレームを空にします。これにより、パフォーマンスが約10倍向上します。


my_df = my_df.append(my_df2)私が指定しない限り私のために動作しませんignore_index=True
Nasif Imtiaz Ohi

0

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])

最初のx pd.Series([x], index = [x])を任意の値に置き換えることができます

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.