手记

构建你的数据科学作品集:用数据讲故事(下)

加入问卷

最可能值得一看的数据集之一就是学生、家长和老师关于学校质量的问卷了。这些问卷包含了每所学校的安全程度、教学水平等。在我们合并数据集之前,让我们添加问卷数据。在真实世界的数据科学工程中,你经常会在分析过程中碰到有趣的数据,并且希望合并它。使用像 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"] = Falsesurvey2["d75"] = Truesurvey = pandas.concat([survey1, survey2], axis=0)

一旦我们将问卷合并,这里将会有一些混乱。我们希望我们合并的数据集列数最少,那么我们将可以轻易的进行列之间的对比并找出其间的关联。不幸的是,问卷数据有很多列并不是很有用:

In [16]:

survey.head()

Out[16]:

N_p

N_s

N_t

aca_p_11

aca_s_11

aca_t_11

aca_tot_11

bn

com_p_11

com_s_11

...

t_q8c_1

t_q8c_2

t_q8c_3

t_q8c_4

t_q9

t_q9_1

t_q9_2

t_q9_3

t_q9_4

t_q9_5

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. ScoreSAT 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              646280  01M140     8  2011  All Students             61              665346  01M184     8  2011  All Students             49              727388  01M188     8  2011  All Students             49              658411  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%         0280         1      1.6%        43     70.5%        17     27.9%         0346         0        0%         0        0%         5     10.2%        44388        10     20.4%        26     53.1%        10     20.4%         3411        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.51  01M019   NaN   100    60    NaN  34.0  161.0       8.4       7.6       7.62  01M020   NaN    88    73    NaN  42.0  367.0       8.9       8.3       8.33  01M034  89.0    73    50  145.0  29.0  151.0       8.8       8.2       8.04  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       NaN1     ...           NaN       9.1       NaN       NaN       NaN       NaN2     ...           NaN       7.5       NaN       NaN       NaN       NaN3     ...           NaN       7.8       6.2       5.9       6.5       7.44     ...           NaN       8.1       NaN       NaN       NaN       NaN

   saf_tot_11  com_tot_11  eng_tot_11  aca_tot_110         8.0         7.7         7.5         7.91         8.5         8.1         8.2         8.42         8.2         7.3         7.5         8.03         7.3         6.7         7.1         7.94         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.              391  01M450                 EAST SIDE COMMUNITY HS              192  01M515                    LOWER EASTSIDE PREP              243  01M539         NEW EXPLORATIONS SCI,TECH,MATH             2554  02M296  High School of Hospitality Management               s

  Total Exams Taken Number of Exams with scores 3 4 or 50                49                                   101                21                                    s2                26                                   243               377                                  1914                 s                                    s
sat_results
      DBN                                    SCHOOL NAME  \0  01M292  HENRY STREET SCHOOL FOR INTERNATIONAL STUDIES1  01M448            UNIVERSITY NEIGHBORHOOD HIGH SCHOOL2  01M450                     EAST SIDE COMMUNITY SCHOOL3  01M458                      FORSYTH SATELLITE ACADEMY4  01M509                        MARTA VALLE HIGH SCHOOL

  Num of SAT Test Takers  SAT Critical Reading Avg. Score  \0                     29                            355.01                     91                            383.02                     70                            377.03                      7                            414.04                     44                            390.0

   SAT Math Avg. Score  SAT Writing Avg. Score  sat_score0                404.0                   363.0     1122.01                423.0                   366.0     1172.02                402.0                   370.0     1149.03                401.0                   359.0     1174.04                433.0                   384.0     1207.0class_size
      DBN  CSD  NUMBER OF STUDENTS / SEATS FILLED  NUMBER OF SECTIONS  \0  01M292    1                            88.0000            4.0000001  01M332    1                            46.0000            2.0000002  01M378    1                            33.0000            1.0000003  01M448    1                           105.6875            4.7500004  01M450    1                            57.6000            2.733333

   AVERAGE CLASS SIZE  SIZE OF SMALLEST CLASS  SIZE OF LARGEST CLASS  \0           22.564286                   18.50              26.5714291           22.000000                   21.00              23.5000002           33.000000                   33.00              33.0000003           22.231250                   18.25              27.0625004           21.200000                   19.40              22.866667

   SCHOOLWIDE PUPIL-TEACHER RATIO0                             NaN1                             NaN2                             NaN3                             NaN4                             NaN
