構建你的數據科學作品集:用數據講故事
這是如何建立 數據科學作品集 系列文章中的第一篇。如果你喜歡這篇文章並且想知道此系列的下一篇文章何時發表,你可以在頁面底部訂閱。
數據科學公司們在決定僱傭一個人時越來越看重其作品集。其中一個原因就是 作品集 是分析一個人真實技能的最好方式。好消息是,作品集是完全可以被你掌控的。如果你在其上投入了一些工作,你就能夠做出一個令那些公司印象深刻的作品集結果。
建立一個高質量作品集的第一步就是知道展示什麼技能。那些公司們主要希望數據科學工作者擁有的技能,或者說他們主要希望作品集所展示的技能是:
- 表達能力
- 合作能力
- 專業技能
- 解釋數據的能力
- 有目標和有積極性的
任何一個好的作品集都由多個工程構成,每一個工程都會展示 1-2 個上面所說的點。這是涵蓋了「如何完成一個完整的數據科學作品集」系列文章的第一篇。在這篇文章中,我們將會涵括如何完成你的第一項數據科學作品集工程,並且對此進行有效的解釋。在最後,你將會得到一個幫助展示你表達能力和解釋數據能力的工程。
用數據講故事
數據科學是表達的基礎。你將會在數據中發現一些觀點,並且找出一個高效的方式來向他人表達這些,之後向他們展示你所開展的課題。數據科學最關鍵的手法之一就是能夠用數據講述一個清晰的故事。一個清晰的故事能夠使你的觀點更加引人注目,並且能使別人理解你的想法。
數據科學中的故事是一個講述你發現了什麼,你怎麼發現它的,並且它意味著什麼的故事。例如假使發現你公司的收入相對去年減少了百分之二十。這並不能夠確定原因,你可能需要和其它人溝通為什麼收入會減少,並且在嘗試修復它。
用數據講故事主要包含:
- 理解並確定上下文
- 從多角度發掘
- 使用有趣的表示方法
- 使用多種數據來源
- 一致的表述
用來講述數據的故事最有效率的工具就是 Jupyter notebook。如果你不熟悉,此處有一個好的教程。Jupyter notebook 允許你互動式的發掘數據,並且將你的結果分享到多個網站,包括 Github。分享你的結果有助於合作研究和其他人拓展你的分析。
在這篇文章中,我們將使用 Jupyter notebook,以及 Pandas 和 matplotlib 這樣的 Python 庫。
為你的數據科學工程選擇一個主題
建立一個工程的第一步就是決定你的主題。你要讓你的主題是你興趣所在,有動力去挖掘。進行數據挖掘時,為了完成而完成和有興趣完成的區別是很明顯的。這個步驟是值得花費時間的,所以確保你找到了你真正感興趣的東西。
一個尋找主題的好方法就是瀏覽不同的數據集並且尋找感興趣的部分。這裡有一些作為起點的好的網站:
- Data.gov - 包含了政府數據。
- /r/datasets – 一個有著上百個有趣數據集的 reddit 板塊。
- Awesome datasets – 一個數據集的列表,位於 Github 上。
- 17 個找到數據集的地方 – 這篇博文列出了 17 個數據集,每個都包含了示例數據集。
真實世界中的數據科學,你經常無法找到可以瀏覽的合適的單個數據集。你可能需要聚合多個獨立的數據源,或者做數量龐大的數據清理。如果該主題非常吸引你,這是值得這樣做的,並且也能更好的展示你的技能。
關於這篇文章的主題,我們將使用紐約市公立學校的數據,我們可以在這裡找到它。
選擇主題
這對於項目全程來說是十分重要的。因為主題能很好的限制項目的範圍,並且它能夠使我們知道它可以被完成。比起一個沒有足夠動力完成的工程來說,添加到一個完成的工程更加容易。
所以,我們將關注高中的學術評估測試,伴隨著多種人口統計和它們的其它數據。關於學習評估測試, 或者說 SAT,是美國高中生申請大學前的測試。大學在做判定時將考慮該成績,所以高分是十分重要的。考試分為三個階段,每個階段總分為 800。全部分數為 2400(即使這個前後更改了幾次,在數據中總分還是 2400)。高中經常通過平均 SAT分數進行排名,並且 SAT 是評判高中有多好的標準。
因為由關於 SAT 分數對於美國中某些種族群體是不公平的,所以對紐約市這個數據做分析能夠對 SAT 的公平性有些許幫助。
我們在這裡有 SAT 成績的數據集,並且在這裡有包含了每所高中的信息的數據集。這些將構成我們的工程的基礎,但是我們將加入更多的信息來創建有趣的分析。
補充數據
如果你已經有了一個很好的主題,拓展其它可以提升主題或者更深入挖掘數據的的數據集是一個好的選擇。在前期十分適合做這些工作,你將會有儘可能多的數據來構建你的工程。數據越少意味著你會太早的放棄了你的工程。
在本項目中,在包含人口統計信息和測試成績的網站上有一些相關的數據集。
這些是我們將會用到的所有數據集:
- 學校 SAT 成績 – 紐約市每所高中的 SAT 成績。
- 學校出勤情況 – 紐約市每所學校的出勤信息。
- 數學成績 – 紐約市每所學校的數學成績。
- 班級規模 - 紐約市每所學校課堂人數信息。
- AP 成績 - 高階位考試,在美國,通過 AP 測試就能獲得大學學分。
- 畢業去向 – 由百分之幾的學生畢業了,和其它去向信息。
- 人口統計 – 每個學校的人口統計信息。
- 學校問卷 – 學校的家長、教師,學生的問卷。
- 學校分布地圖 – 包含學校的區域布局信息,因此我們能將它們在地圖上標出。
(LCTT 譯註:高階位考試(AP)是美國和加拿大的一個由大學委員會創建的計劃,該計劃為高中學生提供大學水平的課程和考試。 美國學院和大學可以授予在考試中獲得高分的學生的就學和課程學分。)
這些數據作品集之間是相互關聯的,並且我們能夠在開始分析之前進行合併。
獲取背景信息
在開始分析數據之前,搜索一些背景信息是有必要的。我們知道這些有用的信息:
- 紐約市被分為五個不同的轄區
- 紐約市的學校被分配到幾個學區,每個學區都可能包含數十所學校。
- 數據集中的學校並不全是高中,所以我們需要對數據進行一些清理工作。
- 紐約市的每所學校都有自己單獨的編碼,被稱為『DBN』,即區域行政編號。
- 為了通過區域進行數據聚合,我們可以使用地圖區域信息來繪製逐區差異。
理解數據
為了真正的理解數據信息,你需要花費時間來挖掘和閱讀數據。因此,每個數據鏈接都有數據的描述信息,並伴隨著相關列。就像是我們擁有的高中 SAT 成績信息,也包含圖像和其它信息的數據集。
我們可以運行一些代碼來讀取數據。我們將使用 Jupyter notebook 來挖掘數據。下面的代碼將會執行以下操作:
- 循環遍歷我們下載的所有數據文件。
- 將文件讀取到 Pandas DataFrame。
- 將所有數據框架導入 Python 資料庫中。
In [100]:
import pandas
import numpy as np
files = ["ap_2010.csv", "class_size.csv", "demographics.csv", "graduation.csv", "hs_directory.csv", "math_test_results.csv", "sat_results.csv"]
data = {}
for f in files:
d = pandas.read_csv("schools/{0}".format(f))
data[f.replace(".csv", "")] = d
一旦我們將數據讀入,我們就可以使用 DataFrames 的 head 方法列印每個 DataFrame 的前五行。
In [103]:
for k,v in data.items():
print("n" + k + "n")
print(v.head())
math_test_results
DBN Grade Year Category Number Tested Mean Scale Score Level 1 #
0 01M015 3 2006 All Students 39 667 2
1 01M015 3 2007 All Students 31 672 2
2 01M015 3 2008 All Students 37 668 0
3 01M015 3 2009 All Students 33 668 0
4 01M015 3 2010 All Students 26 677 6
Level 1 % Level 2 # Level 2 % Level 3 # Level 3 % Level 4 # Level 4 %
0 5.1% 11 28.2% 20 51.3% 6 15.4%
1 6.5% 3 9.7% 22 71% 4 12.9%
2 0% 6 16.2% 29 78.4% 2 5.4%
3 0% 4 12.1% 28 84.8% 1 3%
4 23.1% 12 46.2% 6 23.1% 2 7.7%
Level 3+4 # Level 3+4 %
0 26 66.7%
1 26 83.9%
2 31 83.8%
3 29 87.9%
4 8 30.8%
ap_2010
DBN SchoolName AP Test Takers
0 01M448 UNIVERSITY NEIGHBORHOOD H.S. 39
1 01M450 EAST SIDE COMMUNITY HS 19
2 01M515 LOWER EASTSIDE PREP 24
3 01M539 NEW EXPLORATIONS SCI,TECH,MATH 255
4 02M296 High School of Hospitality Management s
Total Exams Taken Number of Exams with scores 3 4 or 5
0 49 10
1 21 s
2 26 24
3 377 191
4 s s
sat_results
DBN SCHOOL NAME
0 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL STUDIES
1 01M448 UNIVERSITY NEIGHBORHOOD HIGH SCHOOL
2 01M450 EAST SIDE COMMUNITY SCHOOL
3 01M458 FORSYTH SATELLITE ACADEMY
4 01M509 MARTA VALLE HIGH SCHOOL
Num of SAT Test Takers SAT Critical Reading Avg. Score SAT Math Avg. Score
0 29 355 404
1 91 383 423
2 70 377 402
3 7 414 401
4 44 390 433
SAT Writing Avg. Score
0 363
1 366
2 370
3 359
4 384
class_size
CSD BOROUGH SCHOOL CODE SCHOOL NAME GRADE PROGRAM TYPE
0 1 M M015 P.S. 015 Roberto Clemente 0K GEN ED
1 1 M M015 P.S. 015 Roberto Clemente 0K CTT
2 1 M M015 P.S. 015 Roberto Clemente 01 GEN ED
3 1 M M015 P.S. 015 Roberto Clemente 01 CTT
4 1 M M015 P.S. 015 Roberto Clemente 02 GEN ED
CORE SUBJECT (MS CORE and 9-12 ONLY) CORE COURSE (MS CORE and 9-12 ONLY)
0 - -
1 - -
2 - -
3 - -
4 - -
SERVICE CATEGORY(K-9* ONLY) NUMBER OF STUDENTS / SEATS FILLED
0 - 19.0
1 - 21.0
2 - 17.0
3 - 17.0
4 - 15.0
NUMBER OF SECTIONS AVERAGE CLASS SIZE SIZE OF SMALLEST CLASS
0 1.0 19.0 19.0
1 1.0 21.0 21.0
2 1.0 17.0 17.0
3 1.0 17.0 17.0
4 1.0 15.0 15.0
SIZE OF LARGEST CLASS DATA SOURCE SCHOOLWIDE PUPIL-TEACHER RATIO
0 19.0 ATS NaN
1 21.0 ATS NaN
2 17.0 ATS NaN
3 17.0 ATS NaN
4 15.0 ATS NaN
demographics
DBN Name schoolyear fl_percent frl_percent
0 01M015 P.S. 015 ROBERTO CLEMENTE 20052006 89.4 NaN
1 01M015 P.S. 015 ROBERTO CLEMENTE 20062007 89.4 NaN
2 01M015 P.S. 015 ROBERTO CLEMENTE 20072008 89.4 NaN
3 01M015 P.S. 015 ROBERTO CLEMENTE 20082009 89.4 NaN
4 01M015 P.S. 015 ROBERTO CLEMENTE 20092010 96.5
total_enrollment prek k grade1 grade2 ... black_num black_per
0 281 15 36 40 33 ... 74 26.3
1 243 15 29 39 38 ... 68 28.0
2 261 18 43 39 36 ... 77 29.5
3 252 17 37 44 32 ... 75 29.8
4 208 16 40 28 32 ... 67 32.2
hispanic_num hispanic_per white_num white_per male_num male_per female_num
0 189 67.3 5 1.8 158.0 56.2 123.0
1 153 63.0 4 1.6 140.0 57.6 103.0
2 157 60.2 7 2.7 143.0 54.8 118.0
3 149 59.1 7 2.8 149.0 59.1 103.0
4 118 56.7 6 2.9 124.0 59.6 84.0
female_per
0 43.8
1 42.4
2 45.2
3 40.9
4 40.4
[5 rows x 38 columns]
graduation
Demographic DBN School Name Cohort
0 Total Cohort 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL 2003
1 Total Cohort 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL 2004
2 Total Cohort 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL 2005
3 Total Cohort 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL 2006
4 Total Cohort 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL 2006 Aug
Total Cohort Total Grads - n Total Grads - % of cohort Total Regents - n
0 5 s s s
1 55 37 67.3% 17
2 64 43 67.2% 27
3 78 43 55.1% 36
4 78 44 56.4% 37
Total Regents - % of cohort Total Regents - % of grads
0 s s
1 30.9% 45.9%
2 42.2% 62.8%
3 46.2% 83.7%
4 47.4% 84.1%
... Regents w/o Advanced - n
0 ... s
1 ... 17
2 ... 27
3 ... 36
4 ... 37
Regents w/o Advanced - % of cohort Regents w/o Advanced - % of grads
0 s s
1 30.9% 45.9%
2 42.2% 62.8%
3 46.2% 83.7%
4 47.4% 84.1%
Local - n Local - % of cohort Local - % of grads Still Enrolled - n
0 s s s s
1 20 36.4% 54.1% 15
2 16 25% 37.200000000000003% 9
3 7 9% 16.3% 16
4 7 9% 15.9% 15
Still Enrolled - % of cohort Dropped Out - n Dropped Out - % of cohort
0 s s s
1 27.3% 3 5.5%
2 14.1% 9 14.1%
3 20.5% 11 14.1%
4 19.2% 11 14.1%
[5 rows x 23 columns]
hs_directory
dbn school_name boro
0 17K548 Brooklyn School for Music & Theatre Brooklyn
1 09X543 High School for Violin and Dance Bronx
2 09X327 Comprehensive Model School Project M.S. 327 Bronx
3 02M280 Manhattan Early College School for Advertising Manhattan
4 28Q680 Queens Gateway to Health Sciences Secondary Sc... Queens
building_code phone_number fax_number grade_span_min grade_span_max
0 K440 718-230-6250 718-230-6262 9 12
1 X400 718-842-0687 718-589-9849 9 12
2 X240 718-294-8111 718-294-8109 6 12
3 M520 718-935-3477 NaN 9 10
4 Q695 718-969-3155 718-969-3552 6 12
expgrade_span_min expgrade_span_max
0 NaN NaN
1 NaN NaN
2 NaN NaN
3 9 14.0
4 NaN NaN
...
0 ...
1 ...
2 ...
3 ...
4 ...
priority02
0 Then to New York City residents
1 Then to New York City residents who attend an ...
2 Then to Bronx students or residents who attend...
3 Then to New York City residents who attend an ...
4 Then to Districts 28 and 29 students or residents
priority03
0 NaN
1 Then to Bronx students or residents
2 Then to New York City residents who attend an ...
3 Then to Manhattan students or residents
4 Then to Queens students or residents
priority04 priority05
0 NaN NaN
1 Then to New York City residents NaN
2 Then to Bronx students or residents Then to New York City residents
3 Then to New York City residents NaN
4 Then to New York City residents NaN
priority06 priority07 priority08 priority09 priority10
0 NaN NaN NaN NaN NaN
1 NaN NaN NaN NaN NaN
2 NaN NaN NaN NaN NaN
3 NaN NaN NaN NaN NaN
4 NaN NaN NaN NaN NaN
Location 1
0 883 Classon AvenuenBrooklyn, NY 11225n(40.67...
1 1110 Boston RoadnBronx, NY 10456n(40.8276026...
2 1501 Jerome AvenuenBronx, NY 10452n(40.84241...
3 411 Pearl StreetnNew York, NY 10038n(40.7106...
4 160-20 Goethals AvenuenJamaica, NY 11432n(40...
[5 rows x 58 columns]
我們可以開始在數據作品集中觀察有用的部分:
- 大部分數據集包含 DBN 列。
- 一些條目看起來在地圖上標出會很有趣,特別是
Location 1
,這列在一個很長的字元串裡面包含了位置信息。 - 有些數據集會出現每所學校對應多行數據(DBN 數據重複),這意味著我們要進行預處理。
統一數據
為了使工作更簡單,我們將需要將全部零散的數據集統一為一個。這將使我們能夠快速跨數據集對比數據列。因此,我們需要找到相同的列將它們統一起來。請查看上面的輸出數據, DBN 出現在多個數據集中,它看起來可以作為共同列。
如果我們用 google 搜索 DBN New York City Schools
,我們在此得到了結果。它解釋了 DBN 是每個學校獨特的編碼。我們將挖掘數據集,特別是政府數據集。這通常需要做一些工作來找出每列的含義,或者每個數據集的意圖。
現在主要的問題是這兩個數據集 class_size
和 hs_directory
,沒有 DBN
列。在 hs_directory
數據中是 dbn
,那麼我們只需重命名即可,或者將它複製到新的名為 DBN 的列中。在 class_size
數據中,我們將需要嘗試不同的方法。
DBN 列:
In [5]:
data["demographics"]["DBN"].head()
Out[5]:
0 01M015
1 01M015
2 01M015
3 01M015
4 01M015
Name: DBN, dtype: object
如果我們查看 class_size
數據,我們將看到前五行如下:
In [4]:
data["class_size"].head()
Out[4]:
CSD | BOROUGH | SCHOOL CODE | SCHOOL NAME | GRADE | PROGRAM TYPE | CORE SUBJECT (MS CORE and 9-12 ONLY) | CORE COURSE (MS CORE and 9-12 ONLY) | SERVICE CATEGORY(K-9* ONLY) | NUMBER OF STUDENTS / SEATS FILLED | NUMBER OF SECTIONS | AVERAGE CLASS SIZE | SIZE OF SMALLEST CLASS | SIZE OF LARGEST CLASS | DATA SOURCE | SCHOOLWIDE PUPIL-TEACHER RATIO | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | M | M015 | P.S. 015 Roberto Clemente | 0K | GEN ED | - | - | - | 19.0 | 1.0 | 19.0 | 19.0 | 19.0 | ATS | NaN |
1 | 1 | M | M015 | P.S. 015 Roberto Clemente | 0K | CTT | - | - | - | 21.0 | 1.0 | 21.0 | 21.0 | 21.0 | ATS | NaN |
2 | 1 | M | M015 | P.S. 015 Roberto Clemente | 01 | GEN ED | - | - | - | 17.0 | 1.0 | 17.0 | 17.0 | 17.0 | ATS | NaN |
3 | 1 | M | M015 | P.S. 015 Roberto Clemente | 01 | CTT | - | - | - | 17.0 | 1.0 | 17.0 | 17.0 | 17.0 | ATS | NaN |
4 | 1 | M | M015 | P.S. 015 Roberto Clemente | 02 | GEN ED | - | - | - | 15.0 | 1.0 | 15.0 | 15.0 | 15.0 | ATS | NaN |
正如上面所見,DBN 實際上是 CSD
、 BOROUGH
和 SCHOOL CODE
的組合。對那些不熟悉紐約市的人來說,紐約由五個行政區組成。每個行政區是一個組織單位,並且有著相當於美國大城市一樣的面積。DBN 全稱為行政區域編號。看起來就像 CSD 是區域,BOROUGH 是行政區,並且當與 SCHOOL CODE 合併時就組成了 DBN。這裡並沒有尋找像這個數據這樣的內在規律的系統方法,這需要一些探索和努力來發現。
現在我們已經知道了 DBN 的組成,那麼我們就可以將它加入到 class_size
和 hs_directory
數據集中了:
In [ ]:
data["class_size"]["DBN"] = data["class_size"].apply(lambda x: "{0:02d}{1}".format(x["CSD"], x["SCHOOL CODE"]), axis=1)
data["hs_directory"]["DBN"] = data["hs_directory"]["dbn"]
加入問卷
最可能值得一看的數據集之一就是學生、家長和老師關於學校質量的問卷了。這些問卷包含了每所學校的安全程度、教學水平等。在我們合併數據集之前,讓我們添加問卷數據。在真實世界的數據科學工程中,你經常會在分析過程中碰到有趣的數據,並且希望合併它。使用像 Jupyter notebook 一樣靈活的工具將允許你快速添加一些新的代碼,並且重新開始你的分析。
因此,我們將添加問卷數據到我們的 data 文件夾,並且合併所有之前的數據。問卷數據分為兩個文件,一個包含所有的學校,一個包含 75 學區。我們將需要寫一些代碼來合併它們。之後的代碼我們將:
- 使用 windows-1252 編碼讀取所有學校的問卷。
- 使用 windows-1252 編碼讀取所有 75 號學區的問卷。
- 添加指示每個數據集所在學區的標誌。
- 使用 DataFrame 的 concat 方法將數據集合併為一個。
In [66]:
survey1 = pandas.read_csv("schools/survey_all.txt", delimiter="t", encoding='windows-1252')
survey2 = pandas.read_csv("schools/survey_d75.txt", delimiter="t", encoding='windows-1252')
survey1["d75"] = False
survey2["d75"] = True
survey = pandas.concat([survey1, survey2], axis=0)
一旦我們將問卷合併,這裡將會有一些混亂。我們希望我們合併的數據集列數最少,那麼我們將可以輕易的進行列之間的對比並找出其間的關聯。不幸的是,問卷數據有很多列並不是很有用:
In [16]:
survey.head()
Out[16]:
N_p | N_s | N_t | acap11 | acas11 | acat11 | acatot11 | bn | comp11 | coms11 | ... | tq8c1 | tq8c2 | tq8c3 | tq8c4 | t_q9 | tq91 | tq92 | tq93 | tq94 | tq95 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 90.0 | NaN | 22.0 | 7.8 | NaN | 7.9 | 7.9 | M015 | 7.6 | NaN | ... | 29.0 | 67.0 | 5.0 | 0.0 | NaN | 5.0 | 14.0 | 52.0 | 24.0 | 5.0 |
1 | 161.0 | NaN | 34.0 | 7.8 | NaN | 9.1 | 8.4 | M019 | 7.6 | NaN | ... | 74.0 | 21.0 | 6.0 | 0.0 | NaN | 3.0 | 6.0 | 3.0 | 78.0 | 9.0 |
2 | 367.0 | NaN | 42.0 | 8.6 | NaN | 7.5 | 8.0 | M020 | 8.3 | NaN | ... | 33.0 | 35.0 | 20.0 | 13.0 | NaN | 3.0 | 5.0 | 16.0 | 70.0 | 5.0 |
3 | 151.0 | 145.0 | 29.0 | 8.5 | 7.4 | 7.8 | 7.9 | M034 | 8.2 | 5.9 | ... | 21.0 | 45.0 | 28.0 | 7.0 | NaN | 0.0 | 18.0 | 32.0 | 39.0 | 11.0 |
4 | 90.0 | NaN | 23.0 | 7.9 | NaN | 8.1 | 8.0 | M063 | 7.9 | NaN | ... | 59.0 | 36.0 | 5.0 | 0.0 | NaN | 10.0 | 5.0 | 10.0 | 60.0 | 15.0 |
5 rows × 2773 columns
我們可以通過查看數據文件夾中伴隨問卷數據下載下來的文件來解決這個問題。它告訴我們們數據中重要的部分是哪些:
我們可以去除 survey
數據集中多餘的列:
In [17]:
survey["DBN"] = survey["dbn"]
survey_fields = ["DBN", "rr_s", "rr_t", "rr_p", "N_s", "N_t", "N_p", "saf_p_11", "com_p_11", "eng_p_11", "aca_p_11", "saf_t_11", "com_t_11", "eng_t_10", "aca_t_11", "saf_s_11", "com_s_11", "eng_s_11", "aca_s_11", "saf_tot_11", "com_tot_11", "eng_tot_11", "aca_tot_11",]
survey = survey.loc[:,survey_fields]
data["survey"] = survey
survey.shape
Out[17]:
(1702, 23)
請確保理你已經了解了每個數據集的內容和相關聯的列,這能節約你之後大量的時間和精力:
精簡數據集
如果我們查看某些數據集,包括 class_size
,我們將立刻發現問題:
In [18]:
data["class_size"].head()
Out[18]:
CSD | BOROUGH | SCHOOL CODE | SCHOOL NAME | GRADE | PROGRAM TYPE | CORE SUBJECT (MS CORE and 9-12 ONLY) | CORE COURSE (MS CORE and 9-12 ONLY) | SERVICE CATEGORY(K-9* ONLY) | NUMBER OF STUDENTS / SEATS FILLED | NUMBER OF SECTIONS | AVERAGE CLASS SIZE | SIZE OF SMALLEST CLASS | SIZE OF LARGEST CLASS | DATA SOURCE | SCHOOLWIDE PUPIL-TEACHER RATIO | DBN | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | M | M015 | P.S. 015 Roberto Clemente | 0K | GEN ED | - | - | - | 19.0 | 1.0 | 19.0 | 19.0 | 19.0 | ATS | NaN | 01M015 |
1 | 1 | M | M015 | P.S. 015 Roberto Clemente | 0K | CTT | - | - | - | 21.0 | 1.0 | 21.0 | 21.0 | 21.0 | ATS | NaN | 01M015 |
2 | 1 | M | M015 | P.S. 015 Roberto Clemente | 01 | GEN ED | - | - | - | 17.0 | 1.0 | 17.0 | 17.0 | 17.0 | ATS | NaN | 01M015 |
3 | 1 | M | M015 | P.S. 015 Roberto Clemente | 01 | CTT | - | - | - | 17.0 | 1.0 | 17.0 | 17.0 | 17.0 | ATS | NaN | 01M015 |
4 | 1 | M | M015 | P.S. 015 Roberto Clemente | 02 | GEN ED | - | - | - | 15.0 | 1.0 | 15.0 | 15.0 | 15.0 | ATS | NaN | 01M015 |
每所高中都有許多行(正如你所見的重複的 DBN
和 SCHOOL NAME
)。然而,如果我們看向 sat_result
數據集,每所高中只有一行:
In [21]:
data["sat_results"].head()
Out[21]:
DBN | SCHOOL NAME | Num of SAT Test Takers | SAT Critical Reading Avg. Score | SAT Math Avg. Score | SAT Writing Avg. Score | |
---|---|---|---|---|---|---|
0 | 01M292 | HENRY STREET SCHOOL FOR INTERNATIONAL STUDIES | 29 | 355 | 404 | 363 |
1 | 01M448 | UNIVERSITY NEIGHBORHOOD HIGH SCHOOL | 91 | 383 | 423 | 366 |
2 | 01M450 | EAST SIDE COMMUNITY SCHOOL | 70 | 377 | 402 | 370 |
3 | 01M458 | FORSYTH SATELLITE ACADEMY | 7 | 414 | 401 | 359 |
4 | 01M509 | MARTA VALLE HIGH SCHOOL | 44 | 390 | 433 | 384 |
為了合併這些數據集,我們將需要找到方法將數據集精簡到如 class_size
般一行對應一所高中。否則,我們將不能將 SAT 成績與班級大小進行比較。我們通過首先更好的理解數據,然後做一些合併來完成。class_size
數據集像 GRADE
和 PROGRAM TYPE
,每個學校有多個數據對應。為了將每個範圍內的數據變為一個數據,我們將大部分重複行過濾掉,在下面的代碼中我們將會:
- 只從
class_size
中選擇GRADE
範圍為09-12
的行。 - 只從
class_size
中選擇PROGRAM TYPE
是GEN ED
的行。 - 將
class_size
以DBN
分組,然後取每列的平均值。重要的是,我們將找到每所學校班級大小(class_size
)平均值。 - 重置索引,將
DBN
重新加到列中。
In [68]:
class_size = data["class_size"]
class_size = class_size[class_size["GRADE "] == "09-12"]
class_size = class_size[class_size["PROGRAM TYPE"] == "GEN ED"]
class_size = class_size.groupby("DBN").agg(np.mean)
class_size.reset_index(inplace=True)
data["class_size"] = class_size
精簡其它數據集
接下來,我們將需要精簡 demographic
數據集。這裡有每個學校收集多年的數據,所以這裡每所學校有許多重複的行。我們將只選取 schoolyear
最近的可用行:
In [69]:
demographics = data["demographics"]
demographics = demographics[demographics["schoolyear"] == 20112012]
data["demographics"] = demographics
我們需要精簡 math_test_results
數據集。這個數據集被 Grade
和 Year
劃分。我們將只選取單一學年的一個年級。
In [70]:
data["math_test_results"] = data["math_test_results"][data["math_test_results"]["Year"] == 2011]
data["math_test_results"] = data["math_test_results"][data["math_test_results"]["Grade"] == '8']
最後,graduation
需要被精簡:
In [71]:
data["graduation"] = data["graduation"][data["graduation"]["Cohort"] == "2006"]
data["graduation"] = data["graduation"][data["graduation"]["Demographic"] == "Total Cohort"]
在完成工程的主要部分之前數據清理和挖掘是十分重要的。有一個高質量的,一致的數據集將會使你的分析更加快速。
計算變數
計算變數可以通過使我們的比較更加快速來加快分析速度,並且能使我們做到本無法做到的比較。我們能做的第一件事就是從分開的列 SAT Math Avg. Score
,SAT Critical Reading Avg. Score
和 SAT Writing Avg. Score
計算 SAT 成績:
- 將 SAT 列數值從字元轉化為數字。
- 將所有列相加以得到
sat_score
,即 SAT 成績。
In [72]:
cols = ['SAT Math Avg. Score', 'SAT Critical Reading Avg. Score', 'SAT Writing Avg. Score']
for c in cols:
data["sat_results"][c] = data["sat_results"][c].convert_objects(convert_numeric=True)
data['sat_results']['sat_score'] = data['sat_results'][cols[0]] + data['sat_results'][cols[1]] + data['sat_results'][cols[2]]
接下來,我們將需要進行每所學校的坐標位置分析,以便我們製作地圖。這將使我們畫出每所學校的位置。在下面的代碼中,我們將會:
- 從
Location 1
列分析出經度和維度。 - 轉化
lat
(經度)和lon
(維度)為數字。
In [73]:
data["hs_directory"]['lat'] = data["hs_directory"]['Location 1'].apply(lambda x: x.split("n")[-1].replace("(", "").replace(")", "").split(", ")[0])
data["hs_directory"]['lon'] = data["hs_directory"]['Location 1'].apply(lambda x: x.split("n")[-1].replace("(", "").replace(")", "").split(", ")[1])
for c in ['lat', 'lon']:
data["hs_directory"][c] = data["hs_directory"][c].convert_objects(convert_numeric=True)
現在,我們將輸出每個數據集來查看我們有了什麼數據:
In [74]:
for k,v in data.items():
print(k)
print(v.head())
math_test_results
DBN Grade Year Category Number Tested Mean Scale Score
111 01M034 8 2011 All Students 48 646
280 01M140 8 2011 All Students 61 665
346 01M184 8 2011 All Students 49 727
388 01M188 8 2011 All Students 49 658
411 01M292 8 2011 All Students 49 650
Level 1 # Level 1 % Level 2 # Level 2 % Level 3 # Level 3 % Level 4 #
111 15 31.3% 22 45.8% 11 22.9% 0
280 1 1.6% 43 70.5% 17 27.9% 0
346 0 0% 0 0% 5 10.2% 44
388 10 20.4% 26 53.1% 10 20.4% 3
411 15 30.6% 25 51% 7 14.3% 2
Level 4 % Level 3+4 # Level 3+4 %
111 0% 11 22.9%
280 0% 17 27.9%
346 89.8% 49 100%
388 6.1% 13 26.5%
411 4.1% 9 18.4%
survey
DBN rr_s rr_t rr_p N_s N_t N_p saf_p_11 com_p_11 eng_p_11
0 01M015 NaN 88 60 NaN 22.0 90.0 8.5 7.6 7.5
1 01M019 NaN 100 60 NaN 34.0 161.0 8.4 7.6 7.6
2 01M020 NaN 88 73 NaN 42.0 367.0 8.9 8.3 8.3
3 01M034 89.0 73 50 145.0 29.0 151.0 8.8 8.2 8.0
4 01M063 NaN 100 60 NaN 23.0 90.0 8.7 7.9 8.1
... eng_t_10 aca_t_11 saf_s_11 com_s_11 eng_s_11 aca_s_11
0 ... NaN 7.9 NaN NaN NaN NaN
1 ... NaN 9.1 NaN NaN NaN NaN
2 ... NaN 7.5 NaN NaN NaN NaN
3 ... NaN 7.8 6.2 5.9 6.5 7.4
4 ... NaN 8.1 NaN NaN NaN NaN
saf_tot_11 com_tot_11 eng_tot_11 aca_tot_11
0 8.0 7.7 7.5 7.9
1 8.5 8.1 8.2 8.4
2 8.2 7.3 7.5 8.0
3 7.3 6.7 7.1 7.9
4 8.5 7.6 7.9 8.0
[5 rows x 23 columns]
ap_2010
DBN SchoolName AP Test Takers
0 01M448 UNIVERSITY NEIGHBORHOOD H.S. 39
1 01M450 EAST SIDE COMMUNITY HS 19
2 01M515 LOWER EASTSIDE PREP 24
3 01M539 NEW EXPLORATIONS SCI,TECH,MATH 255
4 02M296 High School of Hospitality Management s
Total Exams Taken Number of Exams with scores 3 4 or 5
0 49 10
1 21 s
2 26 24
3 377 191
4 s s
sat_results
DBN SCHOOL NAME
0 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL STUDIES
1 01M448 UNIVERSITY NEIGHBORHOOD HIGH SCHOOL
2 01M450 EAST SIDE COMMUNITY SCHOOL
3 01M458 FORSYTH SATELLITE ACADEMY
4 01M509 MARTA VALLE HIGH SCHOOL
Num of SAT Test Takers SAT Critical Reading Avg. Score
0 29 355.0
1 91 383.0
2 70 377.0
3 7 414.0
4 44 390.0
SAT Math Avg. Score SAT Writing Avg. Score sat_score
0 404.0 363.0 1122.0
1 423.0 366.0 1172.0
2 402.0 370.0 1149.0
3 401.0 359.0 1174.0
4 433.0 384.0 1207.0
class_size
DBN CSD NUMBER OF STUDENTS / SEATS FILLED NUMBER OF SECTIONS
0 01M292 1 88.0000 4.000000
1 01M332 1 46.0000 2.000000
2 01M378 1 33.0000 1.000000
3 01M448 1 105.6875 4.750000
4 01M450 1 57.6000 2.733333
AVERAGE CLASS SIZE SIZE OF SMALLEST CLASS SIZE OF LARGEST CLASS
0 22.564286 18.50 26.571429
1 22.000000 21.00 23.500000
2 33.000000 33.00 33.000000
3 22.231250 18.25 27.062500
4 21.200000 19.40 22.866667
SCHOOLWIDE PUPIL-TEACHER RATIO
0 NaN
1 NaN
2 NaN
3 NaN
4 NaN
demographics
DBN Name schoolyear
6 01M015 P.S. 015 ROBERTO CLEMENTE 20112012
13 01M019 P.S. 019 ASHER LEVY 20112012
20 01M020 PS 020 ANNA SILVER 20112012
27 01M034 PS 034 FRANKLIN D ROOSEVELT 20112012
35 01M063 PS 063 WILLIAM MCKINLEY 20112012
fl_percent frl_percent total_enrollment prek k grade1 grade2
6 NaN 89.4 189 13 31 35 28
13 NaN 61.5 328 32 46 52 54
20 NaN 92.5 626 52 102 121 87
27 NaN 99.7 401 14 34 38 36
35 NaN 78.9 176 18 20 30 21
... black_num black_per hispanic_num hispanic_per white_num
6 ... 63 33.3 109 57.7 4
13 ... 81 24.7 158 48.2 28
20 ... 55 8.8 357 57.0 16
27 ... 90 22.4 275 68.6 8
35 ... 41 23.3 110 62.5 15
white_per male_num male_per female_num female_per
6 2.1 97.0 51.3 92.0 48.7
13 8.5 147.0 44.8 181.0 55.2
20 2.6 330.0 52.7 296.0 47.3
27 2.0 204.0 50.9 197.0 49.1
35 8.5 97.0 55.1 79.0 44.9
[5 rows x 38 columns]
graduation
Demographic DBN School Name Cohort
3 Total Cohort 01M292 HENRY STREET SCHOOL FOR INTERNATIONAL 2006
10 Total Cohort 01M448 UNIVERSITY NEIGHBORHOOD HIGH SCHOOL 2006
17 Total Cohort 01M450 EAST SIDE COMMUNITY SCHOOL 2006
24 Total Cohort 01M509 MARTA VALLE HIGH SCHOOL 2006
31 Total Cohort 01M515 LOWER EAST SIDE PREPARATORY HIGH SCHO 2006
Total Cohort Total Grads - n Total Grads - % of cohort Total Regents - n
3 78 43 55.1% 36
10 124 53 42.7% 42
17 90 70 77.8% 67
24 84 47 56% 40
31 193 105 54.4% 91
Total Regents - % of cohort Total Regents - % of grads
3 46.2% 83.7%
10 33.9% 79.2%
17 74.400000000000006% 95.7%
24 47.6% 85.1%
31 47.2% 86.7%
... Regents w/o Advanced - n
3 ... 36
10 ... 34
17 ... 67
24 ... 23
31 ... 22
Regents w/o Advanced - % of cohort Regents w/o Advanced - % of grads
3 46.2% 83.7%
10 27.4% 64.2%
17 74.400000000000006% 95.7%
24 27.4% 48.9%
31 11.4% 21%
Local - n Local - % of cohort Local - % of grads Still Enrolled - n
3 7 9% 16.3% 16
10 11 8.9% 20.8% 46
17 3 3.3% 4.3% 15
24 7 8.300000000000001% 14.9% 25
31 14 7.3% 13.3% 53
Still Enrolled - % of cohort Dropped Out - n Dropped Out - % of cohort
3 20.5% 11 14.1%
10 37.1% 20 16.100000000000001%
17 16.7% 5 5.6%
24 29.8% 5 6%
31 27.5% 35 18.100000000000001%
[5 rows x 23 columns]
hs_directory
dbn school_name boro
0 17K548 Brooklyn School for Music & Theatre Brooklyn
1 09X543 High School for Violin and Dance Bronx
2 09X327 Comprehensive Model School Project M.S. 327 Bronx
3 02M280 Manhattan Early College School for Advertising Manhattan
4 28Q680 Queens Gateway to Health Sciences Secondary Sc... Queens
building_code phone_number fax_number grade_span_min grade_span_max
0 K440 718-230-6250 718-230-6262 9 12
1 X400 718-842-0687 718-589-9849 9 12
2 X240 718-294-8111 718-294-8109 6 12
3 M520 718-935-3477 NaN 9 10
4 Q695 718-969-3155 718-969-3552 6 12
expgrade_span_min expgrade_span_max ...
0 NaN NaN ...
1 NaN NaN ...
2 NaN NaN ...
3 9 14.0 ...
4 NaN NaN ...
priority05 priority06 priority07 priority08
0 NaN NaN NaN NaN
1 NaN NaN NaN NaN
2 Then to New York City residents NaN NaN NaN
3 NaN NaN NaN NaN
4 NaN NaN NaN NaN
priority09 priority10 Location 1
0 NaN NaN 883 Classon AvenuenBrooklyn, NY 11225n(40.67...
1 NaN NaN 1110 Boston RoadnBronx, NY 10456n(40.8276026...
2 NaN NaN 1501 Jerome AvenuenBronx, NY 10452n(40.84241...
3 NaN NaN 411 Pearl StreetnNew York, NY 10038n(40.7106...
4 NaN NaN 160-20 Goethals AvenuenJamaica, NY 11432n(40...
DBN lat lon
0 17K548 40.670299 -73.961648
1 09X543 40.827603 -73.904475
2 09X327 40.842414 -73.916162
3 02M280 40.710679 -74.000807
4 28Q680 40.718810 -73.806500
[5 rows x 61 columns]
合併數據集
現在我們已經完成了全部準備工作,我們可以用 DBN
列將數據組合在一起了。最終,我們將會從原始數據集得到一個有著上百列的數據集。當我們合併它們,請注意有些數據集中會丟失了 sat_result
中出現的高中。為了解決這個問題,我們需要使用 outer
方法來合併缺少行的數據集,這樣我們就不會丟失數據。在實際分析中,缺少數據是很常見的。能夠展示解釋和解決數據缺失的能力是構建一個作品集的重要部分。
你可以在此閱讀關於不同類型的合併。
接下來的代碼,我們將會:
- 循環遍歷
data
文件夾中的每一個條目。 - 輸出條目中的非唯一的 DBN 碼數量。
- 決定合併策略 -
inner
或outer
。 - 使用
DBN
列將條目合併到 DataFramefull
中。
In [75]:
flat_data_names = [k for k,v in data.items()]
flat_data = [data[k] for k in flat_data_names]
full = flat_data[0]
for i, f in enumerate(flat_data[1:]):
name = flat_data_names[i+1]
print(name)
print(len(f["DBN"]) - len(f["DBN"].unique()))
join_type = "inner"
if name in ["sat_results", "ap_2010", "graduation"]:
join_type = "outer"
if name not in ["math_test_results"]:
full = full.merge(f, on="DBN", how=join_type)
full.shape
survey
0
ap_2010
1
sat_results
0
class_size
0
demographics
0
graduation
0
hs_directory
0
Out[75]:
(374, 174)
添加值
現在我們有了我們的 full
數據框架,我們幾乎擁有分析需要的所有數據。雖然這裡有一些缺少的部分。我們可能將AP 考試結果與 SAT 成績相關聯,但是我們首先需要將這些列轉化為數字,然後填充缺失的數據。
In [76]:
cols = ['AP Test Takers ', 'Total Exams Taken', 'Number of Exams with scores 3 4 or 5']
for col in cols:
full[col] = full[col].convert_objects(convert_numeric=True)
full[cols] = full[cols].fillna(value=0)
然後我們將需要計算表示學校所在學區的 school_dist
列。這將是我們匹配學區並且使用我們之前下載的區域地圖畫出地區級別的地圖。
In [77]:
full["school_dist"] = full["DBN"].apply(lambda x: x[:2])
最終,我們將需要用該列的平均值填充缺失的數據到 full
中。那麼我們就可以計算關聯了:
In [79]:
full = full.fillna(full.mean())
計算關聯
一個挖掘數據並查看哪些列與你所關心的問題有聯繫的好方法來就是計算關聯。這將告訴你哪列與你所關心的列更加有關聯。你可以通過 Pandas DataFrames 的 corr 方法來完成。越接近 0 則關聯越小。越接近 1 則正相關越強,越接近 -1 則負關聯越強:
In [80]:
full.corr()['sat_score']
Out[80]:
Year NaN
Number Tested 8.127817e-02
rr_s 8.484298e-02
rr_t -6.604290e-02
rr_p 3.432778e-02
N_s 1.399443e-01
N_t 9.654314e-03
N_p 1.397405e-01
saf_p_11 1.050653e-01
com_p_11 2.107343e-02
eng_p_11 5.094925e-02
aca_p_11 5.822715e-02
saf_t_11 1.206710e-01
com_t_11 3.875666e-02
eng_t_10 NaN
aca_t_11 5.250357e-02
saf_s_11 1.054050e-01
com_s_11 4.576521e-02
eng_s_11 6.303699e-02
aca_s_11 8.015700e-02
saf_tot_11 1.266955e-01
com_tot_11 4.340710e-02
eng_tot_11 5.028588e-02
aca_tot_11 7.229584e-02
AP Test Takers 5.687940e-01
Total Exams Taken 5.585421e-01
Number of Exams with scores 3 4 or 5 5.619043e-01
SAT Critical Reading Avg. Score 9.868201e-01
SAT Math Avg. Score 9.726430e-01
SAT Writing Avg. Score 9.877708e-01
...
SIZE OF SMALLEST CLASS 2.440690e-01
SIZE OF LARGEST CLASS 3.052551e-01
SCHOOLWIDE PUPIL-TEACHER RATIO NaN
schoolyear NaN
frl_percent -7.018217e-01
total_enrollment 3.668201e-01
ell_num -1.535745e-01
ell_percent -3.981643e-01
sped_num 3.486852e-02
sped_percent -4.413665e-01
asian_num 4.748801e-01
asian_per 5.686267e-01
black_num 2.788331e-02
black_per -2.827907e-01
hispanic_num 2.568811e-02
hispanic_per -3.926373e-01
white_num 4.490835e-01
white_per 6.100860e-01
male_num 3.245320e-01
male_per -1.101484e-01
female_num 3.876979e-01
female_per 1.101928e-01
Total Cohort 3.244785e-01
grade_span_max -2.495359e-17
expgrade_span_max NaN
zip -6.312962e-02
total_students 4.066081e-01
number_programs 1.166234e-01
lat -1.198662e-01
lon -1.315241e-01
Name: sat_score, dtype: float64
這給了我們一些我們需要探索的內在規律:
total_enrollment
與sat_score
強相關,這是令人驚訝的,因為你曾經認為越小的學校越專註於學生就會取得更高的成績。- 女生所佔學校的比例(
female_per
) 與 SAT 成績呈正相關,而男生所佔學生比例(male_per
)成負相關。 - 沒有問卷與 SAT 成績成正相關。
- SAT 成績有明顯的種族不平等(
white_per
、asian_per
、black_per
、hispanic_per
)。 ell_percent
與 SAT 成績明顯負相關。
每一個條目都是一個挖掘和講述數據故事的潛在角度。
設置上下文
在我們開始數據挖掘之前,我們將希望設置上下文,不僅為了我們自己,也是為了其它閱讀我們分析的人。一個好的方法就是建立挖掘圖表或者地圖。因此,我們將在地圖標出所有學校的位置,這將有助於讀者理解我們所探索的問題。
在下面的代碼中,我們將會:
- 建立紐約市為中心的地圖。
- 為城市裡的每所高中添加一個標記。
- 顯示地圖。
In [82]:
import folium
from folium import plugins
schools_map = folium.Map(location=[full['lat'].mean(), full['lon'].mean()], zoom_start=10)
marker_cluster = folium.MarkerCluster().add_to(schools_map)
for name, row in full.iterrows():
folium.Marker([row["lat"], row["lon"]], popup="{0}: {1}".format(row["DBN"], row["school_name"])).add_to(marker_cluster)
schools_map.create_map('schools.html')
schools_map
Out[82]:
這個地圖十分有用,但是不容易查看紐約哪裡學校最多。因此,我們將用熱力圖來代替它:
In [84]:
schools_heatmap = folium.Map(location=[full['lat'].mean(), full['lon'].mean()], zoom_start=10)
schools_heatmap.add_children(plugins.HeatMap([[row["lat"], row["lon"]] for name, row in full.iterrows()]))
schools_heatmap.save("heatmap.html")
schools_heatmap
Out[84]:
區域級別映射
熱力圖能夠很好的標出梯度,但是我們將需要更結構化的畫出不同城市之間的 SAT 分數差距。學區是一個圖形化這個信息的很好的方式,就像每個區域都有自己的管理者。紐約市有數十個學區,並且每個區域都是一個小的地理區域。
我們可以通過學區來計算 SAT 分數,然後將它們畫在地圖上。在下面的代碼中,我們將會:
- 通過學區對
full
進行分組。 - 計算每個學區的每列的平均值。
- 去掉
school_dist
欄位頭部的 0,然後我們就可以匹配地理數據了。
In [ ]:
district_data = full.groupby("school_dist").agg(np.mean)
district_data.reset_index(inplace=True)
district_data["school_dist"] = district_data["school_dist"].apply(lambda x: str(int(x)))
我們現在將可以畫出 SAT 在每個學區的平均值了。因此,我們將會讀取 GeoJSON 中的數據,轉化為每個區域的形狀,然後通過 school_dist
列對每個區域圖形和 SAT 成績進行匹配。最終我們將創建一個圖形:
In [85]:
def show_district_map(col):
geo_path = 'schools/districts.geojson'
districts = folium.Map(location=[full['lat'].mean(), full['lon'].mean()], zoom_start=10)
districts.geo_json(
geo_path=geo_path,
data=district_data,
columns=['school_dist', col],
key_on='feature.properties.school_dist',
fill_color='YlGn',
fill_opacity=0.7,
line_opacity=0.2,
)
districts.save("districts.html")
return districts
show_district_map("sat_score")
Out[85]:
挖掘註冊學生數與SAT分數
現在我們已經依地區畫出學校位置和 SAT 成績確定了上下文,瀏覽我們分析的人將會對數據的上下文有更好的理解。現在我們已經完成了基礎工作,我們可以開始從我們上面尋找關聯時所提到的角度分析了。第一個分析角度是學校註冊學生人數與 SAT 成績。
我們可以通過所有學校的註冊學生與 SAT 成績的散點圖來分析。
In [87]:
%matplotlib inline
full.plot.scatter(x='total_enrollment', y='sat_score')
Out[87]:
<matplotlib.axes._subplots.AxesSubplot at 0x10fe79978>
如你所見,底下角註冊人數較低的部分有個較低 SAT 成績的聚集。這個集群以外,SAT 成績與全部註冊人數只有輕微正相關。這個畫出的關聯顯示了意想不到的圖形.
我們可以通過獲取低註冊人數且低SAT成績的學校的名字進行進一步的分析。
In [88]:
full[(full["total_enrollment"] < 1000) & (full["sat_score"] < 1000)]["School Name"]
Out[88]:
34 INTERNATIONAL SCHOOL FOR LIBERAL ARTS
143 NaN
148 KINGSBRIDGE INTERNATIONAL HIGH SCHOOL
203 MULTICULTURAL HIGH SCHOOL
294 INTERNATIONAL COMMUNITY HIGH SCHOOL
304 BRONX INTERNATIONAL HIGH SCHOOL
314 NaN
317 HIGH SCHOOL OF WORLD CULTURES
320 BROOKLYN INTERNATIONAL HIGH SCHOOL
329 INTERNATIONAL HIGH SCHOOL AT PROSPECT
331 IT TAKES A VILLAGE ACADEMY
351 PAN AMERICAN INTERNATIONAL HIGH SCHOO
Name: School Name, dtype: object
在 Google 上進行了一些搜索確定了這些學校大多數是為了正在學習英語而開設的,所以有這麼低註冊人數(規模)。這個挖掘向我們展示了並不是所有的註冊人數都與 SAT 成績有關聯 - 而是與是否將英語作為第二語言學習的學生有關。
挖掘英語學習者和 SAT 成績
現在我們知道英語學習者所佔學校學生比例與低的 SAT 成績有關聯,我們可以探索其中的規律。ell_percent
列表示一個學校英語學習者所佔的比例。我們可以製作關於這個關聯的散點圖。
In [89]:
full.plot.scatter(x='ell_percent', y='sat_score')
Out[89]:
<matplotlib.axes._subplots.AxesSubplot at 0x10fe824e0>
看起來這裡有一組學校有著高的 ell_percentage
值並且有著低的 SAT 成績。我們可以在學區層面調查這個關係,通過找出每個學區英語學習者所佔的比例,並且查看是否與我們的學區層面的 SAT 地圖所匹配:
In [90]:
show_district_map("ell_percent")
Out[90]:
我們可通過兩個區域層面地圖來查看,一個低 ELL(English-language)學習者比例的地區更傾向有高 SAT 成績,反之亦然。
關聯問卷分數和 SAT 分數
學生、家長和老師的問卷結果如果與 SAT 分數有很大的關聯的假設是合理的。就例如具有高學術期望的學校傾向於有著更高的 SAT 分數是合理的。為了測這個理論,讓我們畫出 SAT 分數和多種問卷指標:
In [91]:
full.corr()["sat_score"][["rr_s", "rr_t", "rr_p", "N_s", "N_t", "N_p", "saf_tot_11", "com_tot_11", "aca_tot_11", "eng_tot_11"]].plot.bar()
Out[91]:
<matplotlib.axes._subplots.AxesSubplot at 0x114652400>
驚人的是,關聯最大的兩個因子是 N_p
和 N_s
,它們分別是家長和學生回應的問卷。都與註冊人數有著強關聯,所以很可能偏離了 ell_learner
。此外指標關聯最強的就是 saf_t_11
,這是學生、家長和老師對學校安全程度的感知。這說明了,越安全的學校,更能讓學生在環境里安心學習。然而其它因子,像互動、交流和學術水平都與 SAT 分數無關,這也許表明了紐約在問卷中問了不理想的問題或者想錯了因子(如果他們的目的是提高 SAT 分數的話)。
挖掘種族和 SAT 分數
其中一個角度就是調查種族和 SAT 分數的聯繫。這是一個大相關微分,將其畫出來幫助我們理解到底發生了什麼:
In [92]:
full.corr()["sat_score"][["white_per", "asian_per", "black_per", "hispanic_per"]].plot.bar()
Out[92]:
<matplotlib.axes._subplots.AxesSubplot at 0x108166ba8>
看起來更高比例的白種和亞洲學生與更高的 SAT 分數有關聯,而更高比例的黑人和西班牙裔與更低的 SAT 分數有關聯。對於西班牙學生,這可能因為近年的移民還是英語學習者的事實。我們可以標出學區層面的西班牙裔的比例並觀察聯繫。
In [93]:
show_district_map("hispanic_per")
Out[93]:
看起來這裡與英語學習者比例有關聯,但是有必要對這種和其它種族在 SAT 分數上的差異進行挖掘。
SAT 分數上的性別差異
挖掘性別與 SAT 分數之間的關係是最後一個角度。我們注意更高的女生比例的學校傾向於與更高的 SAT 分數有關聯。我們可以可視化為一個條形圖:
In [94]:
full.corr()["sat_score"][["male_per", "female_per"]].plot.bar()
Out[94]:
<matplotlib.axes._subplots.AxesSubplot at 0x10774d0f0>
為了挖掘更多的關聯性,我們可以製作一個 female_per
和 sat_score
的散點圖:
In [95]:
full.plot.scatter(x='female_per', y='sat_score')
Out[95]:
<matplotlib.axes._subplots.AxesSubplot at 0x104715160>
看起來這裡有一個高女生比例、高 SAT 成績的簇(右上角)(LCTT 譯註:此處散點圖並未有如此跡象,可能數據圖有誤)。我們可以獲取簇中學校的名字:
In [96]:
full[(full["female_per"] > 65) & (full["sat_score"] > 1400)]["School Name"]
Out[96]:
3 PROFESSIONAL PERFORMING ARTS HIGH SCH
92 ELEANOR ROOSEVELT HIGH SCHOOL
100 TALENT UNLIMITED HIGH SCHOOL
111 FIORELLO H. LAGUARDIA HIGH SCHOOL OF
229 TOWNSEND HARRIS HIGH SCHOOL
250 FRANK SINATRA SCHOOL OF THE ARTS HIGH SCHOOL
265 BARD HIGH SCHOOL EARLY COLLEGE
Name: School Name, dtype: object
使用 Google 進行搜索可以知道這些是專註於表演藝術的精英學校。這些學校有著更高比例的女生和更高的 SAT 分數。這可能解釋了更高的女生比例和 SAT 分數的關聯,並且相反的更高的男生比例與更低的 SAT 分數。
AP 成績
至今,我們關注的是人口統計角度。還有一個角度是我們通過數據來看參加高階測試(AP)的學生和 SAT 分數。因為高學術成績獲得者傾向於有著高的 SAT 分數說明了它們是有關聯的。
In [98]:
full["ap_avg"] = full["AP Test Takers "] / full["total_enrollment"]
full.plot.scatter(x='ap_avg', y='sat_score')
Out[98]:
<matplotlib.axes._subplots.AxesSubplot at 0x11463a908>
看起來它們之間確實有著很強的關聯。有趣的是右上角高 SAT 分數的學校有著高的 AP 測試通過比例:
In [99]:
full[(full["ap_avg"] > .3) & (full["sat_score"] > 1700)]["School Name"]
Out[99]:
92 ELEANOR ROOSEVELT HIGH SCHOOL
98 STUYVESANT HIGH SCHOOL
157 BRONX HIGH SCHOOL OF SCIENCE
161 HIGH SCHOOL OF AMERICAN STUDIES AT LE
176 BROOKLYN TECHNICAL HIGH SCHOOL
229 TOWNSEND HARRIS HIGH SCHOOL
243 QUEENS HIGH SCHOOL FOR THE SCIENCES A
260 STATEN ISLAND TECHNICAL HIGH SCHOOL
Name: School Name, dtype: object
通過 google 搜索解釋了那些大多是高選擇性的學校,你需要經過測試才能進入。這就說明了為什麼這些學校會有高的 AP 通過人數。
包裝故事
在數據科學中,故事不可能真正完結。通過向其他人發布分析,你可以讓他們拓展並且運用你的分析到他們所感興趣的方向。比如在本文中,這裡有一些角度我們沒有完成,並且可以探索更加深入。
一個開始講述故事的最好方式就是嘗試拓展或者複製別人已經完成的分析。如果你覺得採取這個方式,歡迎你拓展這篇文章的分析,並看看你能發現什麼。如果你確實這麼做了,請在下面評論,那麼我就可以看到了。
下一步
如果你做的足夠多,你看起來已經對用數據講故事和構建你的第一個數據科學作品集有了很好的理解。一旦你完成了你的數據科學工程,發表在 Github 上是一個好的想法,這樣別人就能夠與你一起合作。
如果你喜歡這篇文章,你可能希望閱讀我們『Build a Data Science Portfolio』系列文章的其它部分:
via: https://www.dataquest.io/blog/data-science-portfolio-project/
作者:Vik Paruchuri 譯者:[Yoo-4x] 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive