Python for Kids
  • 0 前言
  • 1 编程环境准备
  • 2 运算符和表达式
  • 3 掌握变量
  • 4 字符串
  • 5 获取用户的输入
  • 6 条件判断
  • 7 条件判断实操
  • 8 FOR循环
  • 9 循环和列表
  • 10 WHILE循环
  • 11 WHILE循环实操
  • 12 WHILE循环再实操
  • 13 多重循环
  • 14 再谈列表
  • 15 初见函数
  • 16 函数实操
  • 17 选择排序
  • 18 冒泡排序
  • 19 递归算法之一
  • 20 递归算法实操
  • 21 快速排序
  • 22 汉诺塔游戏
  • 23 递推算法
  • 24 分治算法
  • 25 集合与组合
  • 26 贪心算法
  • 27 字典和键值对
  • 28 广度优先搜索算法
  • 29 数组和向量化计算
  • 30 随机和模拟
  • 31 数据可视化
  • 32 文件读取和分析
Powered by GitBook
On this page
  • 大纲
  • 什么是数据分析
  • 文件读取
  • 一元统计分析
  • 二元统计分析
  • 练习:

Was this helpful?

32 文件读取和分析

数据分析是一种归纳思维

大纲

  • 什么是数据分析

  • 文件读取

  • 一元统计分析

  • 二元统计分析

  • 练习

什么是数据分析

归纳思维是一种重要的理性思考工具,所谓归纳就是观察、实验和调查和问题有关的信息,从中总结概括出一般规律,以帮助解答问题。当我们观察一百次下雨,收集下雨前后时间段的相关信息,例如云层、湿度、温度等数据,就可以归纳出导致下雨的一般规律,并能够预测下雨的可能性。因此,收集分析数据是非常重要的研究手段。

广义的数据分析有四种不同的深度,分别是:描述、解释、预测、控制。描述只是揭示客观事实,例如描述统计历史的下雨的水量最大值、云层厚度平均值等等,解释是解释不同因素的关系,例如云层厚度和下雨水量这两个因素之间的关系是否存在。预测是当前述的多个因素存在关联时,进行预测,例如观察到某时某点的云层厚度,预测后续下雨的水量多少。控制是利用前面发现的关系和预测结果,例如预测到未来下雨水量可能过大,为了避免洪涝,预先干扰云层聚集。

从分析步骤上来看,通常会有几个步骤:

  • 先提出一个问题

  • 针对这个问题,进行数据收集

  • 处理数据成一个表格形式

  • 利用统计学方法对数据进行分析,解答问题

  • 总结报告

本课内容主要是学习基本的描述性统计分析,也就是说数据是给定现成的,用常规的统计函数来计算汇总。

文件读取

本书的配套资料中自带了数据集,可以从data目录中看到有iris.csv文件,这一类文件是一种表格类型的数据文件,每一行之间有回车隔开,每一列之间是逗号隔开,第一行是表头。iris数据是一个历史悠久的数据集,它是由植物学家收集整理得到的关于鸢尾花的数据资料。

不过对于初学者来说,如何在python环境中去找到并读取硬盘目录中对应的文件,还是是一个不容易的事情,所以下面我们仔细来介绍一下如果在notebook环境下去读文。

首先你要确认当前noteboo打开时,当前工作目录的位置是什么,你可以通过cd命令来确认,不同的操作系统,你的显示输出可能不一样。

cd
/Users/xccds

然后我们将工作目录转移到本书的目录。

cd Documents/GitHub/AI-with-kids/
/Users/xccds/Documents/GitHub/AI-with-kids

然后可以通过ls命令,看到这个目录下有哪些文件了,其中data目录就是我们存放数据的地方。

ls
README.md         data/             figures/
code/             edit/             refence_notebook/

可以利用python自带的文件读取功能,即open函数来打开这个文件,文件被打开后可以使用readlines函数来读取文件中的每一行,保存到iris变量中,然后需要通过close来关闭文件。

