シリーズとDataFrameをマージする方法


82

インデックスをマージする方法DataFrameSeriesについての情報を探してここに来た場合は、この回答を見てください。

OPの当初の意図は、シリーズ要素を列として別のDataFrameに割り当てる方法を尋ねることでした。これに対する答えを知りたい場合は、EdChumによって受け入れられた答えを見てください。


私が思いつくことができる最高のものは

df = pd.DataFrame({'a':[1, 2], 'b':[3, 4]})  # see EDIT below
s = pd.Series({'s1':5, 's2':6})

for name in s.index:
    df[name] = s[name]

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

誰かがより良い構文/より速い方法を提案できますか?

私の試み:

df.merge(s)
AttributeError: 'Series' object has no attribute 'columns'

そして

df.join(s)
ValueError: Other Series must have a name

編集投稿された最初の2つの回答は、私の質問の問題を浮き彫りにしたので、以下を使用して作成してくださいdf

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

最終結果で

    a  b  s1  s2
3 NaN  4   5   6
5   2  5   5   6
6   3  6   5   6

回答:


25

シリーズからデータフレームを作成してから、データフレームとマージすることができます。したがって、データを値として指定しますが、それらに長さを掛け、列をインデックスに設定し、left_indexとright_indexのパラメーターをTrueに設定します。

In [27]:

df.merge(pd.DataFrame(data = [s.values] * len(s), columns = s.index), left_index=True, right_index=True)
Out[27]:
   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

シリーズから構築されたdfのインデックスでdfのインデックスを使用する場合は、次のように編集します。

df.merge(pd.DataFrame(data = [s.values] * len(df), columns = s.index, index=df.index), left_index=True, right_index=True)

これは、インデックスが長さと一致することを前提としています。


163

アップデート
v0.24.0以降では、シリーズに名前が付けられている限り、DataFrameとシリーズでマージできます。

df.merge(s.rename('new'), left_index=True, right_index=True)
# If series is already named,
# df.merge(s, left_index=True, right_index=True)

現在では、to_frame()を使用してシリーズをDataFrameに簡単に変換できます。したがって(インデックスに参加する場合):

df.merge(s.to_frame(), left_index=True, right_index=True)

5
質問のとの定義を使用するdfs、この回答は、質問で要求された結果ではなく、空のデータフレームを返します。インデックスで一致させたくありません。のsすべての行に値をブロードキャストしますdf
CPBL

2
これは別の問題を解決しています:「DataFrameとSeriesが与えられた場合、それらをインデックスでマージするにはどうすればよいですか」。OPの質問は、「シリーズの各要素をDataFrameの新しい列として割り当てる」でした。
cs95 2018

5

これが1つの方法です:

df.join(pd.DataFrame(s).T).fillna(method='ffill')

ここで何が起こっているのかを分析するには...

pd.DataFrame(s).Ts次のような1行のDataFrameを作成します。

   s1  s2
0   5   6

次に、joinこの新しいフレームを次のように連結しdfます。

   a  b  s1  s2
0  1  3   5   6
1  2  4 NaN NaN

最後に、NaNインデックス1の値はfillna、forward-fill(ffill)引数を使用して列の前の値で埋められます。

   a  b  s1  s2
0  1  3   5   6
1  2  4   5   6

の使用を回避するためにfillna、を使用pd.concatして、から構築されたDataFrameの行を繰り返すことができsます。この場合、一般的な解決策は次のとおりです。

df.join(pd.concat([pd.DataFrame(s).T] * len(df), ignore_index=True))

編集された質問で提起されたインデックス作成の課題に対処するための別の解決策は次のとおりです。

df.join(pd.DataFrame(s.repeat(len(df)).values.reshape((len(df), -1), order='F'), 
        columns=s.index, 
        index=df.index))

s値を繰り返して再形成し(「Fortran」の順序を指定)、適切な列名とインデックスを渡すことにより、DataFrameに変換されます。次に、この新しいDataFrameはに結合されdfます。


素晴らしいワンライナーですが、注意点として、すでにdfに含まれているNaNもすべて埋められます。
ネイサンロイド

@Nonthありがとうと良い点。NaN値の入力を回避する代替案を含めるように編集しました。
アレックスライリー

EdChumsの元の回答で起こったことは、この改訂された回答に影響します。たとえば、でdfを作成すると、index=[3, 5]新しい列にはコマンドの後にnanが含まれます。
ネイサンロイド

@Nonth再び編集されました!これで、新しい要件を満たすはずです。
アレックスライリー

あなたの答えは20倍速いですが、それでも1e5行のdfで約100msの違いがあります。私のforループはひどく遅いです。ところで、あなたの答えでは、一般的に適用できる2はずlen(df)です。
ネイサンロイド

0

このようにデータフレームを設定することを提案できる場合(自動インデックス作成):

df = pd.DataFrame({'a':[np.nan, 1, 2], 'b':[4, 5, 6]})

次に、s1とs2の値を次のように設定できます(shape()を使用してdfから行数を返します)。

s = pd.DataFrame({'s1':[5]*df.shape[0], 's2':[6]*df.shape[0]})

そうすれば、あなたが望む結果は簡単です:

display (df.merge(s, left_index=True, right_index=True))

または、データフレームdfに新しい値を追加するだけです。

df = pd.DataFrame({'a':[nan, 1, 2], 'b':[4, 5, 6]})
df['s1']=5
df['s2']=6
display(df)

両方が戻ります:

     a  b  s1  s2
0  NaN  4   5   6
1  1.0  5   5   6
2  2.0  6   5   6

(適用する単一の値ではなく)別のデータリストがあり、それがdfと同じシーケンスであることがわかっている場合、例:

s1=['a','b','c']

次に、これを同じ方法で添付できます。

df['s1']=s1

戻り値:

     a  b s1
0  NaN  4  a
1  1.0  5  b
2  2.0  6  c

0

pandas.DataFrame列を定数に簡単に設定できます。この定数は、例のようにintにすることができます。指定した列がdfにない場合、パンダは指定した名前で新しい列を作成します。したがって、データフレームが構築された後、(質問から):

df = pd.DataFrame({'a':[np.nan, 2, 3], 'b':[4, 5, 6]}, index=[3, 5, 6])

あなたはただ走ることができます:

df['s1'], df['s2'] = 5, 6

実際のデータの保存方法に応じて、タプルのリスト内のすべての要素、またはディクショナリ内のキーと値に対してこれを実行するループまたは内包表記を作成できます。


0

場合dfpandas.DataFrame、その後df['new_col']= Series list_object of length len(df)名前の列として、あるいはシリーズLIST_OBJECTを追加します'new_col'df['new_col']= scalar(あなたの場合は5や6など)も機能し、同等ですdf['new_col']= [scalar]*len(df)

したがって、2行のコードが目的を果たします。

df = pd.DataFrame({'a':[1, 2], 'b':[3, 4]})
s = pd.Series({'s1':5, 's2':6})
for x in s.index:    
    df[x] = s[x]

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