Ik heb het volgende geïndexeerde DataFrame met benoemde kolommen en rijen, niet-continue getallen:
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
Ik wil een nieuwe kolom, 'e'
, toevoegen aan het bestaande dataframe en wil niets veranderen in het dataframe (dwz de nieuwe kolom heeft altijd dezelfde lengte als het DataFrame).
0 -0.335485
1 -1.166658
2 -0.385571
dtype: float64
Hoe kan ik kolom e
toevoegen aan het bovenstaande voorbeeld?
Antwoord 1, autoriteit 100%
2017 bewerken
Zoals aangegeven in de opmerkingen en door @Alexander, is de beste methode om de waarden van een serie toe te voegen als een nieuwe kolom van een dataframe momenteel het gebruik van assign
:
df1 = df1.assign(e=pd.Series(np.random.randn(sLength)).values)
2015 bewerken
Sommigen meldden dat ze de SettingWithCopyWarning
kregen met deze code.
De code werkt echter nog steeds perfect met de huidige panda’s versie 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
>>> pd.version.short_version
'0.16.1'
De SettingWithCopyWarning
is bedoeld om te informeren over een mogelijk ongeldige toewijzing op een kopie van het Dataframe. Het zegt niet per se dat je het verkeerd hebt gedaan (het kan valse positieven veroorzaken), maar vanaf 0.13.0 laat het je weten dat er meer geschikte methoden zijn voor hetzelfde doel. Als je de waarschuwing krijgt, volg dan gewoon het advies: Probeer in plaats daarvan .loc[row_index,col_indexer] = value te gebruiken
>>> 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
>>>
In feite is dit momenteel de efficiëntere methode als beschreven in panda’s docs
Oorspronkelijke antwoord:
Gebruik de originele df1-indexen om de serie te maken:
df1['e'] = pd.Series(np.random.randn(sLength), index=df1.index)
Antwoord 2, autoriteit 23%
Dit is de eenvoudige manier om een nieuwe kolom toe te voegen: df['e'] = e
Antwoord 3, autoriteit 16%
Ik wil graag een nieuwe kolom, ‘e’, toevoegen aan het bestaande dataframe en niets veranderen in het dataframe. (De reeks kreeg altijd dezelfde lengte als een dataframe.)
Ik neem aan dat de indexwaarden in e
overeenkomen met die in df1
.
De eenvoudigste manier om een nieuwe kolom met de naam e
te starten en deze de waarden uit uw reeks e
toe te wijzen:
df['e'] = e.values
toewijzen (Panda’s 0.16.0+)
Vanaf Pandas 0.16.0 kunt u ook assign
, die nieuwe kolommen toewijst aan een DataFrame en een nieuw object (een kopie) retourneert met alle originele kolommen naast de nieuwe.
df1 = df1.assign(e=e.values)
Volgens dit voorbeeld (inclusief de broncode van de assign
functie), kunt u ook meer dan één kolom opnemen:
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
In context met uw voorbeeld:
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
De beschrijving van deze nieuwe functie toen deze voor het eerst werd geïntroduceerd, is te vinden hier.
Antwoord 4, autoriteit 5%
Supereenvoudige kolomtoewijzing
Een pandas-dataframe wordt geïmplementeerd als een geordend dictaat van kolommen.
Dit betekent dat de __getitem__
[]
niet alleen kan worden gebruikt om een bepaalde kolom te krijgen, maar __setitem__
[] =
kan worden gebruikt om een nieuwe kolom toe te wijzen.
Aan dit dataframe kan bijvoorbeeld een kolom worden toegevoegd door simpelweg de []
-accessor
te gebruiken
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
Merk op dat dit zelfs werkt als de index van het dataframe is uitgeschakeld.
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
[]= is de juiste keuze, maar kijk uit!
Echter, als je een pd.Series
hebt en deze probeert toe te wijzen aan een dataframe waar de indexen uit staan, kom je in de problemen. Zie voorbeeld:
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
Dit komt omdat een pd.Series
standaard een index heeft die wordt opgesomd van 0 tot n. En de panda’s [] =
methode probeert om “slim” te zijn
Wat is er eigenlijk aan de hand.
Als je de [] =
methode gebruikt, voert pandas stilletjes een outer join of outer merge uit met behulp van de index van het linker dataframe en de index van de rechterhand series. df['column'] = series
Kanttekening
Dit veroorzaakt snel cognitieve dissonantie, aangezien de []=
methode veel verschillende dingen probeert te doen, afhankelijk van de invoer, en de uitkomst kan niet worden voorspeld tenzij je het gewoon weet hoe panda’s werken. Ik zou daarom de []=
in codebases afraden, maar bij het verkennen van gegevens in een notebook is het prima.
Het probleem omzeilen
Als u een pd.Series
heeft en deze van boven naar beneden wilt toewijzen, of als u productieve code codeert en u niet zeker bent van de indexvolgorde, is het de moeite waard om ervoor te zorgen dat dit soort problemen.
Je zou de pd.Series
kunnen verkleinen tot een np.ndarray
of een list
, dit is voldoende.
df['protected'] = pd.Series(['no', 'no', 'no', 'yes']).values
of
df['protected'] = list(pd.Series(['no', 'no', 'no', 'yes']))
Maar dit is niet erg expliciet.
Er kan een programmeur langskomen die zegt: “Hé, dit ziet er overbodig uit, ik zal dit even optimaliseren”.
Expliciete manier
Het instellen van de index van de pd.Series
als index van de df
is expliciet.
df['protected'] = pd.Series(['no', 'no', 'no', 'yes'], index=df.index)
Of realistischer, je hebt waarschijnlijk al een pd.Series
beschikbaar.
protected_series = pd.Series(['no', 'no', 'no', 'yes'])
protected_series.index = df.index
3 no
2 no
1 no
0 yes
Kan nu worden toegewezen
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
Alternatieve manier met df.reset_index()
Aangezien de indexdissonantie het probleem is, als u vindt dat de index van het dataframe niet dingen niet zou moeten dicteren, kunt u de index gewoon laten vallen, dit zou sneller moeten zijn, maar het is niet erg schoon , aangezien uw functie nu waarschijnlijk twee dingen doet.
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
Opmerking over df.assign
Hoewel df.assign
het explicieter maakt wat je doet, heeft het eigenlijk allemaal dezelfde problemen als de bovenstaande []=
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
Pas met df.assign
op dat je kolom niet self
heet. Het zal fouten veroorzaken. Dit maakt df.assign
stinkend, aangezien er dit soort artefacten in de functie zitten.
df.assign(self=pd.Series(['no', 'no', 'no', 'yes'])
TypeError: assign() got multiple values for keyword argument 'self'
Je zou kunnen zeggen: “Nou, dan gebruik ik self
gewoon niet”. Maar wie weet hoe deze functie in de toekomst verandert om nieuwe argumenten te ondersteunen. Misschien is je kolomnaam een argument in een nieuwe update van panda’s, waardoor er problemen ontstaan bij het upgraden.
Antwoord 5, autoriteit 5%
Het lijkt erop dat in recente Pandas-versies het gebruik van df.assign:
df1 = df1.assign(e=np.random.randn(sLength))
Het produceert geen SettingWithCopyWarning
.
Antwoord 6, autoriteit 5%
Dit rechtstreeks doen via NumPy is het meest efficiënt:
df1['e'] = np.random.randn(sLength)
Merk op dat mijn oorspronkelijke (zeer oude) suggestie was om map
te gebruiken (wat veel langzamer is):
df1['e'] = df1['a'].map(lambda x: np.random.random())
Antwoord 7, autoriteit 3%
Gemakkelijkste manieren:-
data['new_col'] = list_of_values
data.loc[ : , 'new_col'] = list_of_values
Op deze manier vermijd je wat chained indexing wordt genoemd bij het instellen van nieuwe waarden in een pandas-object. Klik hier om verder te lezen .
Antwoord 8, autoriteit 2%
Ik kreeg de gevreesde SettingWithCopyWarning
, en het werd niet opgelost door de iloc-syntaxis te gebruiken. Mijn DataFrame is gemaakt door read_sql van een ODBC-bron. Met behulp van een suggestie van lowtech hierboven, werkte het volgende voor mij:
df.insert(len(df.columns), 'e', pd.Series(np.random.randn(sLength), index=df.index))
Dit werkte prima om de kolom aan het einde in te voegen. Ik weet niet of dit het meest efficiënt is, maar ik hou niet van waarschuwingsberichten. Ik denk dat er een betere oplossing is, maar ik kan het niet vinden, en ik denk dat het afhangt van een bepaald aspect van de index.
Opmerking. Dat dit maar één keer werkt en een foutmelding geeft als je een bestaande kolom probeert te overschrijven.
Opmerking Zoals hierboven en vanaf 0.16.0 is toewijzen de beste oplossing. Zie documentatie http://pandas .pydata.org/pandas-docs/stable/generated/pandas.DataFrame.assign.html#pandas.DataFrame.assign
Werkt goed voor het type gegevensstroom waarbij u uw tussenliggende waarden niet overschrijft.
Antwoord 9, autoriteit 2%
Als u de hele nieuwe kolom wilt instellen op een initiële basiswaarde (bijv. None
), kunt u dit doen: df1['e'] = None
Dit zou eigenlijk het type “object” aan de cel toewijzen. Dus later bent u vrij om complexe gegevenstypen, zoals een lijst, in afzonderlijke cellen te plaatsen.
Antwoord 10
- Maak eerst een
list_of_e
van een python met relevante gegevens. - Gebruik dit:
df['e'] = list_of_e
Antwoord 11
Als de kolom die u probeert toe te voegen een reeksvariabele is, dan :
df["new_columns_name"]=series_variable_name #this will do it for you
Dit werkt goed, zelfs als u een bestaande kolom vervangt. Typ gewoon de nieuwe_kolomnaam hetzelfde als de kolom die u wilt vervangen. Het zal alleen de bestaande kolomgegevens overschrijven met de nieuwe reeksgegevens.
Antwoord 12
Als het dataframe en het Series-object dezelfde index hebben, werkt pandas.concat
hier ook:
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
Als ze niet dezelfde index hebben:
e.index = df.index
df = pd.concat([df, e.rename("e")], axis=1)
Antwoord 13
Een lege kolom maken
df['i'] = None
Antwoord 14
Foolproof:
df.loc[:, 'NewCol'] = 'New_Val'
Voorbeeld:
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
Antwoord 15
Eén ding om op te merken is echter dat als je dat doet
df1['e'] = Series(np.random.randn(sLength), index=df1.index)
dit wordt in feite een links-join op de df1.index. Dus als je een outer join-effect wilt hebben, is mijn waarschijnlijk onvolmaakte oplossing om een dataframe te maken met indexwaarden die het universum van je gegevens dekken, en dan de bovenstaande code te gebruiken. Bijvoorbeeld,
data = pd.DataFrame(index=all_possible_values)
df1['e'] = Series(np.random.randn(sLength), index=df1.index)
Antwoord 16
om een nieuwe kolom op een bepaalde locatie (0 <= loc <= aantal kolommen) in een dataframe in te voegen, gebruik je gewoon Dataframe.insert:
DataFrame.insert(loc, column, value)
Als u daarom de kolom e wilt toevoegen aan het einde van een gegevensframe met de naam df , kunt u gebruiken:
e = [-0.335485, -1.166658, -0.385571]
DataFrame.insert(loc=len(df.columns), column='e', value=e)
waarde kan een reeks zijn, een geheel getal (in dat geval worden alle cellen gevuld met deze ene waarde), of een matrixachtige structuur
https://pandas.pydata. org/pandas-docs/stable/reference/api/pandas.DataFrame.insert.html
Antwoord 17
Laat me toevoegen dat, net zoals voor hum3, .loc
dat niet deed los de SettingWithCopyWarning
op en ik moest mijn toevlucht nemen tot df.insert()
. In mijn geval werd vals positief gegenereerd door “nep” kettingindexering dict['a']['e']
, waarbij 'e'
de nieuwe kolom is, en dict['a']
is een DataFrame afkomstig uit een woordenboek.
Houd er rekening mee dat als u weet wat u doet, u de waarschuwing kunt uitschakelen met
pd.options.mode.chained_assignment = None
en gebruik dan een van de andere oplossingen die hier worden gegeven.
Antwoord 18
Voordat u een nieuwe kolom toewijst, moet u de index sorteren als u geïndexeerde gegevens hebt. In mijn geval moest ik tenminste:
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])
Antwoord 19
Een nieuwe kolom, ‘e’, toevoegen aan het bestaande gegevensframe
df1.loc[:,'e'] = Series(np.random.randn(sLength))
Antwoord 20
Ik was op zoek naar een algemene manier om een kolom met numpy.nan
s toe te voegen aan een dataframe zonder de domme SettingWithCopyWarning
te krijgen.
Van het volgende:
- de antwoorden hier
- deze vraag over het doorgeven van een variabele als zoekwoordargument
- deze methode voor het genereren van een
numpy
array van NaN’s in-line
Ik heb dit bedacht:
col = 'column_name'
df = df.assign(**{col:numpy.full(len(df), numpy.nan)})
Antwoord 21
Voor de volledigheid: nog een andere oplossing met DataFrame.eval() methode:
Gegevens:
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
Oplossing:
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
Antwoord 22
Het volgende is wat ik deed… Maar ik ben vrij nieuw voor panda’s en echt Python in het algemeen, dus ik beloof het niet.
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)
Antwoord 23
Als u de SettingWithCopyWarning
krijgt, kunt u eenvoudig het DataFrame kopiëren waaraan u een kolom probeert toe te voegen.
df = df.copy()
df['col_name'] = values
Antwoord 24
x=pd.DataFrame([1,2,3,4,5])
y=pd.DataFrame([5,4,3,2,1])
z=pd.concat([x,y],axis=1)
Antwoord 25
Als u alleen een nieuwe lege kolom moet maken, is de kortste oplossing:
df.loc[:, 'e'] = pd.Series()
Antwoord 26
Als we een scalerwaarde, bijvoorbeeld: 10, willen toewijzen aan alle rijen van een nieuwe kolom in een df:
df = df.assign(new_col=lambda x:10) # x is each row passed in to the lambda func
df heeft nu een nieuwe kolom ‘new_col’ met waarde=10 in alle rijen.
Antwoord 27
dit is een speciaal geval van het toevoegen van een nieuwe kolom aan een panda-dataframe. Hier voeg ik een nieuwe functie/kolom toe op basis van een bestaande kolomgegevens van het dataframe.
Dus, laat ons dataFrame kolommen ‘feature_1’, ‘feature_2’, ‘probability_score’ hebben en we moeten een nieuwe_column ‘predicted_class’ toevoegen op basis van gegevens in kolom ‘probability_score’.
Ik zal de functie map() van python gebruiken en ook een eigen functie definiëren die de logica implementeert voor het geven van een bepaald class_label aan elke rij in mijn dataFrame.
data = pd.read_csv('data.csv')
def myFunction(x):
//implement your logic here
if so and so:
return a
return b
variable_1 = data['probability_score']
predicted_class = variable_1.map(myFunction)
data['predicted_class'] = predicted_class
// check dataFrame, new column is included based on an existing column data for each row
data.head()
Antwoord 28
Telkens wanneer u een Series-object als nieuwe kolom aan een bestaande DF toevoegt, moet u ervoor zorgen dat beide dezelfde index hebben.
Voeg het dan toe aan de DF
e_series = pd.Series([-0.335485, -1.166658,-0.385571])
print(e_series)
e_series.index = d_f.index
d_f['e'] = e_series
d_f