小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

一道基礎(chǔ)題,多種解題思路,引出Pandas多個(gè)知識(shí)點(diǎn)

 小小明代碼實(shí)體 2021-11-30

作者:小小明

源于群管理員林胖發(fā)出的一道基礎(chǔ)題:

image-20210117204240080

文章目錄

基礎(chǔ)解法explode函數(shù)

這道題最簡單的解法,相信大部分用過pandas的朋友都會(huì),林胖也馬上發(fā)出了自己的答案:

import pandas as pd

mydict = {'A': [1], 'B': [2, 3], 'C': [4, 5, 6]}
pd.DataFrame(mydict.items()).explode(1)

結(jié)果:

image-20210117204507756

詳解

mydict.items()是python基礎(chǔ)字典的內(nèi)容,它返回了這個(gè)字典鍵值對(duì)組成的元組列表:

mydict.items()

返回:

dict_items([('A', [1]), ('B', [2, 3]), ('C', [4, 5, 6])])

將這個(gè)內(nèi)部是元組的可迭代對(duì)象傳入DataFrame的構(gòu)造函數(shù)中:

pd.DataFrame(mydict.items())

返回結(jié)果:

image-20210117210813746

這是pandas最基礎(chǔ)的開篇知識(shí)點(diǎn)使用可迭代對(duì)象構(gòu)造DataFrame,列表的每個(gè)元素都是整個(gè)DataFrame對(duì)應(yīng)的一行,而這個(gè)元素內(nèi)部迭代出來的每個(gè)元素將構(gòu)成DataFrame的某一列。

然后再看看這個(gè)explode函數(shù),它是pandas 0.25版本才出現(xiàn)的函數(shù),只有一個(gè)參數(shù)可以傳入列名,然后該函數(shù)就可以把該列的列表每個(gè)元素?cái)U(kuò)展到多行上。

效果與hive使用lateral view+explode實(shí)現(xiàn)的效果幾乎一致,類似于:

select a,b_i from df lateral view explode(b) tmp as b_i;

可以參考很早之前的一篇文章:https://blog.csdn.net/as604049322/article/details/105985770

沒有exlode函數(shù)如何解決這個(gè)問題

但是,黃佬說版本太低沒有這個(gè)函數(shù),于是我給群友們出了一道題:

image-20210117214330202

在群主的邀請(qǐng)下,一位經(jīng)過我多次輔導(dǎo)的群友率先使用了循環(huán)法解題:

image-20210117214609893

我覺得非常棒,但我也希望看到有人再用變形法實(shí)現(xiàn)一次。林胖和一位群友再次給出了簡化版本的循環(huán)解法:

image-20210117215149606

經(jīng)過一番提示后,小五哥和林胖終于給出了變形法的解法:

image-20210117215652916

非常不錯(cuò),群友們終于獨(dú)立的多思路解決了這個(gè)問題,真的要撒花呀!!!

下面我們?cè)敿?xì)分析一下,循環(huán)法和變形法的解法吧:

循環(huán)法解題

基本寫法:

result = []
for k, vs in mydict.items():
    for v in vs:
        result.append((k, v))
pd.DataFrame(result)

本質(zhì)上就是實(shí)現(xiàn)了一個(gè)笛卡爾積的拉平操作,將mydict.items這個(gè)可迭代對(duì)象的元組構(gòu)造笛卡爾積并按照整體拉平。

上面的基本寫法,應(yīng)該99%以上的朋友都能看懂,但 林胖 的循環(huán)簡化解法:

import itertools
result = []
for k, v in mydict.items():
    result.extend(itertools.product(k, v))
pd.DataFrame(result)