filename = 'data/iris.csv'
f = open(filename)
iris = f.readlines()
f.close()
iris[:6]
['"sepal_length","sepal_width","petal_length","petal_width","species"\n',
 '5.1,3.5,1.4,.2,"Setosa"\n',
 '4.9,3,1.4,.2,"Setosa"\n',
 '4.7,3.2,1.3,.2,"Setosa"\n',
 '4.6,3.1,1.5,.2,"Setosa"\n',
 '5,3.6,1.4,.2,"Setosa"\n']

此时可以看到iris是一个list,它的第一行是表头,后面各行是对应的数据,不同列之间以逗号分隔。这是一个标准的csv文件的样子。

你可以直接使用列表解析方式来读取文件,就象下面一样。

iris = [line for line in open('data/iris.csv')]

再看一下整体这个列表的长度。

len(iris)
151

可以看到iris这个列表,一共有151行,说明如果不包括表头,就有150条数据。取出前三个元素,就得到了表头,和前两列具体的数字,可以看到有五列,前四列分别是花萼长度和宽度、花瓣长度和宽表,最后一列表示花的种属。还可以观察到不同列之间是逗号间隔,每个元素最后还有一个看起来奇怪的字符“\n”,这是表示了换行符号。

我们可以根据前面学到的列表的知识,再用一个列表解析,将这些数据做一些处理,对每一列用strip去除空格回车等符号,再用split进行字符串的分隔,处理后就变成了一个嵌套的列表,也就是说原来列表的每个元素也成为一个列表。

iris_prec = [line.strip().split(',') for line in iris]
iris_prec[:3]
[['"sepal_length"',
  '"sepal_width"',
  '"petal_length"',
  '"petal_width"',
  '"species"'],
 ['5.1', '3.5', '1.4', '.2', '"Setosa"'],
 ['4.9', '3', '1.4', '.2', '"Setosa"']]

一元统计分析

一元统计分析就是只看数据的某个列,或者说某单个特征。所以我们先把第一列数据取出来研究一下,所以这里使用了line[0],因为不需要表头,所以是iris_prec[1:]表示从第二行开始,此外还用float把字符转成了数字,保存在iris_prec_first这个变量中。

iris_prec_first = [float(line[0]) for line in iris_prec[1:]]
iris_prec_first[:3]
[5.1, 4.9, 4.7]

然后我们再将这个数据转成numpy的数组,以方便处理分析。

import numpy as np
iris_one = np.array(iris_prec_first)

我们可以用max函数看一下,这150朵花中,花萼长度最长的是多长?

iris_one.max()
7.9

最短是多长?

iris_one.min()
4.3

平均长度是多长?

iris_one.mean()
5.843333333333334

平均长度衡量了大多数花的长度可能集中在哪个位置附近,但是还需要有一个数字来反映这些数字的分散程度,统计学上通常用标准差来衡量,这个数字越大表示越分散。

iris_one.std()
0.8253012917851409

除了用枯燥的数字来计算这些数据的规律以外,还可以用图形来描述,例如直方图,直方图类似于条状图,它是一种统计汇总方法,对一个连续的数组,先定义一些范围边界,然后看落在这些边界里的数字有多少个,它的作用在于可以看到数据的分布情况。更形象的理解是看作一种排分表,一次全班考试之后,90以上有多少人,80-90之间有多少人,70-80之间有多少人。

%matplotlib inline
import matplotlib.pyplot as plt
plt.hist(iris_one);

前述的数据读取处理有些麻烦,python中还有一个专门用于数据分析的模块pandas,用它来做分析会更为简单方便。

import pandas as pd
iris = pd.read_csv(filename)

使用head函数可以取出前五行数据进行观察。

iris.head()

sepal_length

sepal_width

petal_length

petal_width

species

0

5.1

3.5

1.4

0.2

Setosa

1

4.9

3.0

1.4

0.2

Setosa

2

4.7

3.2

1.3

0.2

Setosa

3

4.6

3.1

1.5

0.2

Setosa

4

5.0

3.6

1.4

0.2

