Hoe om te gaan met SettingWithCopyWarning in Pandas?
Background
Ik heb zojuist mijn Pandas geupgrade van 0.11 naar 0.13.0rc1. Nu geeft de applicatie veel nieuwe waarschuwingen. Een van hen als deze:
E:\FinReporter\FM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
Ik wil weten wat het precies betekent? Moet ik iets veranderen?
Hoe moet ik de waarschuwing opschorten als ik erop sta om quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
te gebruiken?
De functie die fouten geeft
def _decode_stock_quote(list_of_150_stk_str):
"""decode the webpage and return dataframe"""
from cStringIO import StringIO
str_of_all = "".join(list_of_150_stk_str)
quote_df = pd.read_csv(StringIO(str_of_all), sep=',', names=list('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefg')) #dtype={'A': object, 'B': object, 'C': np.float64}
quote_df.rename(columns={'A':'STK', 'B':'TOpen', 'C':'TPCLOSE', 'D':'TPrice', 'E':'THigh', 'F':'TLow', 'I':'TVol', 'J':'TAmt', 'e':'TDate', 'f':'TTime'}, inplace=True)
quote_df = quote_df.ix[:,[0,3,2,1,4,5,8,9,30,31]]
quote_df['TClose'] = quote_df['TPrice']
quote_df['RT'] = 100 * (quote_df['TPrice']/quote_df['TPCLOSE'] - 1)
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
quote_df['TAmt'] = quote_df['TAmt']/TAMT_SCALE
quote_df['STK_ID'] = quote_df['STK'].str.slice(13,19)
quote_df['STK_Name'] = quote_df['STK'].str.slice(21,30)#.decode('gb2312')
quote_df['TDate'] = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])
return quote_df
Meer foutmeldingen
E:\FinReporter\FM_EXT.py:449: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TVol'] = quote_df['TVol']/TVOL_SCALE
E:\FinReporter\FM_EXT.py:450: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TAmt'] = quote_df['TAmt']/TAMT_SCALE
E:\FinReporter\FM_EXT.py:453: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_index,col_indexer] = value instead
quote_df['TDate'] = quote_df.TDate.map(lambda x: x[0:4]+x[5:7]+x[8:10])
530
3
De
SettingWithCopyWarning
is in het leven geroepen om potentieel verwarrende "chained" toewijzingen te markeren, zoals de volgende, die niet altijd werken zoals verwacht, vooral wanneer de eerste selectie een kopie oplevert. [zie GH5390 en GH5597 voor achtergrond discussie].De waarschuwing geeft een suggestie om als volgt te herschrijven:
Dit past echter niet in uw gebruik, dat gelijk is aan:
Hoewel het duidelijk is dat je er niet om geeft dat schrijfsels teruggaan naar het oorspronkelijke frame (omdat je de verwijzing ernaar overschreven hebt), kan dit patroon helaas niet onderscheiden worden van het eerste geketende toewijzingsvoorbeeld, vandaar de (vals-positieve) waarschuwing. Het potentieel voor vals-positieven wordt behandeld in de docs on indexing, als je'verder wilt lezen. Je kunt deze nieuwe waarschuwing veilig uitschakelen met de volgende opdracht.
In het algemeen is het punt van de
SettingWithCopyWarning
om gebruikers (en vooral nieuwe gebruikers) te laten zien dat ze misschien op een kopie werken en niet op het origineel zoals ze denken. Er zijn valse positieven (IOW als je weet wat je doet kan het goed zijn). Een mogelijkheid is om de (standaard waarschuwing) waarschuwing uit te schakelen zoals @Garrett voorstelt.Hier is een andere optie:
Je kunt de
is_copy
vlag opFalse
zetten, dat schakelt de controle uit, voor dat object:Als je expliciet kopieert dan zal er geen verdere waarschuwing plaatsvinden:
De code die de OP hierboven laat zien, is weliswaar legitiem, en waarschijnlijk iets wat ik ook doe, maar technisch gezien is het een geval voor deze waarschuwing, en geen vals-positief. Een andere manier om de waarschuwing niet te krijgen zou zijn om de selectie operatie via
reindex
te doen, bijv.Of,
Pandas dataframe kopieer waarschuwing
Als je zoiets als dit gaat doen:
pandas.ix
in dit geval geeft een nieuw, op zichzelf staand dataframe.Waarden die u in dit dataframe wijzigt, zullen het oorspronkelijke dataframe niet veranderen.
Dit is waar pandas je voor probeert te waarschuwen.
Waarom
.ix
een slecht idee isHet
.ix
object probeert meer dan één ding te doen, en voor iedereen die iets gelezen heeft over schone code, is dit een sterke geur.Gegeven dit dataframe:
Twee gedragingen:
Gedrag één:
dfcopy
is nu een op zichzelf staand dataframe. Het veranderen ervan zaldf
niet veranderenGedrag 2: Dit verandert het originele dataframe.
Gebruik
.loc
in plaatsDe pandas ontwikkelaars erkenden dat het
.ix
object nogal stonk [speculatief] en creëerden daarom twee nieuwe objecten die helpen bij het verkrijgen en toewijzen van gegevens. (De andere is.iloc
).loc
is sneller, omdat het niet probeert om een kopie van de gegevens te maken..loc
is bedoeld om je bestaande dataframe inplace aan te passen, wat geheugen efficienter is..loc
is voorspelbaar, het heeft één gedrag.The solution
Wat je in je codevoorbeeld doet, is een groot bestand met veel kolommen laden, en het dan verkleinen.
De
pd.read_csv
functie kan je hierbij helpen en ook het laden van het bestand een stuk sneller maken.Dus in plaats van dit te doen
Doe dan dit
Dit zal alleen de kolommen lezen waarin je geïnteresseerd bent, en ze de juiste naam geven. Het is niet nodig om het slechte
.ix
object te gebruiken om magische dingen te doen.