it-swarm.com.de

Hinzufügen einer neuen Spalte zu einem vorhandenen DataFrame in Python pandas

Ich habe den folgenden indizierten DataFrame mit benannten Spalten und Zeilen und nicht fortlaufenden Zahlen:

          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

Ich möchte eine neue Spalte 'e' zum vorhandenen Datenrahmen hinzufügen und möchte nichts im Datenrahmen ändern (d. H. Die neue Spalte hat immer die gleiche Länge wie der Datenrahmen).

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

Ich habe verschiedene Versionen von join, append, merge ausprobiert, aber ich habe nicht das gewünschte Ergebnis erzielt, sondern höchstens Fehler. Wie kann ich dem obigen Beispiel die Spalte e hinzufügen?

844
tomasz74

Verwenden Sie die ursprünglichen df1-Indizes, um die Reihe zu erstellen:

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

Edit 2015
Einige berichteten, sie hätten den SettingWithCopyWarning mit diesem Code erhalten.
Der Code läuft jedoch immer noch perfekt mit der aktuellen pandas Version 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'] = pd.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'

Das SettingWithCopyWarning soll über eine möglicherweise ungültige Zuordnung auf einer Kopie des DataFrame informieren. Es muss nicht unbedingt heißen, dass Sie etwas falsch gemacht haben (es kann zu Fehlalarmen führen), aber ab 0.13.0 werden Sie darauf hingewiesen, dass es für denselben Zweck geeignetere Methoden gibt. Wenn Sie die Warnung erhalten, befolgen Sie einfach die folgenden Anweisungen: Verwenden Sie stattdessen .loc [row_index, col_indexer] = value

>>> df1.loc[:,'f'] = pd.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
>>> 

Tatsächlich ist dies derzeit die effizientere Methode als beschrieben in pandas docs


Bearbeiten 2017

Wie in den Kommentaren und von @Alexander angegeben, könnte die derzeit beste Methode zum Hinzufügen der Werte einer Reihe als neue Spalte eines DataFrames die Verwendung von assign sein:

df1 = df1.assign(e=pd.Series(np.random.randn(sLength)).values)
932
joaquin

So fügen Sie einfach eine neue Spalte hinzu: df['e'] = e

196

Ich möchte dem vorhandenen Datenrahmen eine neue Spalte "e" hinzufügen und nichts am Datenrahmen ändern. (Die Serie hat immer die gleiche Länge wie ein Datenrahmen.)

Ich gehe davon aus, dass die Indexwerte in e mit denen in df1 übereinstimmen.

Am einfachsten können Sie eine neue Spalte mit dem Namen e initiieren und ihr die Werte aus Ihrer Reihe e zuweisen:

df['e'] = e.values

zuweisen (Pandas 0.16.0 +)

Ab Pandas 0.16.0 können Sie auch assign verwenden, um einem DataFrame neue Spalten zuzuweisen und zusätzlich zu ein neues Objekt (eine Kopie) mit allen ursprünglichen Spalten zurückzugeben die neuen.

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

Gemäß dieses Beispiel (das auch den Quellcode der Funktion assign enthält) können Sie auch mehr als eine Spalte einfügen:

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

Im Zusammenhang mit Ihrem Beispiel:

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

Die Beschreibung dieser neuen Funktion, als sie zum ersten Mal eingeführt wurde, finden Sie hier .

136
Alexander

Dies direkt über NumPy zu tun, ist am effizientesten:

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

Beachten Sie, dass mein ursprünglicher (sehr alter) Vorschlag war, map zu verwenden (was viel langsamer ist):

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

Es scheint, dass in den letzten Pandas Versionen der Weg ist, df.assign zu verwenden:

df1 = df1.assign(e=np.random.randn(sLength))

Es wird kein SettingWithCopyWarning erzeugt.

45
Mikhail Korobov

Super einfache Spaltenzuordnung

Ein pandas -Datenrahmen wird als geordnetes Diktat von Spalten implementiert.

Dies bedeutet, dass mit ___getitem___ _[]_ nicht nur eine bestimmte Spalte abgerufen werden kann, sondern mit ___setitem___ _[] =_ eine neue Spalte zugewiesen werden kann.

Beispielsweise kann diesem Datenrahmen eine Spalte hinzugefügt werden, indem einfach der Accessor _[]_ verwendet wird

_    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
_

Beachten Sie, dass dies auch dann funktioniert, wenn der Index des Datenrahmens deaktiviert ist.

_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
_

[] = ist der richtige Weg, aber pass auf!

