python - 結合 - pandas 複数列 追加




Python pandasで既存のDataFrameに新しい列を追加する (14)

私は、連続した数字ではなく、名前付きの列と行を持つ次のインデックス付きDataFrameを持っています:

          a         b         c         d
2  0.671399  0.101208 -0.181532  0.241273
3  0.446172 -0.243316  0.051767  1.577318
5  0.614758  0.075793 -0.451460 -0.012493

私は、既存のデータフレームに新しい列'e'を追加したいと思います。データフレーム内の何も変更したくない(つまり、新しい列は常にDataFrameと同じ長さです)。

0   -0.335485
1   -1.166658
2   -0.385571
dtype: float64

私はjoin別のバージョンを試して、 appendmerge 、私が望む結果を得られず、エラーだけでした。 上記の例に列eを追加するにはどうすればよいですか?


既存のデータフレームに新しい列「e」を追加したいのですが、データフレーム内の何も変更しません。 (シリーズは常にデータフレームと同じ長さになります。)

私は、 eのインデックス値がdf1インデックス値と一致するとdf1ます。

eという名前の新しい列を開始し、それに系列の値を代入する最も簡単な方法e

df['e'] = e.values

割り当て(パンダ0.16.0+)

Pandas 0.16.0では、 assign使用することもできます。これは、新しい列をDataFrameに割り当て、元の列がすべて新しい列に加えられた新しいオブジェクト(コピー)を返します。

df1 = df1.assign(e=e.values)

この例assign関数のソースコードも含む)に従って、複数の列を含めることもできます。

df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]})
>>> df.assign(mean_a=df.a.mean(), mean_b=df.b.mean())
   a  b  mean_a  mean_b
0  1  3     1.5     3.5
1  2  4     1.5     3.5

あなたの例に関連して:

np.random.seed(0)
df1 = pd.DataFrame(np.random.randn(10, 4), columns=['a', 'b', 'c', 'd'])
mask = df1.applymap(lambda x: x <-0.7)
df1 = df1[-mask.any(axis=1)]
sLength = len(df1['a'])
e = pd.Series(np.random.randn(sLength))

>>> df1
          a         b         c         d
0  1.764052  0.400157  0.978738  2.240893
2 -0.103219  0.410599  0.144044  1.454274
3  0.761038  0.121675  0.443863  0.333674
7  1.532779  1.469359  0.154947  0.378163
9  1.230291  1.202380 -0.387327 -0.302303

>>> e
0   -1.048553
1   -1.420018
2   -1.706270
3    1.950775
4   -0.509652
dtype: float64

df1 = df1.assign(e=e.values)

>>> df1
          a         b         c         d         e
0  1.764052  0.400157  0.978738  2.240893 -1.048553
2 -0.103219  0.410599  0.144044  1.454274 -1.420018
3  0.761038  0.121675  0.443863  0.333674 -1.706270
7  1.532779  1.469359  0.154947  0.378163  1.950775
9  1.230291  1.202380 -0.387327 -0.302303 -0.509652

最初に導入されたときのこの新機能の説明は、 hereで見つけることができhere


スーパーシンプルな列の割り当て

パンダのデータフレームは、列の順序付き辞書として実装されています。

つまり、 __getitem__ []は特定の列を取得するために使用できるだけでなく、 __setitem__ [] =を使用して新しい列を割り当てることができます。

たとえば、このデータフレームには、 []アクセサを使用するだけで列が追加されます

    size      name color
0    big      rose   red
1  small    violet  blue
2  small     tulip   red
3  small  harebell  blue

df['protected'] = ['no', 'no', 'no', 'yes']

    size      name color protected
0    big      rose   red        no
1  small    violet  blue        no
2  small     tulip   red        no
3  small  harebell  blue       yes

これは、データフレームのインデックスがオフであっても機能することに注意してください。

df.index = [3,2,1,0]
df['protected'] = ['no', 'no', 'no', 'yes']
    size      name color protected
3    big      rose   red        no
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue       yes

[] =行く方法ですが、注意してください!

ただし、 pd.Seriesを持っていて、インデックスがないデータフレームに割り当てようとすると、問題が発生します。 例を参照してください:

df['protected'] = pd.Series(['no', 'no', 'no', 'yes'])
    size      name color protected
3    big      rose   red       yes
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue        no

これは、 pd.Seriesはデフォルトで0からnまで列挙されたインデックスがあるためです。 そして、pandas [] =メソッド "スマート"

実際に何が起こっているのか。

[] =メソッドを使用すると、pandasは、左手のデータフレームのインデックスと右手シリーズのインデックスを使用して、静的に外部結合または外部結合を実行しています。 df['column'] = series

サイドノート

これはすぐに認知の不調和を引き起こします。なぜなら、 []=メソッドは入力に応じて多くの異なることをしようとしており、パンダの仕組みを知っていなければ結果を予測できません。 したがって、コードベースでは[]=に対して助言をしますが、ノートブックでデータを調べるときは問題ありません。

