[Python] Marvel和DC哪個更政治正確
系列第6篇,完全版(在線寫代碼+測評)首發於:[Python入門] 06 面向對象 - 集智
知乎專欄為純圖文版。01. 數據集
本篇將要用到的示例數據是Marvel和DC的漫畫人物的信息統計,來自知名數據分析網站fivethirtyeight.com。
首先導入並進行簡單的預處理:
import pandas as pdndf = pd.read_csv("marvel-wikia-data.csv")nndf = df.drop("page_id", axis=1) # 刪除「page_id」這一列ndf = df.drop("urlslug", axis=1) # 刪除「urlslug」列ndf = df.drop("ID", axis=1) #刪除「ID」列nnprint(df.head())n
數據各列的含義如下:
name: 角色姓名
ALIGN: 所屬陣營EYE: 眼睛顏色HAIR: 頭髮顏色SEX: 性別GSM: 是否性少數群體ALIVE: 是否存活APPREARANCES: 登場次數FIRST APPEARANCES: 首次登場時間
Year: 首次登場年份02. 類和對象
當我們想要寫簡歷的時候,如果打開一個空白文檔從零寫起,那將是最痛苦的。比較理智的做法是找一個模板,模板中已經定義並排版了姓名、年齡、教育背景、工作經歷等版塊,我們只需要填空就行。
在這裡,網上的簡歷模板就是一個「類」(class),下載到本地的模板就是創建了一個「對象」(object),具體的信息板塊就是建立的「屬性」(atrribute),接下來要做的就是修改屬性的值,使之滿足實際需要。
對象還具有「方法」(method),像word文檔可以把自己導出為PDF,又比如Python中列表對象的.append()方法可以為自己增補一個元素。
類(class)和對象(object)可以幫助我們寫出更加簡潔高效的程序,在之前的章節中,我們已經接觸過了不少類和對象。比如:
- 變數類:整數(int),浮點數(float)。
- 數據結構類:列表(list),字典(dictionary),元組(tuple)。
03. 屬性
定義一個類的關鍵字是」class「,當我們要定義一個Resume()類,那麼語句就是:
class Resume():
注意類名Resume()後面的冒號(:),這與定義函數和控制流類似。
在類的代碼段中,再定義一個特別的函數:__init__(),init前後各有兩條下劃線,本函數用以定義屬性。
class Resume():n def __init__(self):n self.name = "Kaiser"n self.sex = "秀吉"n
根據如上定義,現在類Resume()就有了name和gender兩項屬性,且默認值分別為"Kaiser"和"秀吉"。
下面針對Marvel數據集,定義一個超級英雄的類Hero(),再定義屬性name,使其默認值為蜘蛛俠的全稱:Spider-Man (Peter Parker)。
創建Hero()的對象,命名為spider,保留默認屬性值。
class Hero():n def __init__(self):n self.name = df.loc[0,"name"]nnspider = Hero()nprint(spider.name)n
04. __init__()與self
除了屬性,類還可以有自己的方法,__init__()就是最特殊的一種方法,當對象被創建時,就會自動被調用。 在上面的例子中,創建對象spider無需執行spider.__init__(),其屬性就具有了默認值。
__init__()函數以self為參數,在一個類的定義代碼中,self指代的是當前創建過程中的對象。當__init__()被自動執行的時候,self.name 實際也就是spider.name。
在self之外,__init__()函數還可以讀取其他參數,比如當我們想要創建另一個對象美國隊長時,name屬性就不再是類的默認值了,而需要在init()函數中顯式指定。
class Hero():n def __init__(self, name):n self.name = namenncaptain = Hero(df.loc[1, "name"])nprint(captain.name)n
self總是__init__()的第一個參數,在創建對象時無需顯式聲明,上例也可以寫成captain = Hero(df.loc[1, "name"]),參數仍然會傳遞給name,self還是self。
讀者朋友可以嘗試在def init(self, name)中調換self的位置或去掉self,查看輸出的錯誤信息。
05. 方法
之前輸出對象的name屬性,使用了print()函數,我們也可以使對象自己具有輸出屬性的功能,這就是方法。定義對象方法的格式與__init__()完全一致,只是其他方法不會被自動執行,需要顯式調用。
比如輸出金剛狼的性別:
class Hero():n def __init__(self, name ,sex):n self.name = namen self.sex = sexnn def print_sex(self):n print(self.sex)nnwolverine = Hero(df.loc[2, "name"], df.loc[2, "SEX"])nwolverine.print_sex()n
這次來編寫一個稍微複雜一點兒的方法,計算某個人物的年均登場次數。以鋼鐵俠(id=3)為例,創建鋼鐵俠對應的Hero()對象,並使其avg_app屬性具有正確的值。
import datetimennow = datetime.datetime.now()nnclass Hero():n def __init__(self, id=0): # 默認id為0n self.name = df.loc[id, "name"]n self.sex = df.loc[id, "SEX"]n self.appearances = df.loc[id, "APPEARANCES"]n self.year = now.year - df.loc[id, "Year"]nn def show_name(self):n print("{0}".format(self.name))nn def show_avg_app(self):n self.avg_app = self.appearances / self.yearn print("{0}".format(self.avg_app))nnniron = Hero(id=3)niron.show_name() # 輸出姓名,確認由ID指定了正確的人物niron.show_avg_app()n
06. 政治正確
任何文藝作品都不能脫離社會大環境而存在,尤其是Marvel這樣緊跟潮流甚至引領潮流的創作集團,更是深諳佔領宣傳高地的要領。
最近幾年,「政治正確」(Political Correctness)對美國社會的影響越來越大,突出體現在對少數祖裔和弱勢群體的區別對待,比如黑人,非法移民,性少數群體等。
神盾局的領導尼克·弗瑞,在漫畫世界觀的兩個宇宙中,分別有白人和黑人兩種形象。其中主線宇宙:616宇宙中,他是一名白人,外形有點像《合金裝備》的Snake;在1610宇宙中則是黑人。《復仇者聯盟》電影則是選擇了後者,由塞繆爾·傑克遜扮演。
除了種族以外,538提供的數據集還專門列出了GSM(Gender or Sexual Minority),即性少數群體,如同性戀,雙性戀等。
漫威的多數作品裡,善惡是較為分明的,此前傳出的「美國隊長實為九頭蛇卧底」說法後來也證實為一派胡言,我們濃眉大眼的史愛民同志並沒有叛變革命。在538提供的數據集當中,每個角色都有「陣營」屬性,簡單的分為Good Characters(好漢),Bad Characters(壞逼)和Neutrual Characters(野怪)。
把政治正確群體設置為反面角色,是很容易傷害到他們感情的,進而就會遭到抵制甚至懲罰。所以創作者越來越傾向於避免這一情況,甚至儘可能選擇讓高大全形色具有政治正確屬性。
與Marvel齊名的DC公司旗下角色也在538提供的數據集當中,接來下可以做個對比,看看兩家誰更「政治正確」一些。
我們不僅可以把單個角色作為一類,也可以將一個陣營作為一類,接下來就定義陣營類。 首先排除部分登場次數數據缺失以及小於等於5的龍套角色,然後按照ALIGN列的值分別建立三個數據表。
df = df[df[APPEARANCES] > 5]ndf_good = df[df["ALIGN"] == "Good Characters"]ndf_bad = df[df["ALIGN"] == "Bad Characters"]ndf_neu = df[df["ALIGN"] == "Neutral Characters"]n
定義類Align(),讓self.gsm_ratio等於對應陣營中性少數群體所佔的比例。
class Align():nn def __init__(self, side):n if side == "b":n self.name = "Bad Ass"n self.df = df_badn elif side == "g":n self.name = "Good Ass"n self.df = df_goodn else:n self.name = "Neutral Ass"n self.df = df_neunn self.counts = self.df.shape[0]n self.gsm = self.df[self.df["GSM"].notnull()].shape[0]n self.gsm_ratio = self.gsm / self.countsnn def show_gsm(self):n print("The ratio of GSM in {} is {:.2f}%".format(self.name, self.gsm_ratio * 100))n
根據計算,Marvel登場角色中,性少數群體在三個陣營中的百分比為:
好漢 中立 壞逼
2.13 1.83 0.34對DC數據集dc-wikia-data.csv做同樣計算得到對應百分比:
好漢 中立 壞逼
2.16 1.49 0.90可見,Marvel的反面角色中,GSM群體比例明顯小於DC。運行下面的代碼,可以看到圖像表示:
mv_gsm = [2.13, 1.83, 0.34]ndc_gsm = [2.16, 1.49, 0.90]nndf_city = pd.DataFrame({"mv":mv_gsm, "dc":dc_gsm})ndf_city.plot(kind=bar, stacked=True, title=DC/Marvel GSM Ratios)n
原文:[Python入門] 06 面向對象 - 集智
最後祝你,提前剩蛋,身體健康。
推薦閱讀: