次のような、名前付きの列と行が連続していない番号の付いた、インデックス付きの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
、append
、merge
の異なるバージョンを試しましたが、望んだ結果が得られず、せいぜいエラーだけでした。上記の例にe
列を追加するにはどうすればよいですか?
元の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
>>>
実際、これは現在のところより効率的な方法です - パンダのドキュメントで説明されている
2017年の編集
コメントと@Alexanderによって示されているように、DataFrameの新しい列としてSeriesの値を追加するための現在最良の方法はassign
を使用することです。
df1 = df1.assign(e=p.Series(np.random.randn(sLength)).values)
これは新しい列を追加する簡単な方法です:df['e'] = e
既存のデータフレームに新しい列 'e'を追加し、データフレームの内容を変更しないでください。 (シリーズは常にデータフレームと同じ長さになりました。)
e
のインデックス値はdf1
のインデックス値と一致すると思います。
e
という名前の新しい列を開始して、それにあなたの系列e
からの値を代入する最も簡単な方法:
df['e'] = e.values
代入(Pandas 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
この新機能が最初に導入されたときの説明は ここ にあります。
NumPy で直接これを実行するのが最も効率的です。
df1['e'] = np.random.randn(sLength)
私の最初の(非常に古い)提案はmap
を使うことでした(これはもっと遅いです):
df1['e'] = df1['a'].map(lambda x: np.random.random())
最近のPandasバージョンでは、 df.assign を使用するのがよいでしょう。
df1 = df1.assign(e=np.random.randn(sLength))
SettingWithCopyWarning
は生成されません。
pandasデータフレームは、列の順序付き辞書として実装されます。
つまり、__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 [] =
メソッドtries「スマート」
[] =
メソッドを使用すると、pandasは、左手のデータフレームのインデックスと右手のシリーズのインデックスを使用して、外部結合または外部マージを静かに実行します。 df['column'] = series
[]=
メソッドは入力に応じてさまざまなことをしようとしているため、これはすぐに認知的不協和を引き起こし、あなたがを知らない限り結果を予測できませんpandasの仕組み。したがって、コードベースの[]=
に対してアドバイスをしますが、ノートブックのデータを調べる場合は問題ありません。
pd.Series
があり、上から下に割り当てたい場合、または生産的なコードをコーディングしていてインデックスの順序がわからない場合は、この種の問題を保護する価値があります。
pd.Series
をnp.ndarray
または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()
を使用した別の方法インデックスの不協和が問題であるため、データフレームのインデックスが物事を指示すべきではないと感じた場合、単にインデックスを削除できます。より高速ですが、あまりきれいではありません。関数がおそらくの2つのことを行うためです。
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(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.assign
臭いになります。関数にはこの種のアーティファクトが含まれているためです。
df.assign(self=pd.Series(['no', 'no', 'no', 'yes'])
TypeError: assign() got multiple values for keyword argument 'self'
「それでは、self
を使用しない」と言うかもしれません。しかし、新しい引数をサポートするためにこの関数が将来どのように変化するかを誰が知っていますか。たぶん、パンダの新しい更新では、列名が引数になり、アップグレードで問題が発生する可能性があります。
新しい列全体を初期ベース値(例:None
)に設定したい場合は、次のようにします。df1['e'] = None
これは実際にはセルに "オブジェクト"タイプを割り当てます。そのため、後でリストなどの複雑なデータ型を個々のセルに自由に配置できます。
最も簡単な方法: -
data['new_col'] = list_of_values
data.loc[ : , 'new_col'] = list_of_values
私は恐ろしいSettingWithCopyWarning
を手に入れました、そしてそれはiloc構文を使用することによって固定されませんでした。私のDataFrameはODBCソースからread_sqlによって作成されました。上記のローテクによる提案を使用して、以下が私のために働きました:
df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength), index=df.index))
これは最後にカラムを挿入するのにうまくいきました。それが最も効率的かどうかはわかりませんが、警告メッセージは好きではありません。もっと良い解決策があると思いますが、見つけることができません、そしてそれはインデックスのある面に依存すると思います。
注意。これが一度だけ動作し、既存の列を上書きしようとするとエラーメッセージが表示されます。
注 上記のとおり、および0.16.0からassignが最良の解決策です。ドキュメントを参照してください http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html#pandas.DataFrame.assign 上書きしないデータフロータイプではうまく機能します。中間値.
list_of_e
を作成してください。df['e'] = list_of_e
追加しようとしている列が系列変数の場合は、次のようにします。
df["new_columns_name"]=series_variable_name #this will do it for you
既存の列を置き換える場合でも、これはうまく機能します。置き換えたい列と同じnew_columns_nameを入力します。既存の列データを新しい系列データで上書きするだけです。
e = [ -0.335485, -1.166658, -0.385571]
シンプルで簡単な方法
df['e'] = e
フールプルーフ:
df.loc[:, 'NewCol'] = 'New_Val'
例:
df = pd.DataFrame(data=np.random.randn(20, 4), columns=['A', 'B', 'C', 'D'])
df
A B C D
0 -0.761269 0.477348 1.170614 0.752714
1 1.217250 -0.930860 -0.769324 -0.408642
2 -0.619679 -1.227659 -0.259135 1.700294
3 -0.147354 0.778707 0.479145 2.284143
4 -0.529529 0.000571 0.913779 1.395894
5 2.592400 0.637253 1.441096 -0.631468
6 0.757178 0.240012 -0.553820 1.177202
7 -0.986128 -1.313843 0.788589 -0.707836
8 0.606985 -2.232903 -1.358107 -2.855494
9 -0.692013 0.671866 1.179466 -1.180351
10 -1.093707 -0.530600 0.182926 -1.296494
11 -0.143273 -0.503199 -1.328728 0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832 0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15 0.955298 -1.430019 1.434071 -0.088215
16 -0.227946 0.047462 0.373573 -0.111675
17 1.627912 0.043611 1.743403 -0.012714
18 0.693458 0.144327 0.329500 -0.655045
19 0.104425 0.037412 0.450598 -0.923387
df.drop([3, 5, 8, 10, 18], inplace=True)
df
A B C D
0 -0.761269 0.477348 1.170614 0.752714
1 1.217250 -0.930860 -0.769324 -0.408642
2 -0.619679 -1.227659 -0.259135 1.700294
4 -0.529529 0.000571 0.913779 1.395894
6 0.757178 0.240012 -0.553820 1.177202
7 -0.986128 -1.313843 0.788589 -0.707836
9 -0.692013 0.671866 1.179466 -1.180351
11 -0.143273 -0.503199 -1.328728 0.610552
12 -0.923110 -1.365890 -1.366202 -1.185999
13 -2.026832 0.273593 -0.440426 -0.627423
14 -0.054503 -0.788866 -0.228088 -0.404783
15 0.955298 -1.430019 1.434071 -0.088215
16 -0.227946 0.047462 0.373573 -0.111675
17 1.627912 0.043611 1.743403 -0.012714
19 0.104425 0.037412 0.450598 -0.923387
df.loc[:, 'NewCol'] = 0
df
A B C D NewCol
0 -0.761269 0.477348 1.170614 0.752714 0
1 1.217250 -0.930860 -0.769324 -0.408642 0
2 -0.619679 -1.227659 -0.259135 1.700294 0
4 -0.529529 0.000571 0.913779 1.395894 0
6 0.757178 0.240012 -0.553820 1.177202 0
7 -0.986128 -1.313843 0.788589 -0.707836 0
9 -0.692013 0.671866 1.179466 -1.180351 0
11 -0.143273 -0.503199 -1.328728 0.610552 0
12 -0.923110 -1.365890 -1.366202 -1.185999 0
13 -2.026832 0.273593 -0.440426 -0.627423 0
14 -0.054503 -0.788866 -0.228088 -0.404783 0
15 0.955298 -1.430019 1.434071 -0.088215 0
16 -0.227946 0.047462 0.373573 -0.111675 0
17 1.627912 0.043611 1.743403 -0.012714 0
19 0.104425 0.037412 0.450598 -0.923387 0
データフレームとSeriesオブジェクトが 同じインデックス を持つ場合、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)
hum3 と同じように、.loc
はSettingWithCopyWarning
を解決できなかったので、df.insert()
に頼らなければなりませんでした。私の場合、偽陽性は "偽の"チェーンインデックスdict['a']['e']
によって生成されました。ここで、'e'
は新しい列で、dict['a']
は辞書からのDataFrameです。
また、自分が何をしているのかを知っていれば、pd.options.mode.chained_assignment = None
を使って警告を切り替えることができます。ここで説明している他の解決策を使うよりも注意が必要です。
データにインデックスを付けた場合は、新しい列を割り当てる前に、インデックスを並べ替える必要があります。少なくとも私の場合、私はしなければならなかった:
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])
注意すべき1つのことは、しかし、あなたがそうすればそれです
df1['e'] = Series(np.random.randn(sLength), index=df1.index)
これは実質的にdf1.indexの left joinになります。したがって、 outer join効果を得たい場合は、おそらく不完全な解決策として、データの範囲をカバーするインデックス値を持つデータフレームを作成してから、上記のコードを使用します。例えば、
data = pd.DataFrame(index=all_possible_values)
df1['e'] = Series(np.random.randn(sLength), index=df1.index)
完全を期すために - DataFrame.eval() methodを使用したさらに別の解決策:
データ:
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
既存のデータフレームに新しい列 'e'を追加する
df1.loc[:,'e'] = Series(np.random.randn(sLength))
以下は私がしたことです...しかし私はパンダ、そして本当にPython全般についてはかなり新しいので、約束はありません。
df = pd.DataFrame([[1, 2], [3, 4], [5,6]], columns=list('AB'))
newCol = [3,5,7]
newName = 'C'
values = np.insert(df.values,df.shape[1],newCol,axis=1)
header = df.columns.values.tolist()
header.append(newName)
df = pd.DataFrame(values,columns=header)
SettingWithCopyWarning
を取得した場合、簡単な解決策は、列を追加しようとしているDataFrameをコピーすることです。
df = df.copy()
df['col_name'] = values
データフレーム内の指定された位置(0 <= loc <=列数)に新しい列を挿入するには、単にDataframe.insertを使用します。
DataFrame.insert(loc, column, value)
したがって、dfというデータフレームの最後にeという列を追加する場合は、次のようにします。
e = [-0.335485, -1.166658, -0.385571]
DataFrame.insert(loc=len(df.columns), column='e', value=e)
valueは、Series、整数(この場合、すべてのセルがこの1つの値で埋められる)、または配列のような構造になります。
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.insert.html