問題を回避する

pd.Seriesあり、上から下に割り当てたい場合や、生産的なコードをコーディングしていて、インデックスの順序がわからない場合は、この種の問題を守ることは価値があります。

あなたはpd.Seriesnp.ndarrayまたはlistにダウンキャストすることができlist 、これはトリックを行います。

df['protected'] = pd.Series(['no', 'no', 'no', 'yes']).values

または

df['protected'] = list(pd.Series(['no', 'no', 'no', 'yes']))

しかし、これはあまり明白ではありません。

コーダーの中には、「こんにちは、これは冗長に見えますが、私はこれを最適化します」と言う人もいます。

明示的な方法

pd.Seriesのインデックスをdfのインデックスに設定することは明白です。

df['protected'] = pd.Series(['no', 'no', 'no', 'yes'], index=df.index)

それとももっと現実的には、おそらくpd.Seriesすでに利用可能です。

protected_series = pd.Series(['no', 'no', 'no', 'yes'])
protected_series.index = df.index

3     no
2     no
1     no
0    yes

今すぐ割り当てることができます

df['protected'] = protected_series

    size      name color protected
3    big      rose   red        no
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue       yes

df.reset_index()df.reset_index()別の方法

インデックスの不協和音が問題であるため、データフレームのインデックスが物事を指示してはならないと感じる場合は、単にインデックスを削除することができます。これは速くなければなりませんが、

df.reset_index(drop=True)
protected_series.reset_index(drop=True)
df['protected'] = protected_series

    size      name color protected
0    big      rose   red        no
1  small    violet  blue        no
2  small     tulip   red        no
3  small  harebell  blue       yes

df.assignに関するdf.assign

df.assignはあなたがしていることをより明示的にしますが、実際には上記の[]=

df.assign(protected=pd.Series(['no', 'no', 'no', 'yes']))
    size      name color protected
3    big      rose   red       yes
2  small    violet  blue        no
1  small     tulip   red        no
0  small  harebell  blue        no

df.assignで列がselfと呼ばれていないことに注意してください。 エラーが発生します。 df.assigndf.assignなります。 df.assign 、これらの種類のアーチファクトがこの関数に存在するからです。

