So führen Sie eine Serie und einen DataFrame zusammen

83

Wenn Sie hierher gekommen sind, um Informationen zum Zusammenführen von a DataFrameund Serieszum Index zu erhalten , lesen Sie bitte diese Antwort .

Die ursprüngliche Absicht des OP bestand darin, zu fragen, wie Serienelemente als Spalten einem anderen DataFrame zugewiesen werden sollen . Wenn Sie daran interessiert sind, die Antwort darauf zu erfahren , schauen Sie sich die von EdChum akzeptierte Antwort an.


Das Beste, was ich mir einfallen lassen kann, ist

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

Kann jemand eine bessere Syntax / schnellere Methode vorschlagen?

Meine Versuche:

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

und

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

BEARBEITEN Die ersten beiden Antworten haben ein Problem mit meiner Frage hervorgehoben. Verwenden Sie daher zum Konstruieren Folgendes df:

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

mit dem Endergebnis

    a  b  s1  s2
3 NaN  4   5   6
5   2  5   5   6
6   3  6   5   6
Nathan Lloyd
quelle

Antworten:

26

Sie können einen Datenrahmen aus der Serie erstellen und dann mit dem Datenrahmen zusammenführen. Sie geben also die Daten als Werte an, multiplizieren sie jedoch mit der Länge, setzen die Spalten auf den Index und setzen die Parameter für left_index und right_index auf 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

BEARBEITEN Sie für die Situation, in der der Index Ihres erstellten df aus der Reihe den Index des df verwenden soll, und gehen Sie dann wie folgt vor:

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

Dies setzt voraus, dass die Indizes mit der Länge übereinstimmen.

EdChum
quelle
165

Update
Ab Version 0.24.0 können Sie DataFrame und Series zusammenführen, solange die Serie benannt ist.

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)

Heutzutage können Sie die Serie einfach mit to_frame () in einen DataFrame konvertieren . Also (wenn Sie sich dem Index anschließen):

df.merge(s.to_frame(), left_index=True, right_index=True)
Nicholas Morley
quelle
6
Unter Verwendung der Fragendefinitionen von dfund sgibt diese Antwort für mich einen leeren Datenrahmen zurück, nicht das in der Frage angeforderte Ergebnis. Wir möchten nicht mit dem Index übereinstimmen. Wir wollen die sWerte an alle Zeilen von senden df.
CPBL
2
Dies löst ein anderes Problem: "Wie können sie bei einem DataFrame und einer Serie im Index zusammengeführt werden?" Die Frage von OP lautete "Weisen Sie jedem Element einer Serie eine neue Spalte in einem DataFrame zu".
CS95
5

Hier ist eine Möglichkeit:

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

Um aufzuschlüsseln, was hier passiert ...

pd.DataFrame(s).TErstellt einen einzeiligen DataFrame, sder folgendermaßen aussieht:

   s1  s2
0   5   6

Als nächstes wird joindieser neue Frame verkettet mit df:

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

Zuletzt werden die NaNWerte bei Index 1 mit den vorherigen Werten in der Spalte gefüllt, indem fillnadas ffillArgument forward-fill ( ) verwendet wird:

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

Um die Verwendung zu vermeiden fillna, können pd.concatdie Zeilen des DataFrame, aus dem erstellt wurde, wiederholt werden s. In diesem Fall lautet die allgemeine Lösung:

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

Hier ist eine weitere Lösung, um die in der bearbeiteten Frage gestellte Indizierungsherausforderung zu lösen:

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

swird in einen DataFrame umgewandelt, indem die Werte wiederholt und umgeformt werden (unter Angabe der Fortran-Reihenfolge) und die entsprechenden Spaltennamen und der Index übergeben werden. Dieser neue DataFrame wird dann mit verbunden df.

Alex Riley
quelle
Netter Einzeiler, eine Einschränkung ist, dass alle NaNs, die bereits in df sind, ebenfalls gefüllt werden.
Nathan Lloyd
@Nonth Danke und guter Punkt. Ich habe eine Alternative hinzugefügt, die das Ausfüllen von NaNWerten vermeidet .
Alex Riley
Was mit der ursprünglichen Antwort von EdChums passiert ist, wirkt sich auf diese überarbeitete Antwort aus. Wenn ich den df beispielsweise mit konstruiere index=[3, 5], enthalten die neuen Spalten nach Ihrem Befehl Nans.
Nathan Lloyd
@Nonth Wieder bearbeitet! Es sollte jetzt Ihren neuen Anforderungen entsprechen.
Alex Riley
Ihre Antwort ist 20x schneller, aber es ist immer noch ein Unterschied von ~ 100 ms mit df bei 1e5 Zeilen. Meine for-Schleife ist schrecklich langsam. BTW in Ihrer Antwort der 2sein sollte len(df)allgemein anwendbar sein.
Nathan Lloyd
0

Wenn ich vorschlagen könnte, Ihre Datenrahmen wie folgt einzurichten (automatische Indizierung):

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

dann können Sie Ihre s1- und s2-Werte folgendermaßen einrichten (mit shape (), um die Anzahl der Zeilen von df zurückzugeben):

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

dann ist das gewünschte Ergebnis einfach:

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

Alternativ können Sie einfach die neuen Werte zu Ihrem Datenrahmen hinzufügen. Df:

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

Beide kehren zurück:

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

Wenn Sie eine andere Datenliste haben (anstatt nur einen einzigen anzuwendenden Wert) und wissen, dass diese in derselben Reihenfolge wie df liegt, z.

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

dann können Sie dies auf die gleiche Weise anhängen:

df['s1']=s1

kehrt zurück:

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

Sie können eine pandas.DataFrame-Spalte einfach auf eine Konstante setzen. Diese Konstante kann ein int sein, wie in Ihrem Beispiel. Wenn die von Ihnen angegebene Spalte nicht in der df enthalten ist, erstellen Pandas eine neue Spalte mit dem von Ihnen angegebenen Namen. Nachdem Ihr Datenrahmen erstellt wurde (aus Ihrer Frage):

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

Sie können einfach ausführen:

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

Sie können eine Schleife oder ein Verständnis schreiben, um dies für alle Elemente in einer Liste von Tupeln oder Schlüssel und Werte in einem Wörterbuch zu tun, je nachdem, wie Sie Ihre realen Daten gespeichert haben.

Alex
quelle
0

Wenn dfein pandas.DataFramedann df['new_col']= Series list_object of length len(df)wird die oder die Serie list_object als Spalte mit dem Namen hinzufügen 'new_col'. df['new_col']= scalar(wie 5 oder 6 in Ihrem Fall) funktioniert auch und ist gleichbedeutend mitdf['new_col']= [scalar]*len(df)

Ein zweizeiliger Code erfüllt also den Zweck:

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
Aishik Roy Chaudhury
quelle