Wenn Sie jedoch einen _pd.Series_ haben und versuchen, ihn einem Datenrahmen zuzuweisen, in dem die Indizes deaktiviert sind, treten Probleme auf. Siehe Beispiel:

_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
_

Dies liegt daran, dass ein _pd.Series_ standardmäßig einen Index von 0 bis n hat. Und die pandas _[] =_ -Methode versucht, "klug" zu sein

Was ist eigentlich los?.

Wenn Sie die _[] =_ -Methode verwenden, führt pandas im Hintergrund eine äußere Verknüpfung oder Zusammenführung aus, wobei der Index des linken Datenrahmens und der Index der rechten Reihe verwendet werden. _df['column'] = series_

Randnotiz

Dies führt schnell zu kognitiver Dissonanz, da die _[]=_ -Methode versucht, je nach Eingabe viele verschiedene Dinge zu tun, und das Ergebnis kann nur vorhergesagt werden, wenn Sie genau wissen wie pandas funktioniert. Ich würde daher in Codebasen von _[]=_ abraten, aber beim Durchsuchen von Daten in einem Notizbuch ist dies in Ordnung.

Das Problem umgehen

Wenn Sie einen _pd.Series_ haben und möchten, dass dieser von oben nach unten zugewiesen wird, oder wenn Sie den Produktivcode codieren und sich hinsichtlich der Indexreihenfolge nicht sicher sind, lohnt es sich, ihn für diese Art von Problem zu schützen.

Sie könnten den _pd.Series_ auf einen _np.ndarray_ oder einen list heruntertragen, dies wird den Trick machen.

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

oder

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

Dies ist aber nicht sehr explizit.

Ein Codierer könnte mitkommen und sagen "Hey, das sieht überflüssig aus, ich optimiere das einfach weg".

Expliziter Weg

Das Festlegen des Index von _pd.Series_ als Index von df ist explizit.

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

Realistischerweise haben Sie wahrscheinlich bereits einen _pd.Series_ zur Verfügung.

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

3     no
2     no
1     no
0    yes
_

Kann jetzt zugewiesen werden

_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
_

Alternativer Weg mit df.reset_index()

Da die Index-Dissonanz das Problem ist, sollten Sie den Index einfach löschen, wenn Sie der Meinung sind, dass der Index des Datenrahmens keine Vorgaben machen sollte schneller, aber es ist nicht sehr sauber, da Ihre Funktion jetzt wahrscheinlich zwei Dinge tut.

_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
_

Anmerkung zu _df.assign_

Während _df.assign_ deutlich macht, was Sie tun, gibt es tatsächlich dieselben Probleme wie oben _[]=_

_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
_

Passen Sie einfach mit _df.assign_ auf, dass Ihre Spalte nicht self heißt. Es wird Fehler verursachen. Dies macht _df.assign_ stinkend, da diese Art von Artefakten in der Funktion vorhanden sind.

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

Sie können sagen: "Nun, ich werde dann einfach nicht self verwenden". Aber wer weiß, wie sich diese Funktion in Zukunft ändert, um neue Argumente zu unterstützen. Möglicherweise ist der Name Ihrer Spalte ein Argument in einem neuen Update von Pandas, das Probleme beim Upgrade verursacht.

35
firelynx

Wenn Sie die gesamte neue Spalte auf einen anfänglichen Basiswert setzen möchten (z. B. None), können Sie dies tun: df1['e'] = None

Dies würde der Zelle tatsächlich den Typ "Objekt" zuweisen. So können Sie später komplexe Datentypen wie Listen in einzelne Zellen einfügen.

22
digdug

Einfachste Wege: -

data['new_col'] = list_of_values

data.loc[ : , 'new_col'] = list_of_values
20
Abhishek

Ich habe das gefürchtete SettingWithCopyWarning, und es wurde nicht mit der iloc-Syntax behoben. Mein DataFrame wurde von read_sql aus einer ODBC-Quelle erstellt. Auf der Grundlage eines Vorschlags von Lowtech funktionierte für mich Folgendes:

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

Dies hat gut funktioniert, um die Spalte am Ende einzufügen. Ich weiß nicht, ob es am effizientesten ist, aber ich mag keine Warnmeldungen. Ich denke, es gibt eine bessere Lösung, aber ich kann sie nicht finden, und ich denke, dass sie von einem Aspekt des Index abhängt.
Hinweis . Dies funktioniert nur einmal und es wird eine Fehlermeldung ausgegeben, wenn versucht wird, eine vorhandene Spalte zu überschreiben.
Hinweis Wie oben und ab 0.16.0 zuweisen ist die beste Lösung. Siehe Dokumentation http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html#pandas.DataFrame.assign Funktioniert gut für Datenflusstypen, bei denen Sie nicht ' t Überschreiben Sie Ihre Zwischenwerte.

