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?
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)
So fügen Sie einfach eine neue Spalte hinzu: df['e'] = e
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 .
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())
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.
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
_
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
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
_
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.
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".
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
_
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
_
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.
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.
Einfachste Wege: -
data['new_col'] = list_of_values
data.loc[ : , 'new_col'] = list_of_values
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.
list_of_e
eines Pythons, der relevante Daten enthält.df['e'] = list_of_e
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.
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
e = [ -0.335485, -1.166658, -0.385571]
Einfach und leicht
df['e'] = e
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)
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.
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])
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)
Ich suchte nach einer allgemeinen Möglichkeit, eine Spalte mit numpy.nan
s zu einem Datenrahmen hinzuzufügen, ohne das dumme SettingWithCopyWarning
zu erhalten.
Aus dem Folgenden:
numpy
Arrays von NaNs in-lineDas habe ich mir ausgedacht:
col = 'column_name'
df = df.assign(**{col:numpy.full(len(df), numpy.nan)})
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
Hinzufügen einer neuen Spalte 'e' zum vorhandenen Datenrahmen
df1.loc[:,'e'] = Series(np.random.randn(sLength))
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)
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
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