最近在寫個性化推薦的論文芹助,經(jīng)常用到Python來處理數(shù)據(jù)连霉,被pandas和numpy中的數(shù)據(jù)選取和索引問題繞的比較迷糊,索性把這篇官方文檔翻譯出來统抬,方便自查和學習冀宴,翻譯過程中難免很多不到位的地方灭贷,但大致能看懂,錯誤之處歡迎指正~
官方文檔鏈接 ? ?http://pandas.pydata.org/pandas-docs/stable/indexing.html
數(shù)據(jù)索引和選取
pandas對象中的軸標簽信息有很多作用:
? ? · 使用已知指標來標識數(shù)據(jù)(即提供元數(shù)據(jù))略贮,這對于分析氧腰、可視化以及交互式控制臺的顯示都十分重要
? ? · 使能夠?qū)崿F(xiàn)自動和顯式的數(shù)據(jù)對齊
? ? · 允許直觀地獲取和設置數(shù)據(jù)集的子集
在這一部分,我們將關注最終的目的:即如何切片刨肃,切丁以及一般地獲取和設置pandas對象的子集。文章將主要集中在Series和DataFrame上箩帚,因為它們在這方面潛力很大真友。
提示:Python和Numpy的索引操作“[ ]”和屬性操作“.”為pandas數(shù)據(jù)結(jié)構(gòu)提供了非常快速和簡便的方式紧帕。它們能給使交互工作更為直觀盔然,如果你已經(jīng)知道如何操作Python字典和Numpy數(shù)組的話桅打,那就沒什么新的東西可以學習了。然而愈案,由于數(shù)據(jù)的類型無法提前預知挺尾,直接使用標準操作將會有一些優(yōu)化的限制。對于產(chǎn)品代碼來說站绪,我們建議你可以利用本文展示的優(yōu)化的pandas數(shù)據(jù)使用方法遭铺。
警告:一個設置操作是會返回一個副本還是一個引用可能取決于具體情況。這種有時被稱為“鏈式賦值”恢准,我們應當避免這種情況魂挂。請參見返回視圖與副本。
警告:在0.18.0中對基于浮點的整數(shù)索引的變化進行了總結(jié)說明馁筐,請參見這里涂召。
多索引和更高級的索引文檔請參見多索引/高級索引。
一些先進的策略見菜譜敏沉。
多樣的索引方法
為了實現(xiàn)更簡便的基于位置的索引果正,對象選取方法添加了一些用戶的請求。pandas現(xiàn)在支持三種類型的多軸索引盟迟。
? .loc是最基本的基于標簽的索引秋泳,但是也可以用于布爾數(shù)組。當item無法找到時队萤,.loc將會產(chǎn)生KeyError轮锥。合法的輸入有:
? ? · 一個單獨的標簽,如5或“a”,(注意5是作為索引標簽要尔,而不是一個整數(shù)的位置索引)
? ? · 一個列表或者數(shù)組標簽[“a”,”b”,”c”]
? ? · 一個帶有標簽“a”:“f”的切片對象(注意舍杜,與Python切片相反,這種切片的第一個和最后一個都包含在內(nèi)赵辕!請參見標簽切片既绩。)
? ? · 一個布爾數(shù)組
? ? · 一個可調(diào)用的函數(shù)(調(diào)用Series, DataFrame或Panel)并返回索引的有效輸出(上面中的一個)
更多的基于標簽選取。
? .iloc主要是基于整數(shù)位置的索引(從軸的第0位到第length-1位)还惠,但是也可以用于布爾數(shù)組饲握。除了允許超范圍索引的索引器之外,如果一個請求的索引超出了索引范圍蚕键,.iloc將會產(chǎn)生IndexError救欧。合法的輸入有:
? ? · 一個整數(shù)。如5
? ? · 一個列表或整數(shù)數(shù)組锣光。如[4,3,0]
? ? · 一個整型的切片對象笆怠,如1:7
? ? · 一個布爾數(shù)組
? ? · 一個可調(diào)用的函數(shù)(調(diào)用Series, DataFrame或Panel)并返回索引的有效輸出(上面中的一個)
? .loc, .iloc和[ ]索引能夠接受一個可調(diào)用對象作為索引器蹬刷。更多請參見基于可調(diào)用對象的選取瓢捉。
使用以下標記從一個多軸對象中獲取值(使用.loc為例,但同樣適用于.iloc)办成。任何的軸訪問器都可能是空的切片:假定不規(guī)范的軸泡态。(如p.loc[‘a(chǎn)’]等價于p.loc[‘a(chǎn)’,:,:])
基礎知識
正如在上一章節(jié)中介紹數(shù)據(jù)結(jié)構(gòu)中所提到的那樣,使用[ ]進行索引的主要功能(相當于Python中的__getitem__)是選取出低維切片迂卢。下面的表顯示了使用[ ]索引pandas對象時返回值的類型:
對象類型 ? ? ? ? ? ? ? ? 選取 ? ? ? ? ? ? ? ? ? ?返回值類型
Series ? ? ? ? ? ? ? ?series[label] ? ? ? ? ? ? 標量值
DataFrame ? ? ? ?frame[colname] ? ? ? 對應colname的Series
Panel ? ? ? ? ? ? ? ? ?panel[itemname] ? ? 對應itemname的DataFrame
這里我們構(gòu)建了一個簡單的時間序列數(shù)據(jù)集來說明索引功能:
注意:除非特殊說明某弦,所有的索引功能都是通用的,不只適用于該時間序列冷守。
因此刀崖,根據(jù)上述,我們使用[ ]能夠?qū)崿F(xiàn)最基本的索引:
你可以向[ ]中傳遞列的列表來按照順序選取多列拍摇。如果某列不在DataFrame中亮钦,將引發(fā)一個異常。也可以通過這種方式設置多個列充活。
當將這種變換就地應用到列的子集的時候蜂莉,你可能會發(fā)現(xiàn)這個方法的有用之處。
警告:當從.loc, .iloc設置Series和DataFrame時混卵,pandas會將所有軸對齊映穗。
這不會改變df,因為在賦值之前就進行了列對齊。
正確的做法是使用原始值
屬性訪問
你或許能夠直接把Series的index幕随,一個DataFrame的column蚁滋,一個Panel的item作為一種屬性來訪問。
警告:
· 只有當索引元素是一個有效的Python標識符時才能使用這種方式進行訪問赘淮,比如s.1就不可以辕录。請參照關于有效標識符的解釋。
·?如果屬性和現(xiàn)存的方法名沖突的話梢卸,這種方式也不可行走诞。如s.min
·?同樣,如果屬性名和任意一個如下的名字沖突的話也不可行:index蛤高,major_axis, minor_axis, items蚣旱。
·?無論哪種情況,標準的索引總是可行的戴陡,如s[“1”], s[“min”]和s[“index”]都能夠訪問相應的元素或列塞绿。
如果你使用的是IPython的環(huán)境,你也可以使用tab-完成鍵來查看這些訪問屬性恤批。
你也可以向一個DataFrame的一行分配一個dict异吻。
你可以使用屬性訪問來修改一個Series或DataFrame的一個列中已有的元素,但是要謹慎操作开皿;如果你試圖使用屬性訪問來創(chuàng)建一列的話涧黄,它將會創(chuàng)建一個新的屬性,而不是新列赋荆。在0.21.0和之后的版本里笋妥,該操作將會報出UserWarning:
切片范圍
在沿任意軸的切片方法中,魯棒性和一致性最強的方法是在使用位置選擇部分詳細介紹的.iloc方法≌叮現(xiàn)在春宣,我們介紹一下使用[ ]操作進行切片的語法。
對于Series來說嫉你,這個語法對應的就是ndarray月帝,返回的是值的切片和相關的標簽:
需要注意的是設置操作也是如此:
對于DataFrame來說,在[ ]中的切片是對行的操作幽污。由于它的普適性嚷辅,所以這樣非常方便。
使用標簽選擇
警告:對于一個設置操作距误,是返回一個副本還是引用取決于當時的上下文簸搞。這叫做“鏈式賦值”,這種情況應當避免准潭。請參見返回視圖與副本趁俊。
警告:當你的切片器與索引類型不兼容(或不可轉(zhuǎn)換)時,.loc是非常嚴格的刑然。例如在一個DatatimeIndex中使用整數(shù)的話寺擂,將會引發(fā)一個TypeError。
在切片中的string能夠轉(zhuǎn)換為index的類型泼掠,這樣才能正常切片怔软。
警告:從0.21.0版本開始,如果使用帶有缺失值的進行索引的話武鲁,pandas將會顯示一個FurtherWarning爽雄。在未來的版本中將會引發(fā)KeyError。詳見不推薦使用缺失的列表進行索引沐鼠。
pandas提供了一系列的方法來基于標簽進行索引挚瘟。這是一個嚴格基于包的協(xié)議。所有請求的標簽都需要確實存在于索引中饲梭,不然就會引發(fā)一個KeyError乘盖。切片范圍的第一個和最后一個都被包含在內(nèi)。整數(shù)是有效的標簽憔涉,但是他們必須作為標簽而不是位置订框。
.loc屬性是基礎的訪問方法。下面的是有效的輸入:
? ? · 一個單獨的標簽兜叨,如5或“a”,(注意5是作為索引標簽穿扳,而不是一個整數(shù)的位置索引)
? ? · 一個列表或者數(shù)組標簽[“a”,”b”,”c”]
? ? · 一個帶有標簽“a”:“f”的切片對象(注意衩侥,與Python切片相反,這種切片的第一個和最后一個都包含在內(nèi)C铩)
? ? · 一個布爾數(shù)組
? ? · 一個可調(diào)用對象茫死,詳見基于可調(diào)用對象的選取。
要注意的是設置操作也同樣適用:
對于一個DataFrame來說:
通過標簽切片訪問:
使用一個標簽來獲取截取部分(相當于df.xs(“a"))
使用一個布爾型數(shù)組獲取值
直接獲取值(相當于過時的df.get_value(“a”,”A”))
# 等價于 ``df1.at['a','A']`
使用標簽選擇
當時用.loc進行切片時履羞,如果當前索引中包含了開始標簽和結(jié)束標簽峦萎,那么將返回位于這兩個標簽中的元素(包括這兩個端點):
如果缺失了至少其中一個標簽,但是索引被排序了忆首,并且能夠與開始和結(jié)束標簽進行比較爱榔,那么通過選擇在兩個之間排序的標簽,切片將仍然按預期進行:
然而糙及,如果缺失了至少一個標簽并且索引已經(jīng)被排序详幽,將會引發(fā)一個錯誤(因為這樣做在計算上是昂貴的,而且對于混合型索引可能是不明確的)比如丁鹉,在上面的例子中妒潭,s.loc[2:6]將會引發(fā)一個KeyError。
使用位置選擇
警告:對于一個設置操作揣钦,是返回一個復制還是引用取決于當時的上下文雳灾。這叫做“鏈式賦值”,這種情況應當避免冯凹。詳見返回一個視圖vs副本谎亩。
pandas提供了一系列的方法來獲得純粹的基于整數(shù)的索引。該語法遵循Python和numpy切片方法宇姚。這些是0-based索引匈庭。切片時,包含范圍內(nèi)的第一個浑劳,而不包含最后一個阱持。如果試圖使用非整數(shù),即使是一個有效的標簽也將會引發(fā)一個IndexError魔熏。
.loc屬性是基礎的訪問方法衷咽。下面的是有效的輸入:
? ? · 一個單獨的標簽,如5
? ? · 一個列表或者整數(shù)數(shù)組[4蒜绽,3镶骗,0]
? ? · 一個帶有整數(shù)的切片對象1:7
? ? · 一個布爾數(shù)組
? ? · 一個可調(diào)用的函數(shù),詳見通過可調(diào)用對象選擇躲雅。
要注意的是設置操作也同樣如此:
對于一個DataFrame來說:
通過整數(shù)切片來選擇:
通過整數(shù)列表來選擇:
使用一個整數(shù)位置來獲取一個截取部分(相當于df.xs(1))
正如在Python或Numpy中那樣鼎姊,超出索引范圍的切片也是被允許的。
注意,超出范圍進行切片將會導致一個空軸(如返回一個空的DataFrame)
一個單獨的超出范圍的索引器將會引發(fā)IndexError. 一個其元素超出了索引范圍的索引列表也會引發(fā)IndexError相寇。
使用可調(diào)用函數(shù)來選擇
.loc, .iloc和[ ]索引都可以接收一個可調(diào)用函數(shù)作為索引慰于。這個可調(diào)用函數(shù)必須是有一個參數(shù)的函數(shù)(Series, DataFrame或者Panel),并為索引返回有效的輸出。
你可以在Series中使用可調(diào)用函數(shù)
使用這種方法/索引時唤衫,你可以不用臨時變量就能夠進行數(shù)據(jù)選擇操作东囚。
.IX已被禁用
從0.20.0版本開始,禁用.IX索引器战授,使用更為嚴謹?shù)?iloc和.loc索引器將其取代。
使用缺失的列表進行索引的功能已被禁用
從0.20.0版本開始桨嫁,使用.loc或[]來索引帶有一個或多個缺失標簽的列表的功能被禁用植兰,在新版本中使用.reindex()替代。
重新索引
對可能找不到的元素進行索引的慣用方法是.reindex()璃吧。詳見重新索引部分楣导。
或者,如果你只想要選擇有效鍵畜挨,下面的方法是慣用且有效的筒繁,它能保證保留選擇的dtype。
a.reindex()將會重復索引:
通常巴元,您可以使用當前軸交叉所需標簽毡咏,然后重新索引。
然而逮刨,如果生成的索引被復制的話呕缭,將仍舊引發(fā)警告。
隨機樣本的選擇
從一個Series或DataFrame或Panel的行或列中使用sample()方法來選擇隨機樣本修己。這個方法默認是對列進行取樣恢总,并接收一個特定的行/列返回,或者行的一部分睬愤。
默認情況下片仿,sample方法將會使每行最多返回一次,但是你也可以使用替換選項進行替換:
默認情況下尤辱,每行被取樣的概率是相等的砂豌,但是如果你想讓每行有不同的概率被抽到,你可以講抽樣權(quán)重作為權(quán)重來傳遞給抽樣函數(shù)啥刻。這些權(quán)重可以是一個列表奸鸯,一個numpy數(shù)組或者一個Series,但是他們的長度必須和你抽樣的對象的長度一致可帽。缺失值的權(quán)重將被設為0娄涩,inf值不被允許。如果所有權(quán)重的和不為1,他們將使用各權(quán)重除以目前權(quán)重的和進行重新歸一化蓄拣。例如:
對于一個DataFrame來說扬虚,你可以使用一個DataFrame的一列作為抽樣權(quán)重(假設你正在對行進行抽樣而不是列),把列名作為一個字符串傳進去就可以球恤。
sample還允許用戶使用軸參數(shù)來對列進行抽樣.
最后辜昵,你還可以使用random_state參數(shù)來為sample的隨機數(shù)生成器設置一個種子,它將會接收一個整數(shù)或者一個numpy RandomState 對象咽斧。
使用擴展來設置
當為一個軸設置一個不存在的鍵值時堪置,.loc[ ]操作可以進行擴容。
在Series中张惹,這其實是一個追加操作舀锨。
一個DataFrame可以通過.loc或軸進行擴容
這就像是DataFrame的一個追加操作。
標量值的快速獲取和設置
由于使用[ ]進行索引必須管理很多情況(單標簽訪問宛逗,切片坎匿,布爾索引等等),它會花費一些性能來識別你究竟請求的是什么雷激。如果你想要訪問一個標量替蔬,最快速的方法是使用at和iat方法,他們能夠適用于所有數(shù)據(jù)結(jié)構(gòu)屎暇。
與loc類似承桥,at提供基于標簽的標量查找纽窟,而iat提供基于整數(shù)的標量查找(與iloc類似)彻犁。
你也可以使用同樣的索引進行設置
如果索引缺失的話玫霎,at方法可對對象進行原地擴充
布爾索引
另一個常見的操作是使用布爾向量來過濾數(shù)據(jù)粟耻。操作是:|對應或沾瓦,&對應與僧家,~對應非澳泵。這些必須使用括號進行分組性湿。由于Python默認df.A?>?2?&?df.B?<?3 等同于 df.A?>?(2?&?df.B)?<?3玄柏,但我們所需的其實是(df.A?>?2)?&?(df.B?<?3)襟衰。
使用一個布爾向量來對一個Series進行索引與對一個numpy的多維數(shù)組進行索引是一樣一樣的:
你可以使用一個與DataFrame的index相同長度的布爾向量從一個DataFrame中選擇列(例如,一些來自DataFrame的一列的東西)
Series的list和map方法也可以用來產(chǎn)生更為復雜的匹配標準:
使用布爾向量和其他索引表達式共同索引時粪摘,使用選擇方法 通過標簽選擇瀑晒,通過位置選擇和先進索引,你可能會選出不只一個軸的數(shù)據(jù)徘意。
使用isin索引
Series的 isin()方法能夠返回一個布爾向量苔悦,Series的元素在傳遞列表的地方顯示為True。這使你能夠選擇那些一列或多列中有你需要的值的行椎咧。
該方法同樣適用于Index對象玖详,當你不知道哪個標簽是真的存在的時候把介,這種方法也同樣適用。
另外蟋座,MultiIndex方法能夠允許選取一個單獨的level來用于成員資格審查:
DataFrame也有isin方法拗踢。當使用isin時,需要傳入一個值的集合向臀,數(shù)組或字典都可以巢墅。如果是數(shù)組,isin返回一個布爾型的DataFrame券膀,它和原DataFrame的大小一樣君纫,而且元素在值序列中的地方顯示為True.
通常情況下,你會想要使用特定的列來匹配特定的值芹彬。只需要使值成為一個dict庵芭,其key是列,value是你想要檢索的item列表即可雀监。
將DataFrame的isin方法和any( )和all( )方法混合起來以一個給定的標準快速選擇你的數(shù)據(jù)的子集。選擇一行數(shù)據(jù)眨唬,它的每一列都有各自的標準:
where( )方法和偽裝
使用一個布爾向量從一個Series中選取值通常會返回一個數(shù)據(jù)的子集会前。為了保證選取的輸出與源數(shù)據(jù)有相同的規(guī)模,你可以使用Series和DataFrame中的where方法匾竿。
只返回選取的行:
返回一個與源數(shù)據(jù)具有相同規(guī)模的Series
從一個DataFrame中選取值也能保留輸入數(shù)據(jù)的規(guī)模瓦宜。在底層使用where作為實現(xiàn)。下面的代碼等價于df.where(df<0)
另外岭妖,在返回的復制數(shù)據(jù)中临庇,where需要一個可選的其他參數(shù)來當條件為假時進行替換。
你或許想要基于一些布爾標準來設置值昵慌。這能夠直觀地這樣做:
默認情況下假夺,where將會返回一個數(shù)據(jù)的修改副本。有一個可選擇的參數(shù)inplace斋攀,它能夠在源數(shù)據(jù)上直接修改已卷,而不產(chǎn)生一個副本。
注意:DataFrame.where()和numpy.where()的識別標志不同淳蔼。大體上侧蘸,df1.where(m,?df2)等價于np.where(m,?df1,?df2).
校準
與此同時,where使輸入的環(huán)境對齊(ndarray 或DataFrame)鹉梨,因此部分選擇與設置是可能的讳癌。這與使用.ix進行部分設置相似(但是在內(nèi)容上倒不如軸標簽)
在使用where時,where也可以接收axis和level參數(shù)來使輸入對齊存皂。
這個方法與下面的方法相同晌坤,但是比下面的快。
where能夠接收一個可調(diào)用函數(shù)作為條件和其他參數(shù)。這個函數(shù)必須有一個參數(shù)(Series 或者 DataFrame)泡仗,并返回有效的輸出作為條件或其他參數(shù)埋虹。
偽裝
mask() 是where的逆布爾運算。
query()方法
DataFrame對象有一個query()方法能夠允許使用一個表達式來選取數(shù)據(jù)娩怎。
你可以獲取到frame中列b中介于列a和列c之間的值搔课,例如:
如果沒有名為a的列,這樣做的話將會把操作作用于一個命了名的index截亦。
如果你不想或不能為你的index命名爬泥,你可以在你的query表達式中使用“index”這個名字崩瓤。
注意: 如果你的index的名字和一個列名相同,那列名將會被賦予優(yōu)先值趁啸。如:
即使index已經(jīng)命名了辞友,你還是可以在query表達式中使用“index”這個名字對index列進行使用:
如果由于某些原因你有一列名為index疫向,那么你可以使用ilevel_0來使用index,但是這時你最好應該考慮給你的列換個名字舵鳞。
MultiIndex的query( ?)語法
你也可以把MultiIndex和一個DataFrame的levels當做frame中的列進行使用。
如果MultiIndex的levels未命名,你可以使用特殊名字來使用它們:
慣例是level_0眉孩,它意味著為index的第0level“索引level0”
query( ?)使用示例
一個query()的使用示例是凯旋,當你有一個有著共同列名(或索引level/名稱)的子集DataFrame的對象集舰蟆,你可以向所有frame傳遞相同的query界赔,而不用指定哪個frame是你要查詢的损痰。
query()Python與pandas語法比較
完全的numpy形式的語法
去掉括號會更好一點 (通過綁定比較操作符&/|)
使用英語來代替符號
可能和你在紙上寫的非常相近
in 和 not?in 操作
在比較操作中卢未,query()也支持Python的特殊用法in和not in肪凛,為調(diào)用isin方法提供了一個簡潔的語法。
你可以將這種方法和其他表達式混合來實現(xiàn)非常簡潔的查詢:
# 列a和列b有重復值且列c的值小于列d的值的所有行
注意:in和not in在Python中進行了評估辽社,因為numexpr沒有與該操作相等的操作伟墙。然而,只有表達式中的in和not in自身在普通Python中被評估了滴铅。例如远荠,在表達式
df.query('a in b + c + d')
(b?+?c?+?d)通過numexpr進行評估,然后in操作就在普通Python評估了失息。通常來說譬淳,任何能夠使用numexpr評估的操作都是這樣档址。
==操作和list對象的特殊用法
使用==/!=對一列數(shù)值進行比較和in/not in的機制是相似的
布爾操作
你可以使用not或~操作來否定布爾表達式
當然,表達式也可以變得任意復雜:
query()的性能
對于大型frame來說邻梆,DataFrame.query()使用numexpr比Python快一些
注意: 當你的frame超過200守伸,000行時DataFrame.query()的快速才能體現(xiàn)出來
這個圖表是使用numpy.random.randn()生成的3列浮點值生成的.
重復數(shù)據(jù)
如果你想要識別并刪除一個DataFrame中的重復行,有兩種方法:duplicated和drop_duplicates浦妄。每種都需要傳入一個列參數(shù)來識別重復行尼摹。
· duplicated返回一個布爾向量,該向量的長度是行數(shù)剂娄,且它會指出每一行是不是重復行
· drop_duplicates會刪除重復行
默認情況下蠢涝,幾個重復行的第一行會被留下,但是每種方法都有一個keep參數(shù)來決定要留下哪一行阅懦。
· keep='first'(默認): 將第一行視為非重復行并留下
· keep='last':將最后一行視為非重復行并留下
· keep=False: 刪除所有行/將所有行都標記為重復行
同樣和二,你可以傳入一個列來識別特定重復行
使用index.duplicated然后進行切片可以根據(jù)index的值去重。keep參數(shù)在這個方法中同樣適用耳胎。
類似于字典的get( )方法
Series, DataFrame, 和 Panel都有一個get方法能夠返回一個默認值
lookup( ?)方法
有些時候你想要按照某種特定順序來獲取行或列惯吕,那么lookup方法就能夠?qū)崿F(xiàn),并返回一個numpy數(shù)組怕午。例如废登,
索引對象
pandas的Index類和它的子類可以被視為實施一個有序的多集,允許重復郁惜。然而堡距,如果你試圖將一個有重復項的索引對象轉(zhuǎn)換為一個集合,將會引發(fā)一個異常兆蕉。
Index還為查找羽戒、數(shù)據(jù)規(guī)整和重新索引提供了必要的基礎。創(chuàng)建一個Index的最簡單的方式是向Index傳遞一個list或其他的序列恨樟。
你也可以給index起個名字半醉,并存儲在索引中:
如果名字是個集合疚俱,將會在控制臺顯示:
設置元數(shù)據(jù)
索引“大部分是不可變的”劝术,但是設置和改變他們的元數(shù)據(jù)卻是可能的,比如索引名(或者呆奕,對于MultiIndex來說养晋,level和標簽)
你可以使用rename,set_name ,set_levels set_labels來直接設置這些屬性梁钾。它們默認返回一個副本绳泉,然而,你可以令關鍵字inplace=True來使數(shù)據(jù)直接原地改變姆泻。
詳見MultiIndexes的Advanced Indexing用法零酪。
set_names,set_levels, 和set_labels也有一個可選參數(shù)level:
Index對象的設置操作
兩個主要的操作是union?(|)和intersection?(&)冒嫡。它們可以作為實例方法被直接調(diào)用或通過重載操作使用。Difference 是由.difference()方法實現(xiàn)的四苇。
symmetric_difference?(^)操作也同樣能用孝凌,它能夠返回idx1或idx2中出現(xiàn)的元素,但不能二者都返回月腋。這等價于使用idx1.difference(idx2).union(idx2.difference(idx1))來創(chuàng)建索引蟀架,沒有重復項。
注意:從集合操作中得到的索引將升序排列榆骚。
缺失值
重要: 雖然Index能夠保留缺失值(NaN)片拍,但如果你不想出現(xiàn)什么亂七八糟的結(jié)果,最好還是避免缺失值妓肢。例如捌省,有些操作會隱性地直接排除缺失值。
Index.fillna能夠使用指定值來填充缺失值职恳。
設置/重置索引
有時候你會向一個DataFrame中加載或創(chuàng)建一個數(shù)據(jù)集所禀,并給這個后來加入的數(shù)據(jù)子集加上索引。有以下幾種方法:
設置索引
DataFrame有一個set_index方法放钦,能夠接收一個列名(對于常規(guī)Index來說)或一個列名list(對于MutiIndex來說)來創(chuàng)建一個新的色徘,帶有索引的DataFrame:
關鍵字append能夠使你保留當前index,并把給定的列追加到一個MultiIndex中:
set_index中的其他選項能夠使你保留索引列或者原地加上索引操禀,而不用創(chuàng)建一個新的對象褂策。
重置索引
考慮到方便性,DataFrame有一個新的功能叫做reset_index颓屑,它能夠把index值轉(zhuǎn)換為DataFrame的列并設置一個簡單的整數(shù)索引斤寂。它是set_index()的逆運算。
輸出的結(jié)果更像是一個SQL表或一個數(shù)組記錄揪惦。來自index的列名被存儲在names屬性里遍搞。
你可以使用level關鍵字來移除index的一部分。
reset_index有一個可選參數(shù)drop器腋,當drop=True時會直接丟棄index溪猿,而不是將index值放在DataFrame的列中。
添加ad hoc索引
如果你自己創(chuàng)建了一個index纫塌,你可以將它分配到索引字段
data.index = index
返回視圖vs副本
在一個pandas對象中設置值時诊县,必須小心避免鏈式索引的出現(xiàn)。示例如下:
比較一下這兩個訪問方法:
這兩種方法產(chǎn)生的結(jié)果一樣措左,所以你該用哪一種依痊?了解它們的操作順序、了解為什么第二種方法(.loc)比第一種好得多怎披,是非常有意義的胸嘁。
dfmi?[“one”] 選取了列的第一個level瓶摆,并返回一個單獨索引的DataFrame,另一個Python操作ddmi_with_one[“second”]選取“second”索引的Series性宏。這由可變的dfmi_with_one來指示赏壹,因為pandas把這些操作視為獨立事件。例如對__getitem__的單獨調(diào)用衔沼,所以它必須把他們作為線性運算蝌借,他們一個接一個地發(fā)生。
相反指蚁,df菩佑。loc[:,(“one”,”second”)]向單獨調(diào)用的__getitem__傳入了一個嵌套元組(slice(None),('one','second’)).這能夠使pandas把它們作為一個單一的實體進行處理。此外凝化,這個操作命令比第一種方法要快得多稍坯,并且如果需要的話,還能夠允許同時索引多個軸搓劫。
為什么使用鏈式索引進行分配時會報錯瞧哟?
前面部分的問題僅僅是性能問題。為什么會有SettingWithCopy警告枪向?當你的操作會多花費不必要的幾毫秒時勤揩,我們通常不會報出警告!
但是事實證明秘蛔,鏈式索引會導致不可預知的結(jié)果陨亡。要了解這一點,想想Python解釋器如果執(zhí)行這個代碼的:
但這個代碼的處理方式是完全不同的:
看到這里的__getitem__了嗎深员?除了一些簡單的情況之外负蠕,我們很難預測它到底會返回一個視圖還是一個副本(這取決于數(shù)組的內(nèi)存布局,pandas可不能保證這個)倦畅,也不能預測__setitem__是將會直接修改dfmi還是修改一個用完即扔的臨時對象遮糖。這也是SettingWithCopy在警告你的東西!
注意:你可能會想在第一個例子中我們是否應該考慮到loc的特性叠赐。但是我們能肯定在修改索引時欲账,dfmi.loc是dfmi自身,所以dfmi.loc.__getitem__/dfmi.loc.__setitem__操作是直接作用在dfmi自身上的燎悍。當然敬惦,dfmi.loc.__getitem__?(idx)或許是dfmi的一個視圖或副本盼理。
有些時候谈山,當沒有明顯的鏈式索引時,SettingWithCopy警告也會產(chǎn)生宏怔。這是SettingWithCopy的一些設計上的bug奏路,pandas可能會試著發(fā)出警告畴椰,如果你這樣做的話:
def do_something(df):
foo = df[['bar', 'baz']]? # foo是一個視圖還是副本,沒人知道啊!
#許多行在此省略
foo['quux'] = value? ? ? # 我們不知道這個操作到底有沒有修改到df案敕邸斜脂!
return foo
唉!真無奈按セ帚戳!
評估事項
當你使用鏈式索引時,索引操作的命令和類型將部分決定是返回原始對象里的一個切片還是該切片的副本儡首。
Pandas具有設置警告的功能片任,因為分配給切片的副本常常并非本意,而是由鏈式索引而引起的錯誤蔬胯。
如果你想讓Pandas或多或少相信鏈式索引表達式的任務对供,你可以通過選項mode.chained_assignment來控制一個鏈式分配:
· “warn”,默認選項氛濒,表示打印了一個帶有警告的設置产场;
· “raise”,表示Pandas將會引發(fā)一個你必須處理的SettingWithCopyException舞竿;
· 無法完全阻止這個警告京景。
# 這將會引發(fā)SettingWithCopyWarning
# 但是frame的值確實被設置了
然而這是在副本上的操作,并木有什么卵用骗奖。
一個鏈式分配也可以在設置一個混合類型的frame時讓人猝不及防地出現(xiàn)醋粟。
注意: 這些設置規(guī)則對.loc/.iloc通用
這才是正確的訪問方法:
下面的方法有時能夠正常使用,但不能保證任何時候都正常重归,所以應該避免使用:
下面的方法是錯的米愿,所以別用啊
警告:鏈式分配警告/異常是為了把可能無效的分配告知用戶。有時候有可能是誤報鼻吮。