18
hum3
  1. Erstellen Sie zunächst den list_of_e eines Pythons, der relevante Daten enthält.
  2. Benutze dies: df['e'] = list_of_e
13
Sumit Pokhrel

Wenn die Spalte, die Sie hinzufügen möchten, eine Serienvariable ist, gehen Sie wie folgt vor:

df["new_columns_name"]=series_variable_name #this will do it for you

Dies funktioniert auch dann, wenn Sie eine vorhandene Spalte ersetzen. Geben Sie den Namen der neuen Spalte genauso ein wie die Spalte, die Sie ersetzen möchten. Es werden lediglich die vorhandenen Spaltendaten mit den neuen Seriendaten überschrieben.

11
Akshay Singhvi

kinderleicht:

df.loc[:, 'NewCol'] = 'New_Val'

Beispiel:

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
10
K88

e = [ -0.335485, -1.166658, -0.385571]

Einfach und leicht

df['e'] = e

9
Nursnaaz

Wenn der Datenrahmen und das Serienobjekt denselben Index haben, funktioniert pandas.concat auch hier :

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

Falls sie nicht den gleichen Index haben:

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

Lassen Sie mich das hinzufügen, genau wie für hum , .loc hat das SettingWithCopyWarning nicht gelöst und ich musste auf df.insert() zurückgreifen. In meinem Fall wurde ein falsches Positiv durch "falsches" Indizieren der Kette dict['a']['e'] erzeugt, wobei 'e' die neue Spalte ist und dict['a'] ein DataFrame ist, der aus dem Wörterbuch stammt.

Beachten Sie auch, dass Sie, wenn Sie wissen, was Sie tun, die Warnung mit pd.options.mode.chained_assignment = None ausschalten und dann eine der anderen hier angegebenen Lösungen verwenden können.

6
kkumer

Wenn Sie Daten indiziert haben, müssen Sie vor dem Zuweisen einer neuen Spalte den Index sortieren. Zumindest in meinem Fall musste ich:

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])
6
Dima Lituiev

Eines ist jedoch zu beachten, wenn Sie dies tun

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

dies wird effektiv ein links Join auf dem df1.index sein. Wenn Sie also einen äußeren Join-Effekt haben möchten, besteht meine wahrscheinlich unvollständige Lösung darin, einen Datenrahmen mit Indexwerten zu erstellen, der das Universum Ihrer Daten abdeckt, und dann den obigen Code zu verwenden. Zum Beispiel,

data = pd.DataFrame(index=all_possible_values)
df1['e'] = Series(np.random.randn(sLength), index=df1.index)
6
WillZ

Ich suchte nach einer allgemeinen Möglichkeit, eine Spalte mit numpy.nans zu einem Datenrahmen hinzuzufügen, ohne das dumme SettingWithCopyWarning zu erhalten.

Aus dem Folgenden:

  • die antworten hier
  • diese Frage über die Übergabe einer Variablen als Schlüsselwortargument
  • diese Methode zum Erzeugen eines numpy Arrays von NaNs in-line

Das habe ich mir ausgedacht:

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

Der Vollständigkeit halber noch eine andere Lösung mit der Methode DataFrame.eval () :

Daten:

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

Lösung:

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
4
MaxU

Hinzufügen einer neuen Spalte 'e' zum vorhandenen Datenrahmen

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

Folgendes habe ich getan ... Aber ich bin ziemlich neu in pandas und wirklich Python im Allgemeinen, also keine Versprechungen.

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)
3
Devin Charles

um eine neue Spalte an einer bestimmten Position (0 <= loc <= Anzahl der Spalten) in einen Datenrahmen einzufügen, verwenden Sie einfach Dataframe.insert:

DataFrame.insert(loc, column, value)

Wenn Sie daher die Spalte e am Ende eines Datenrahmens mit dem Namen df können Sie verwenden:

e = [-0.335485, -1.166658, -0.385571]    
DataFrame.insert(loc=len(df.columns), column='e', value=e)

value kann eine Reihe sein, eine ganze Zahl (in diesem Fall werden alle Zellen mit diesem einen Wert gefüllt ) oder eine Array-ähnliche Struktur

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.insert.html

3
Nooyi

Wenn Sie die Meldung SettingWithCopyWarning erhalten, besteht eine einfache Lösung darin, den DataFrame zu kopieren, dem Sie eine Spalte hinzufügen möchten.

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