demographics
       DBN                                              Name  schoolyear  \6   01M015  P.S. 015 ROBERTO CLEMENTE                           2011201213  01M019  P.S. 019 ASHER LEVY                                 2011201220  01M020  PS 020 ANNA SILVER                                  2011201227  01M034  PS 034 FRANKLIN D ROOSEVELT                         2011201235  01M063  PS 063 WILLIAM MCKINLEY                             20112012

   fl_percent  frl_percent  total_enrollment prek    k grade1 grade2  \6         NaN         89.4               189   13   31     35     2813        NaN         61.5               328   32   46     52     5420        NaN         92.5               626   52  102    121     8727        NaN         99.7               401   14   34     38     3635        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         413    ...            81      24.7          158         48.2        2820    ...            55       8.8          357         57.0        1627    ...            90      22.4          275         68.6         835    ...            41      23.3          110         62.5        15

   white_per male_num male_per female_num female_per6        2.1     97.0     51.3       92.0       48.713       8.5    147.0     44.8      181.0       55.220       2.6    330.0     52.7      296.0       47.327       2.0    204.0     50.9      197.0       49.135       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   200610  Total Cohort  01M448    UNIVERSITY NEIGHBORHOOD HIGH SCHOOL   200617  Total Cohort  01M450             EAST SIDE COMMUNITY SCHOOL   200624  Total Cohort  01M509                MARTA VALLE HIGH SCHOOL   200631  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%                3610           124              53                     42.7%                4217            90              70                     77.8%                6724            84              47                       56%                4031           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             ...                                  3610            ...                                  3417            ...                                  6724            ...                                  2331            ...                                  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%                 1610        11                8.9%              20.8%                 4617         3                3.3%               4.3%                 1524         7  8.300000000000001%              14.9%                 2531        14                7.3%              13.3%                 53

   Still Enrolled - % of cohort Dropped Out - n Dropped Out - % of cohort3                         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   Brooklyn1  09X543                   High School for Violin and Dance      Bronx2  09X327        Comprehensive Model School Project M.S. 327      Bronx3  02M280     Manhattan Early College School for Advertising  Manhattan4  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              121          X400    718-842-0687  718-589-9849              9              122          X240    718-294-8111  718-294-8109              6              123          M520  718-935-3477             NaN              9              104          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        NaN1                              NaN        NaN        NaN        NaN2  Then to New York City residents        NaN        NaN        NaN3                              NaN        NaN        NaN        NaN4                              NaN        NaN        NaN        NaN

  priority09  priority10                                         Location 1  \0        NaN         NaN  883 Classon Avenue\nBrooklyn, NY 11225\n(40.67...1        NaN         NaN  1110 Boston Road\nBronx, NY 10456\n(40.8276026...2        NaN         NaN  1501 Jerome Avenue\nBronx, NY 10452\n(40.84241...3        NaN         NaN  411 Pearl Street\nNew York, NY 10038\n(40.7106...4        NaN         NaN  160-20 Goethals Avenue\nJamaica, NY 11432\n(40...

      DBN        lat        lon0  17K548  40.670299 -73.9616481  09X543  40.827603 -73.9044752  09X327  40.842414 -73.9161623  02M280  40.710679 -74.0008074  28Q680  40.718810 -73.806500[5 rows x 61 columns]

合并数据集

现在我们已经完成了全部准备工作,我们可以用 DBN 列将数据组合在一起了。最终,我们将会从原始数据集得到一个有着上百列的数据集。当我们合并它们,请注意有些数据集中会丢失了 sat_result 中出现的高中。为了解决这个问题,我们需要使用 outer 方法来合并缺少行的数据集,这样我们就不会丢失数据。在实际分析中,缺少数据是很常见的。能够展示解释和解决数据缺失的能力是构建一个作品集的重要部分。

你可以在阅读关于不同类型的合并。

接下来的代码,我们将会:

  • 循环遍历 data 文件夹中的每一个条目。

  • 输出条目中的非唯一的 DBN 码数量。

  • 决定合并策略 - inner 或 outer

  • 使用 DBN 列将条目合并到 DataFrame full 中。

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
survey0ap_20101sat_results0class_size0demographics0graduation0hs_directory0

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-02rr_s                                    8.484298e-02rr_t                                   -6.604290e-02rr_p                                    3.432778e-02N_s                                     1.399443e-01N_t                                     9.654314e-03N_p                                     1.397405e-01saf_p_11                                1.050653e-01com_p_11                                2.107343e-02eng_p_11                                5.094925e-02aca_p_11                                5.822715e-02saf_t_11                                1.206710e-01com_t_11                                3.875666e-02eng_t_10                                         NaN
aca_t_11                                5.250357e-02saf_s_11                                1.054050e-01com_s_11                                4.576521e-02eng_s_11                                6.303699e-02aca_s_11                                8.015700e-02saf_tot_11                              1.266955e-01com_tot_11                              4.340710e-02eng_tot_11                              5.028588e-02aca_tot_11                              7.229584e-02AP Test Takers                          5.687940e-01Total Exams Taken                       5.585421e-01Number of Exams with scores 3 4 or 5    5.619043e-01SAT Critical Reading Avg. Score         9.868201e-01SAT Math Avg. Score                     9.726430e-01SAT Writing Avg. Score                  9.877708e-01
                                            ...
SIZE OF SMALLEST CLASS                  2.440690e-01SIZE OF LARGEST CLASS                   3.052551e-01SCHOOLWIDE PUPIL-TEACHER RATIO                   NaN
schoolyear                                       NaN
frl_percent                            -7.018217e-01total_enrollment                        3.668201e-01ell_num                                -1.535745e-01ell_percent                            -3.981643e-01sped_num                                3.486852e-02sped_percent                           -4.413665e-01asian_num                               4.748801e-01asian_per                               5.686267e-01black_num                               2.788331e-02black_per                              -2.827907e-01hispanic_num                            2.568811e-02hispanic_per                           -3.926373e-01white_num                               4.490835e-01white_per                               6.100860e-01male_num                                3.245320e-01male_per                               -1.101484e-01female_num                              3.876979e-01female_per                              1.101928e-01Total Cohort                            3.244785e-01grade_span_max                         -2.495359e-17expgrade_span_max                                NaN
zip                                    -6.312962e-02total_students                          4.066081e-01number_programs                         1.166234e-01lat                                    -1.198662e-01lon                                    -1.315241e-01Name: sat_score, dtype: float64

这给了我们一些我们需要探索的内在规律:

  • total_enrollment 与 sat_score 强相关,这是令人惊讶的,因为你曾经认为越小的学校越专注于学生就会取得更高的成绩。

  • 女生所占学校的比例(female_per) 与 SAT 成绩呈正相关,而男生所占学生比例(male_per)成负相关。

  • 没有问卷与 SAT 成绩成正相关。

  • SAT 成绩有明显的种族不平等(white_perasian_perblack_perhispanic_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 ARTS143                                      NaN148    KINGSBRIDGE INTERNATIONAL HIGH SCHOOL203                MULTICULTURAL HIGH SCHOOL294      INTERNATIONAL COMMUNITY HIGH SCHOOL304          BRONX INTERNATIONAL HIGH SCHOOL314                                      NaN317            HIGH SCHOOL OF WORLD CULTURES320       BROOKLYN INTERNATIONAL HIGH SCHOOL329    INTERNATIONAL HIGH SCHOOL AT PROSPECT331               IT TAKES A VILLAGE ACADEMY351    PAN AMERICAN INTERNATIONAL HIGH SCHOOName: 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 SCH92                    ELEANOR ROOSEVELT HIGH SCHOOL100                    TALENT UNLIMITED HIGH SCHOOL111            FIORELLO H. LAGUARDIA HIGH SCHOOL OF229                     TOWNSEND HARRIS HIGH SCHOOL250    FRANK SINATRA SCHOOL OF THE ARTS HIGH SCHOOL265                  BARD HIGH SCHOOL EARLY COLLEGEName: 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 SCHOOL98                    STUYVESANT HIGH SCHOOL157             BRONX HIGH SCHOOL OF SCIENCE161    HIGH SCHOOL OF AMERICAN STUDIES AT LE176           BROOKLYN TECHNICAL HIGH SCHOOL229              TOWNSEND HARRIS HIGH SCHOOL243    QUEENS HIGH SCHOOL FOR THE SCIENCES A260      STATEN ISLAND TECHNICAL HIGH SCHOOLName: School Name, dtype: object

通过 google 搜索解释了那些大多是高选择性的学校,你需要经过测试才能进入。这就说明了为什么这些学校会有高的 AP 通过人数。

包装故事

在数据科学中,故事不可能真正完结。通过向其他人发布分析,你可以让他们拓展并且运用你的分析到他们所感兴趣的方向。比如在本文中,这里有一些角度我们没有完成,并且可以探索更加深入。

一个开始讲述故事的最好方式就是尝试拓展或者复制别人已经完成的分析。如果你觉得采取这个方式,欢迎你拓展这篇文章的分析,并看看你能发现什么。如果你确实这么做了,请在下面评论,那么我就可以看到了。

下一步

如果你做的足够多,你看起来已经对用数据讲故事和构建你的第一个数据科学作品集有了很好的理解。一旦你完成了你的数据科学工程,发表在 Github 上是一个好的想法,这样别人就能够与你一起合作。

译文出处

via: https://www.dataquest.io/blog/data-science-portfolio-project/

作者:Vik Paruchuri 译者:Yoo-4x 校对:wxy


0人推荐
随时随地看视频
慕课网APP