Setosa

iris在此时的数据类型是数据框类型,这是pandas提供的专用于数据分析的数据类型。这种方方正正的表格类的数据,也是大部分数据分析和机器学习会使用的数据类型。在这里我们定义一下常用的数据分析术语。这个数据框的每一行称为一个样本,每一列称为一个特征,像前四个特征都是数值的表示,称为数值特征或连续特征,最后那个species是用字符表示的,称为类别特征或离散特征。

type(iris)
pandas.core.frame.DataFrame

类似的,可以用直方图来绘制出数据的分布情况。

iris.sepal_length.hist();

自然的,pandas也支持计算数据的极值,均值等汇总数字。

iris.sepal_length.max()
7.9
iris.sepal_length.min()
4.3
iris.sepal_length.mean()
5.843333333333335
iris.sepal_length.std()
0.8280661279778629

还可以一次性的计算出四列变量的所有均值,非常方便。

iris.mean()
sepal_length    5.843333
sepal_width     3.057333
petal_length    3.758000
petal_width     1.199333
dtype: float64

这150个样本中有三种花的种属,我们还可以计算分组后的均值,这种计算称为分类汇总,非常类似于Excel中的透视表这种功能。

iris.groupby('species').mean()

sepal_length

sepal_width

petal_length

petal_width

species

Setosa

5.006

3.428

1.462

0.246

Versicolor

5.936

2.770

4.260

1.326

Virginica

6.588

2.974

5.552

2.026

如果是只计算某一个变量的均值,可以在其中加上方括号进行取子集的操作

iris.groupby('species')['sepal_length'].mean()
species
Setosa        5.006
Versicolor    5.936
Virginica     6.588
Name: sepal_length, dtype: float64

小结:pandas模块是用于数据分析的重要模块,可以使用read_csv来方便的读取本地文件,产生对应的数据类型是数据框。

二元统计分析

前述内容是只看单个变量的情况,还可以观察研究两个变量之间的关系,例如画出前两个变量之间的散点图。

plt.scatter(iris.sepal_length, iris.sepal_width);

看起来这两个变量之间的关系是负相关,我们可以进一步计算相关系数来确认这一点。可以使用numpy模块中的corrcoef函数来计算相关系数,它会返回一个二维数组,我们只需要看非对角线上的值即可,这个-0.11说明这两个特征之间是负的关系。但是这个结论看起来不合理,因为花的长度更大,按道理说宽度也会更大,这种不合常理的结论是为什么呢?

np.corrcoef(iris.sepal_length, iris.sepal_width)
array([[ 1.        , -0.11756978],
       [-0.11756978,  1.        ]])

让我们细分一下,根据种属来分组计算相关系数,可以看到虽然整体相关性为负,但是分组来看,为正

iris.groupby('species').apply(lambda x: np.corrcoef(x.sepal_length, x.sepal_width)[0,1])
species
Setosa        0.742547
Versicolor    0.525911
Virginica     0.457228
dtype: float64

让我们重新来绘制散点图,这次将种属这个变量作为颜色画在图上,非常清晰的看到,分组来看,各组的相关性都是正的。这种结论才是合理正确的。

color_list = ['blue']*50 + ['red']*50+ ['grey']*50
plt.scatter(iris.sepal_length, iris.sepal_width,color=color_list);

小结:二元统计分析是研究两个特征之间的关系,相关系数和散点图是一种有用的分析工具;我们还发现,分组后体现出来的规律,在合为整体时可能结论相反,这种现象称为辛普森悖论。

练习:

写一个函数来计算相关系数,注意不要使用现有numpy中计算相关系数的函数

def corrcoef(x,y):
    x_mean = np.mean(x)
    y_mean = np.mean(y)
    cov = np.mean((x-x_mean)*(y-y_mean))
    output = cov/(np.std(x)*np.std(y))
    return output
corrcoef(iris.sepal_length, iris.sepal_width)
-0.11756978413300205

Previous31 数据可视化

Last updated 4 years ago

Was this helpful?