python - tutorial - pandas spalte hinzufügen




Hinzufügen einer neuen Spalte zum vorhandenen DataFrame in Python-Pandas (14)

Ich habe den folgenden indizierten Datenrahmen mit benannten Spalten und Zeilen nicht fortlaufenden Nummern:

          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 dem vorhandenen Datenrahmen eine neue Spalte, 'e' , hinzufügen und möchte nichts im Datenrahmen ändern (dh die neue Spalte hat immer die gleiche Länge wie der DataFrame).

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 erhalten, höchstens Fehler. Wie kann ich Spalte e zum obigen Beispiel hinzufügen?


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

Ich nehme an, dass die Indexwerte in e denen in df1 .

Der einfachste Weg, um eine neue Spalte mit dem Namen e zu initiieren und ihr die Werte aus Ihrer Serie e zuzuordnen:

df['e'] = e.values

zuweisen (Pandas 0.16.0+)

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

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

Gemäß diesem Beispiel (das auch den Quellcode der assign ) können Sie auch mehr als eine Spalte einschließen:

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 dieses neuen Features, als es erstmals vorgestellt wurde, finden Sie here .


Super einfache Spaltenzuordnung

Ein Pandas-Datenrahmen wird als ein geordnetes dict von Spalten implementiert.

Dies bedeutet, dass das __getitem__ [] nicht nur verwendet werden kann, um eine bestimmte Spalte zu erhalten, sondern __setitem__ [] = kann verwendet werden, um eine neue Spalte zuzuweisen.

Zum Beispiel 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 Weg zu gehen, aber pass auf!

Wenn Sie jedoch eine pd.Series und versuchen, sie einem Datenrahmen zuzuordnen, in dem die Indizes deaktiviert sind, werden Sie Probleme bekommen. 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 eine pd.Series standardmäßig einen Index von 0 bis n hat. Und die pandas [] = Methode versucht "smart" zu sein

Was ist eigentlich los?

Wenn Sie die Methode [] = verwenden, führt Pandas leise eine äußere Verknüpfung oder äußere Zusammenführung unter Verwendung des Index des linken Datenrahmens und des Index der rechten Reihe aus. df['column'] = series

Randnotiz

Dies führt schnell zu einer kognitiven Dissonanz, da die []= Methode versucht, abhängig von der Eingabe eine Menge verschiedener Dinge zu tun, und das Ergebnis kann nicht vorhergesagt werden, solange man nicht weiß, wie Pandas funktionieren. Ich würde daher gegen die []= in Codebasen raten, aber beim Erkunden von Daten in einem Notebook ist es in Ordnung.

Umgehen des Problems

Wenn Sie eine pd.Series und sie von oben nach unten zugewiesen pd.Series möchten, oder wenn Sie produktiven Code codieren und die Indexreihenfolge nicht sicher ist, lohnt es sich, für diese Art von Problem zu sorgen.

Sie könnten die pd.Series auf einen np.ndarray oder eine list np.ndarray , dies wird den Trick tun.

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

oder

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

Aber das ist nicht sehr explizit.

Irgendein Programmierer könnte kommen und sagen: "Hey, das sieht überflüssig aus, ich werde das einfach optimieren".

Expliziter Weg

Das Setzen des Indexes der pd.Series als Index des df ist explizit.

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

Oder realistischer, Sie haben wahrscheinlich eine pd.Series bereits verfügbar.

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

Alternative Möglichkeit mit df.reset_index()

Da die Dissonanz des Index das Problem ist, wenn Sie der Meinung sind, dass der Index des Datenrahmens keine Dinge diktieren sollte, können Sie einfach den Index löschen, dieser sollte schneller sein, aber er 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

Hinweis zu df.assign

Während df.assign es expliziter macht, was Sie tun, hat es tatsächlich die gleichen 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

df.assign dass deine Spalte nicht selbst heißt. Es wird Fehler verursachen. Dies macht df.assign , da es diese Art von Artefakten in der Funktion gibt.

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 kein self benutzen". Aber wer weiß, wie sich diese Funktion in der Zukunft ändert, um neue Argumente zu unterstützen. Vielleicht wird dein Spaltenname ein Argument in einem neuen Update von Pandas sein, was Probleme beim Upgrade verursacht.


Bevor Sie eine neue Spalte zuweisen, müssen Sie den Index nach indizierten Daten 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])

Das Folgende ist, was ich getan habe ... Aber ich bin ziemlich neu für 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)

Dies NumPy am besten über NumPy :

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

Beachten Sie, dass mein ursprünglicher (sehr alter) Vorschlag darin bestand, eine map zu verwenden (die viel langsamer ist):

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

Dies ist der einfache Weg, eine neue Spalte hinzuzufügen: df['e'] = e


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

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

Es erzeugt SettingWithCopyWarning nicht.


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

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

Ich suchte nach einer allgemeinen Weise, eine Spalte von numpy.nan s zu einem Datenrahmen hinzuzufügen, ohne das dumme SettingWithCopyWarning .

Von den folgenden:

  • die Antworten hier
  • Diese Frage zum Übergeben einer Variablen als Keyword-Argument
  • Dieses Verfahren zum Erzeugen einer numpy Anordnung von NaNs in-line

Ich kam auf Folgendes:

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

Lassen Sie mich nur hinzufügen, dass, wie für , .loc das .loc nicht gelöst SettingWithCopyWarning und ich auf df.insert() zurückgreifen df.insert() . In meinem Fall wurde falsches positives Ergebnis durch "falsche" Kettenindizierung dict['a']['e'] generiert, wobei 'e' die neue Spalte ist und dict['a'] ein DataFrame aus dem Wörterbuch ist.

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


Wenn Sie das SettingWithCopyWarning , 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

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

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


Wenn die Spalte, die Sie hinzufügen möchten, eine Serienvariable ist, dann:

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

Dies funktioniert auch dann gut, wenn Sie eine vorhandene Spalte ersetzen. Geben Sie den Namen new_columns_name genauso ein wie die Spalte, die Sie ersetzen möchten. Er überschreibt einfach die vorhandenen Spaltendaten mit den neuen Seriendaten.


Narrensicher:

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






chained-assignment