第九章 分類數(shù)據(jù)

整章知識架構(gòu)

一辽故、cat對象

cat對象

cat對象屬性

  • 類別本身,通過Index類型存儲
  • 是否有序, 通過的cat屬性訪問
s.cat.categories
s.cat.ordered
s.cat.codes #編號

類別的增刪改

s = s.cat.add_categories('Graduate') # 增加一個(gè)畢業(yè)生類別
s = s.cat.remove_categories('Freshman')
s = s.cat.set_categories(['Sophomore','PhD']) # 新類別為大二學(xué)生
和博士
s = s.cat.remove_unused_categories() # 移除了未出現(xiàn)的博士生類別
s = s.cat.rename_categories({'Sophomore':'本科二年級學(xué)生'})

二、有序分類

有序分類

序的建立

  • 通過s.cat.as_ordered()可以將類別轉(zhuǎn)化為有序曙旭,有序類別和無序類別可以通過as_unorderedreorder_categories互相轉(zhuǎn)化
s = df.Grade.astype('category')
s = s.cat.reorder_categories(['Freshman', 'Sophomore', 'Junior', 'Senior'],ordered=True)
s.head()
s.cat.as_unordered().head()

排序和比較

  • 有序的類別可以使用sort_indexsort_values進(jìn)行排序
  • 也可以是使用比較運(yùn)算符進(jìn)行比較,主義在使用大小比較時(shí)比較的對象必須存在category中晶府,不然無法比較

三桂躏、區(qū)間類別

區(qū)間類別

cut和qcut

  • cut:可以指定分割區(qū)間的數(shù)量或者通過list指定端點(diǎn)值
pd.cut(s, bins=2, right=False)
pd.cut(s, bins=[-np.infty, 1.2, 1.8, 2.2, np.infty])
  • qcut:可以指定分位等分的數(shù)量或者通過list指定端點(diǎn)值(分位數(shù))
pd.qcut(s, q=3)
pd.qcut(s, q=[0,0.2,0.8,1])

二者皆可使用labels指定區(qū)間名稱

區(qū)間的構(gòu)造

  • 通過pd.Interval構(gòu)造, 指定左右端點(diǎn)和閉合開閉狀態(tài)
my_interval = pd.Interval(0, 1, 'right')
  • 通過pd.IntervalIndex構(gòu)造
    • 從cut或者qcut的結(jié)果轉(zhuǎn)換
    • from_breaks
    • from_arrays
    • from_tuples
    • interval_range
id_interval = pd.IntervalIndex(pd.cut(s, 3))
pd.IntervalIndex.from_breaks([1,3,6,10], closed='both')
pd.IntervalIndex.from_arrays(left = [1,3,6,10], right = [5,4,9,11], closed = 'neither')
pd.IntervalIndex.from_tuples([(1,5),(3,4),(6,9),(10,11)], closed='neither')
pd.interval_range(start=1,end=5,periods=8)

【練一練】

無論是interval_range還是下一章時(shí)間序列中的date_range都是給定了等差序列中四要素中的三個(gè),從而確定整個(gè)序列川陆。請回顧等差數(shù)列中的首項(xiàng)剂习、末項(xiàng)、項(xiàng)數(shù)和公差的聯(lián)系较沪,寫出interval_range中四個(gè)參數(shù)之間的恒等關(guān)系鳞绕。

(end - start) / freq == periodes

區(qū)間的屬性與方法

  • overlaps:判斷是否有交集
id_demo.overlaps(pd.Interval(40,60))
  • contains: 判斷區(qū)間是否含有某個(gè)元素
id_demo.contains(4)
  • 屬性:
    • left
    • right
    • mid
    • length
id_demo.left
id_demo.right
id_demo.mid
id_demo.length

四、練習(xí)

Ex1:統(tǒng)計(jì)未出現(xiàn)的類別

在第五章中介紹了crosstab函數(shù)尸曼,在默認(rèn)參數(shù)下它能夠?qū)蓚€(gè)列的組合出現(xiàn)的頻數(shù)進(jìn)行統(tǒng)計(jì)匯總:

df = pd.DataFrame({'A':['a','b','c','a'], 'B':['cat','cat','dog','cat']})
pd.crosstab(df.A, df.B)

但事實(shí)上有些列存儲的是分類變量们何,列中并不一定包含所有的類別,此時(shí)如果想要對這些未出現(xiàn)的類別在crosstab結(jié)果中也進(jìn)行匯總控轿,則可以指定dropna參數(shù)為False
請實(shí)現(xiàn)一個(gè)帶有dropna參數(shù)的my_crosstab函數(shù)來完成上面的功能冤竹。

構(gòu)造s1與s2的dataframe, 將s1.name作為index茬射,索引出相關(guān)的行鹦蠕,然后使用==計(jì)算與s2.name相等的元素的個(gè)數(shù)

def my_crosstab(s1, s2, dropna=True):
    columns = s2.cat.categories[s2.cat.categories.isin(s2)]
    table = pd.concat([s1,s2], axis=1).set_index(s1.name)
    if dropna:
        _columns = columns
    else:
        _columns = s2.cat.categories
    ret = pd.DataFrame(index=index, columns=_columns, data=np.zeros((len(index), len(_columns))))
    res = res.rename_axis(index=s1.name, columns=s2.name).astype('int')
    for idx in index:
        content = table.loc[idx]
        for c in columns:
            ret.loc[idx, c] = (content == c).values.sum()
    return ret
my_crosstab(s1, s2, dropna=False)
result

Ex2:鉆石數(shù)據(jù)集

現(xiàn)有一份關(guān)于鉆石的數(shù)據(jù)集,其中carat, cut, clarity, price分別表示克拉重量躲株、切割質(zhì)量片部、純凈度和價(jià)格,樣例如下:

df = pd.read_csv('../data/diamonds.csv') 
df.head(3)
  1. 分別對df.cutobject類型和category類型下使用nunique函數(shù)霜定,并比較它們的性能档悠。
  2. 鉆石的切割質(zhì)量可以分為五個(gè)等級,由次到好分別是Fair, Good, Very Good, Premium, Ideal望浩,純凈度有八個(gè)等級辖所,由次到好分別是I1, SI2, SI1, VS2, VS1, VVS2, VVS1, IF,請對切割質(zhì)量按照由好到次的順序排序磨德,相同切割質(zhì)量的鉆石缘回,按照純凈度進(jìn)行由次到好的排序吆视。
  3. 分別采用兩種不同的方法,把cut, clarity這兩列按照由好到次的順序酥宴,映射到從0到n-1的整數(shù)啦吧,其中n表示類別的個(gè)數(shù)。
  4. 對每克拉的價(jià)格按照分別按照分位數(shù)(q=[0.2, 0.4, 0.6, 0.8])與[1000, 3500, 5500, 18000]割點(diǎn)進(jìn)行分箱得到五個(gè)類別Very Low, Low, Mid, High, Very High拙寡,并把按這兩種分箱方法得到的category序列依次添加到原表中授滓。
  5. 第4問中按照整數(shù)分箱得到的序列中,是否出現(xiàn)了所有的類別肆糕?如果存在沒有出現(xiàn)的類別請把該類別刪除般堆。
  6. 對第4問中按照分位數(shù)分箱得到的序列,求每個(gè)樣本對應(yīng)所在區(qū)間的左右端點(diǎn)值和長度诚啃。

根據(jù)結(jié)果可知淮摔, category類型速度略快

# 性能測量
%timeit -n 100 df.cut.nunique()
cat = df.cut.astype('category')
%timeit -n 100 cat.nunique()
performance

轉(zhuǎn)換為category類型后使用reorder_categories轉(zhuǎn)換成有序類型排序即可