df.assign(self=pd.Series(['no', 'no', 'no', 'yes'])
TypeError: assign() got multiple values for keyword argument 'self'

あなたは、「まあ、私はselfを使わない」と言うかもしれません。 しかし、誰が新しい機能をサポートするために将来どのようにこの機能が変化するかを知っています。 おそらくあなたの列名は、アップグレードの問題を引き起こすパンダの新しいアップデートの引数になるでしょう。


DataFrame.eval()メソッドを使用するさらに別のソリューション:

データ:

In [44]: e
Out[44]:
0    1.225506
1   -1.033944
2   -0.498953
3   -0.373332
4    0.615030
5   -0.622436
dtype: float64

In [45]: df1
Out[45]:
          a         b         c         d
0 -0.634222 -0.103264  0.745069  0.801288
4  0.782387 -0.090279  0.757662 -0.602408
5 -0.117456  2.124496  1.057301  0.765466
7  0.767532  0.104304 -0.586850  1.051297
8 -0.103272  0.958334  1.163092  1.182315
9 -0.616254  0.296678 -0.112027  0.679112

溶液:

In [46]: df1.eval("e = @e.values", inplace=True)

In [47]: df1
Out[47]:
          a         b         c         d         e
0 -0.634222 -0.103264  0.745069  0.801288  1.225506
4  0.782387 -0.090279  0.757662 -0.602408 -1.033944
5 -0.117456  2.124496  1.057301  0.765466 -0.498953
7  0.767532  0.104304 -0.586850  1.051297 -0.373332
8 -0.103272  0.958334  1.163092  1.182315  0.615030
9 -0.616254  0.296678 -0.112027  0.679112 -0.622436

SettingWithCopyWarningを取得した場合、簡単な修正は、列を追加しようとしているDataFrameをコピーすることです。

df = df.copy()
df['col_name'] = values

これは、新しい列を追加する単純な方法です: df['e'] = e


これをNumPy経由で直接行うのが最も効率的です:

df1['e'] = np.random.randn(sLength)

私のオリジナルの(非常に古い)提案はmapを使うことでした(これははるかに遅いです)。

df1['e'] = df1['a'].map(lambda x: np.random.random())

ちょうどように.locSettingWithCopyWarningを解決しなかったSettingWithCopyWarning 、私はdf.insert()df.insert()ざるを得ませんでした。 私のケースでは、 'e'が新しい列であり、 dict['a']が辞書から来るDataFrameである "fake"チェーンインデックスdict['a']['e']によって偽陽性が生成されました。

また、あなたが何をしているのか分かっている場合は、 pd.options.mode.chained_assignment = Noneを使用して警告を切り替え、ここに記載されている他の解決策の1つを使用することもできます。


データフレームとシリーズオブジェクトが同じインデックスを持つ場合、 pandas.concatもここで動作します:

import pandas as pd
df
#          a            b           c           d
#0  0.671399     0.101208   -0.181532    0.241273
#1  0.446172    -0.243316    0.051767    1.577318
#2  0.614758     0.075793   -0.451460   -0.012493

e = pd.Series([-0.335485, -1.166658, -0.385571])    
e
#0   -0.335485
#1   -1.166658
#2   -0.385571
#dtype: float64

# here we need to give the series object a name which converts to the new  column name 
# in the result
df = pd.concat([df, e.rename("e")], axis=1)
df

#          a            b           c           d           e
#0  0.671399     0.101208   -0.181532    0.241273   -0.335485
#1  0.446172    -0.243316    0.051767    1.577318   -1.166658
#2  0.614758     0.075793   -0.451460   -0.012493   -0.385571

彼らは同じインデックスを持っていない場合:

e.index = df.index
df = pd.concat([df, e.rename("e")], axis=1)

元のdf1インデックスを使用してシリーズを作成します。

df1['e'] = Series(np.random.randn(sLength), index=df1.index)

2015年を編集
いくつかは、このコードでSettingWithCopyWarningを取得すると報告されています。
しかし、コードは現在のパンダバージョン0.16.1でも完璧に動作します。

>>> sLength = len(df1['a'])
>>> df1
          a         b         c         d
6 -0.269221 -0.026476  0.997517  1.294385
8  0.917438  0.847941  0.034235 -0.448948

>>> df1['e'] = p.Series(np.random.randn(sLength), index=df1.index)
>>> df1
          a         b         c         d         e
6 -0.269221 -0.026476  0.997517  1.294385  1.757167
8  0.917438  0.847941  0.034235 -0.448948  2.228131

>>> p.version.short_version
'0.16.1'

SettingWithCopyWarningは、Dataframeのコピーに対する無効な割り当てを通知することを目的としています。 必ずしも間違っているとは限りません(誤検出を引き起こす可能性があります)が、0.13.0から、同じ目的のためにさらに適切な方法があることがわかります。 警告が表示されたら、そのアドバイスに従ってください。代わりに.loc [row_index、col_indexer] = valueを使用してみてください

>>> df1.loc[:,'f'] = p.Series(np.random.randn(sLength), index=df1.index)
>>> df1
          a         b         c         d         e         f
6 -0.269221 -0.026476  0.997517  1.294385  1.757167 -0.050927
8  0.917438  0.847941  0.034235 -0.448948  2.228131  0.006109
>>> 

実際、これは現在、 pandas docsに記述されているように 、より効率的な方法です

編集2017

コメントと@Alexanderで示されているように、現在、DataFrameの新しい列としてSeriesの値を追加する最も良い方法は、assignを使用するassignです。

df1 = df1.assign(e=p.Series(np.random.randn(sLength)).values)

新しい列を割り当てる前に、索引データがある場合は、索引をソートする必要があります。 少なくとも私の場合は、私は:

data.set_index(['index_column'], inplace=True)
"if index is unsorted, assignment of a new column will fail"        
data.sort_index(inplace = True)
data.loc['index_value1', 'column_y'] = np.random.randn(data.loc['index_value1', 'column_x'].shape[0])

既存のデータフレームに新しい列 'e'を追加するには

 df1.loc[:,'e'] = Series(np.random.randn(sLength))

最も簡単な方法: -

データ['new_col'] = list_of_values

data.loc [:、 'new_col'] = list_of_values


私はnumpy.nanの列をnumpy.nanに追加する一般的な方法を探していましたが、ダムSettingWithCopyWarningを取得しSettingWithCopyWarning

以下から:

  • ここの答え
  • 変数をキーワード引数として渡すことに関するこの質問
  • インラインで数多くのNaN配列を生成するこのメソッド

私はこれを思いついた:

col = 'column_name'
df = df.assign(**{col:numpy.full(len(df), numpy.nan)})

私は恐ろしいSettingWithCopyWarningを得て、それはiloc構文を使って修正されませんでした。 私のDataFrameは、ODBCソースからのread_sqlによって作成されました。 上記のlowtechによる提案を使用して、以下のことが私のために働いた:

df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength),  index=df.index))

これは端にカラムを挿入するために問題なく機能しました。 私はそれが最も効率的かどうかわかりませんが、私は警告メッセージが好きではありません。 私は良い解決策があると思うが、私はそれを見つけることができず、私はそれがインデックスのいくつかの側面に依存していると思う。
注意してください 。 これは一度しか動作せず、既存の列を上書きしようとするとエラーメッセージが表示されます。
注意上記のように0.16.0から割り当てが最適です。 documentation http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html#pandas.DataFrame.assign参照してください。中間値を上書きしないデータフロータイプの場合はうまく機能します。





chained-assignment