部分朋友可能沒有看明白,這個(gè)就需要查詢一下product方法的官方文檔(https://docs./zh-cn/3.7/library/itertools.html?highlight=product#itertools.product):

product(*iterables, repeat=1) --> product object

參數(shù):

  • iterables 為可迭代對(duì)象
  • 可選參數(shù)repeat 表示重復(fù)次數(shù)

用于生成可迭代對(duì)象輸入的笛卡兒積,相當(dāng)于生成器表達(dá)式中的嵌套循環(huán)。

例如: product(A, B) 中的元素A和B將共同構(gòu)成可迭代元素[A, B]作為iterables傳入和 ((x,y) for x in A for y in B) 返回結(jié)果一樣。

返回示例:

  • product('ab’, range(3)) --> ('a’,0) ('a’,1) ('a’,2) ('b’,0) ('b’,1) ('b’,2)
  • product((0,1), (0,1), (0,1)) --> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) …

也可以傳入可選參數(shù) repeat 表示重復(fù)的次數(shù):例如,product(A, repeat=4)product(A, A, A, A) 的返回結(jié)果是一樣的。


列表的extend方法是將可迭代對(duì)象的每個(gè)元素都添加到列表中,而append方法只能添加單個(gè)元素。

當(dāng)然,我們還可以將整個(gè)for循環(huán)改寫成列表生成式:

result = [(k, v) for k, vs in mydict.items() for v in vs]
pd.DataFrame(result)

也可以簡化代碼量。

變形法解題

df = pd.DataFrame(mydict.items(), columns=["a", "b"])
df

實(shí)現(xiàn)思路,上面的界面是下面最左邊:

image-20210118001008103

列表分列的2種方法

列表分列的思路:Pandas的Series對(duì)象調(diào)用apply方法單個(gè)元素返回的結(jié)果是Series時(shí),這個(gè)Series的每個(gè)數(shù)據(jù)會(huì)作為Datafrem的每一列,索引會(huì)作為列名。

對(duì)Series進(jìn)行列表分列

例如:

df["b"].apply(pd.Series)

結(jié)果:

image-20210118001116439

不過這樣會(huì)丟失原本的"a"列,我們可以先將"a"列設(shè)置為索引,再進(jìn)行Series分列操作:

df.set_index("a")["b"].apply(pd.Series)

或者把結(jié)果設(shè)置成原本的"a"列為索引:

df["b"].apply(pd.Series).set_index(df["a"])

結(jié)果均為上述實(shí)現(xiàn)思路的第二步。

直接對(duì)Datafream進(jìn)行列表分列

如果我們希望直接使用Datafream實(shí)現(xiàn)分列可以借助agg方法,因?yàn)閍gg方法是對(duì)每一列的Series對(duì)象操作:

df.agg({"a": lambda x: x, "b": pd.Series})

結(jié)果:

image-20210118001344742

但這操作導(dǎo)致列多了一個(gè)級(jí)別,需要?jiǎng)h除:

df.agg({"a": lambda x: x, "b": pd.Series}).droplevel(0, axis=1)

結(jié)果:

image-20210118001450495

只要再執(zhí)行set_index("a")

df.agg({"a": lambda x: x, "b": pd.Series}).droplevel(0, axis=1).set_index("a")

結(jié)果就會(huì)與實(shí)現(xiàn)思路的第二步結(jié)果一致。

將字典的鍵作為索引的2種讀取方法

當(dāng)然上面我只是為了給大家講述分列的一些方法。對(duì)于這個(gè)例子,其實(shí)我們可以直接通過pd.DataFrame.from_dict方法orient參數(shù)傳入’index’,直接獲得第二步的結(jié)果(只是索引沒有名稱):

df = pd.DataFrame.from_dict(mydict, 'index')

或者分別傳入data和索引index:

df = pd.DataFrame(data=mydict.values(), index=mydict.keys())

都能得到以下結(jié)果:

image-20210118002617199

melt實(shí)現(xiàn)逆透視

說起逆透視我個(gè)人首先想到了melt方法,然后才想到melt方法實(shí)現(xiàn)的本質(zhì)用到了stack方法。

為了避免索引丟失,我們首先還原索引為普通的列:

df = df.rename_axis(index="a").reset_index()
df

結(jié)果:

image-20210118003731159

然后使用melt方法進(jìn)行逆透視:

df.melt(id_vars='a', value_name='b')

結(jié)果:

image-20210118005108598

然后刪除第二列,再刪除空值行,再將數(shù)值列轉(zhuǎn)換為整數(shù)類型就搞定。

最終代碼:

df = pd.DataFrame.from_dict(mydict, 'index')
df = df.melt(id_vars='a', value_name='b').drop(columns="variable").dropna()
df.b = df.b.astype("int")
df

成功得到結(jié)果:

image-20210118005544447

stack實(shí)現(xiàn)逆透視

df = pd.DataFrame.from_dict(mydict, 'index')
df.stack()

結(jié)果:

A  0    1.0
B  0    2.0
   1    3.0
C  0    4.0
   1    5.0
   2    6.0
dtype: float64

結(jié)果返回了一個(gè)多級(jí)索引的Series,我們首先需要?jiǎng)h除索引中多余的部分:

df.stack().droplevel(1)

結(jié)果:

A    1.0
B    2.0
B    3.0
C    4.0
C    5.0
C    6.0
dtype: float64

此時(shí)我們?cè)龠€原索引到普通列:

df.stack().droplevel(1).reset_index()

再重新設(shè)置一下列名:

df.stack().droplevel(1).reset_index().set_axis(["a", "b"], axis=1)

最后重設(shè)一下B列的類型:

df.b = df.b.astype("int")

最終代碼:

df = pd.DataFrame.from_dict(mydict, 'index')
df = df.stack().droplevel(1).reset_index().set_axis(["a", "b"], axis=1)
df.b = df.b.astype("int")
df

結(jié)果:

image-20210118011340419

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多