df.cut = df.cut.astype('category').cat.reorder_categories(['Fair', 'Good', 'Very Good', 'Premium', 'Ideal'])
df.clarity = df.clarity.astype('category').cat.reorder_categories(['I1', 'SI2', 'SI1', 'VS2', 'VS1', 'VVS2', 'VVS1', 'IF'])
df.sort_values(['cut', 'clarity'], ascending=[False, True]).head()
result

利用cat.code或者replace

df.cut = df.cut.cat.reorder_categories(df.cut.cat.categories[::-1])
df.clarity = df.clarity.cat.reorder_categories(df.clarity.cat.categories[::-1])
df.cut = df.cut.cat.codes # 方法一:利用cat.codes
clarity_cat = df.clarity.cat.categories
df.clarity = df.clarity.replace(dict(zip(clarity_cat, np.arange(len(clarity_cat))))) # 方法二:使用replace映射

使用qcut和cut,注意的是對區(qū)間進(jìn)行補(bǔ)全始赎,使其正確地分為5個(gè)區(qū)間

pricePerCarat = df.price / df.carat
type1 = pd.qcut(pricePerCarat, q=[0, 0.2, 0.4, 0.6, 0.8, 1], labels=['Very Low', 'Low', 'Mid', 'High', 'Very High'])
type2 = pd.cut(pricePerCarat, bins=[0, 1000, 3500, 5500, 18000, np.inf], labels=['Very Low', 'Low', 'Mid', 'High', 'Very High'])
type1.name = 'type1'
type2.name = 'type2'
df = pd.concat([df, type1, type2], axis=1)
df.head()
result

通過唯一值的數(shù)目判斷所有的種類是否都出現(xiàn)了和橙,可以知道使用cut劃分區(qū)間的種類中少了Very LowVery High,使用remove_categories移除不存在的類別即可

print(df.type1.cat.categories.nunique() == df.type1.nunique())
print(df.type2.cat.categories.nunique() == df.type2.nunique())
cond = df.type2.cat.categories.isin(df.type2)
df.type2.cat.remove_categories(df.type2.cat.categories[~cond])
result

使用pd.IntervalIndex將分區(qū)結(jié)果轉(zhuǎn)換成區(qū)間之后調(diào)用相關(guān)屬性即可

interval = pd.IntervalIndex(pd.qcut(pricePerCarat, q=[0, 0.2, 0.4, 0.6, 0.8, 1]))
interval.right #右端點(diǎn)
interval.left #左端點(diǎn)
interval.length #區(qū)間長度
result right
result left
result length
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末极阅,一起剝皮案震驚了整個(gè)濱河市胃碾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌筋搏,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厕隧,死亡現(xiàn)場離奇詭異奔脐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吁讨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門髓迎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人建丧,你說我怎么就攤上這事排龄。” “怎么了翎朱?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵橄维,是天一觀的道長。 經(jīng)常有香客問我拴曲,道長争舞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任澈灼,我火速辦了婚禮竞川,結(jié)果婚禮上店溢,老公的妹妹穿的比我還像新娘。我一直安慰自己委乌,他們只是感情好床牧,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遭贸,像睡著了一般戈咳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上革砸,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天除秀,我揣著相機(jī)與錄音,去河邊找鬼算利。 笑死册踩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的效拭。 我是一名探鬼主播暂吉,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缎患!你這毒婦竟也來了慕的?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤挤渔,失蹤者是張志新(化名)和其女友劉穎肮街,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體判导,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嫉父,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了眼刃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绕辖。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖擂红,靈堂內(nèi)的尸體忽然破棺而出仪际,到底是詐尸還是另有隱情,我是刑警寧澤昵骤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布树碱,位于F島的核電站,受9級特大地震影響涉茧,放射性物質(zhì)發(fā)生泄漏赴恨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一伴栓、第九天 我趴在偏房一處隱蔽的房頂上張望伦连。 院中可真熱鬧雨饺,春花似錦、人聲如沸惑淳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽歧焦。三九已至移斩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绢馍,已是汗流浹背向瓷。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留舰涌,地道東北人猖任。 一個(gè)月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像瓷耙,于是被迫代替她去往敵國和親朱躺。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容