专题——使用Python创建可供多重比较的数据框

发布于 2021-11-04  195 次阅读


更新:感谢凌空的桨一文《R语言数据处理——表格转换》的启发以及FTDdata一文《python--pandas长宽数据转换》的帮助,其实本文思路的专业叫法为“数据框长宽数据转换”,总结下来,对于python来说一个.melt()函数足以解决本文这么多废话要解决的问题。

这个故事告诉我们,基本概念还是要弄懂的,不然容易给自己添很大的麻烦。


以下为原文:

两组样本之间的比较由于数据结构比较简单,自己输入数据或直接从Excel中读取数据为元组或列表就可以了。而多组数据之间的比较则相对复杂,根据实验设计需求,有时候我们的分组会远多于三组,python中用于多组数据的多重比较对数据框(DataFrame)的接受较好。


数据框是一种类似于表格的二维数据结构,其可认为是由一维数据结构数组(Array)所组成。事实上,python严格意义上是没有数组这个概念的,可以用列表和元组实现数组的功能(参考链接)。也可以通过整理好的特定形式的列表和元组,借助numpy和pandas模块来将这些数据分别整理成类似数组和数据框的格式,并实现相应的数据处理。我们通过一个案例来简单理解一下数据框的构建。

(先来段废话)假如班里有三位同学经常迟到,但他们总是不承认班级时钟的准确性,经常调慢自己手表后厚着脸皮说自己没迟到。通常老师对这三个孩纸也是睁一只眼闭一只眼。这一天,国家授时中心来到了这所学校,本着“科技以人为本”的原则,捐给这个班级一台原子钟。这下可好了,这台原子钟不仅走时准确,而且具备记录功能,可以将同学们迟到的时间记录精确到0.01秒。教务处适时展开学风整顿活动,要求每班揪出三位典型,记为一般迟到,中度迟到,严重迟到。若其中两名同学迟到时间并列(即没有统计学差异),那么按高等级记并列迟到。(以上皆为胡说,接下来进入正题)一星期后,根据统计数据,小A这星期迟到时间分别为20.15分钟、12.53分钟、8.12分钟、9.46分钟、14.42分钟,小B这星期迟到时间分别为3.14分钟、2.58分钟、4.01分钟、6.66分钟、2.92分钟,小C这星期迟到时间分别为5.52分钟、7.96分钟、5.19分钟、5.25分钟、6.30分钟。

接下来,我们试着将以上材料提供的数据整理成能够为python进行多组数据比较所接受的数据框的形式。

一、数据采集

根据以上材料,我们可以将三位同学这一周的迟到时间生成3个列表:

A = [20.15, 12.53, 8.12, 9.46, 14.42]
B = [3.14, 2.58, 4.01, 6.66, 2.92]
C = [5.52, 7.96, 5.19, 5.25, 6.30]

也可以将以上数据合并到一个字典中:

late_time = {"A": [20.15, 12.53, 8.12, 9.46, 14.42], "B": [3.14, 2.58, 4.01, 6.66, 2.92], "C": [5.52, 7.96, 5.19, 5.25, 6.30]}

现实中,我们的实验数据多数情况下是整理到Excel表格中,后面会专门写一篇如何获取Excel数据的文章。

二、数据整理

回到概念,本文前面我们提及二维数据框由一维数组所组成。在本案例中,我们可以将每位同学每天迟到的时间记成一个元组,这个元组要包含最起码两个元素:该同学的名字,该同学这一天迟到的时间。不过最好让用于形成数据框的元组多包含一个元素,为该元组编个号,可以方面后续可能存在的检索工作。以上数据我们可以整理成如下15个元组,并将其放入一个列表中,命名为late_tuple_list:

late_tuple_list = [(1, 'A', 20.15), (2, 'A', 12.53), (3, 'A', 8.12), (4, 'A', 9.46), (5, 'A', 14.42), (6, 'B', 3.14), (7, 'B', 2.58), (8, 'B', 4.01), (9, 'B', 6.66), (10, 'B', 2.92), (11, 'C', 5.52), (12, 'C', 7.96), (13, 'C', 5.19), (14, 'C', 5.25), (15, 'C', 6.3)]

15个元组手输确实已经够窒息了,万一要是需要收集115个元组岂不是要累死?能看到今天这篇文章的读者对python的基本语法最起码会略知一二。我们可以通过循环和遍历字典的方式自动生成以上元组列表。实现代码如下:

late_dict = {"A": [20.15, 12.53, 8.12, 9.46, 14.42], "B": [3.14, 2.58, 4.01, 6.66, 2.92], "C": [5.52, 7.96, 5.19, 5.25, 6.30]}
h = 1
late_tuple_list = []
for i in range(len(late_dict)):
    for j in range(len(list(late_dict.values())[i])):
        late_tuple_list.append((h, list(late_dict.keys())[i], list(late_dict.values())[i][j]))
        h += 1

得到一个包含三位学生迟到时间的元组列表late_tuple_list之后,我们就可以调用python的numpy和pandas模块先后生成数组和数据框了:

import numpy as np  # 导入numpy模块
df_pre = np.rec.array(late_tuple_list, dtype=[('idx', '<i4'), ('student', '|S8'), ('late_time', '<f8')])

其中np.rec.arraydtype变量意思为data type,相当于声明每个元组中三个元素的名字和数据类型(其实我对dtype要传入的参数也还没弄太明白)。“idx”意为每个元组的第一个元素为该元组的id,“<i4”表示"idx"的数据类型为小于32位整形数;“student”意为每个元组的第二个元素为该元组的学生代码,“|S8”表示“student”的数据类型为64位字符串;“late_time”意为每个元组的第三个元素为该元组的学生迟到的时间,“<f8”表示“late_time”的数据类型为小于64位浮点数(参考链接)。

由此我们建立好了包含三位学生迟到时间的元组,df_pre输出结果和类型如下:

[( 1, b'A', 20.15) ( 2, b'A', 12.53) ( 3, b'A',  8.12) ( 4, b'A',  9.46)
 ( 5, b'A', 14.42) ( 6, b'B',  3.14) ( 7, b'B',  2.58) ( 8, b'B',  4.01)
 ( 9, b'B',  6.66) (10, b'B',  2.92) (11, b'C',  5.52) (12, b'C',  7.96)
 (13, b'C',  5.19) (14, b'C',  5.25) (15, b'C',  6.3 )]  # df_pre输出结果
<class 'numpy.recarray'>  # df_pre输出类型

三、数据框生成

离最终目标——获取用于数据统计的数据框只剩一步了:有请pandas模块闪亮登场:

import pandas as pd
late_df = pd.DataFrame(df_pre)

终于大功告成,此时late_df的输出结果和类型如下:

    idx student  late_time
0     1    b'A'      20.15
1     2    b'A'      12.53
2     3    b'A'       8.12
3     4    b'A'       9.46
4     5    b'A'      14.42
5     6    b'B'       3.14
6     7    b'B'       2.58
7     8    b'B'       4.01
8     9    b'B'       6.66
9    10    b'B'       2.92
10   11    b'C'       5.52
11   12    b'C'       7.96
12   13    b'C'       5.19
13   14    b'C'       5.25
14   15    b'C'       6.30
<class 'pandas.core.frame.DataFrame'>

得到这样的结果,拿去做统计就完全没问题啦!

四、代码总结

# 数据采集
A = [20.15, 12.53, 8.12, 9.46, 14.42]
B = [3.14, 2.58, 4.01, 6.66, 2.92]
C = [5.52, 7.96, 5.19, 5.25, 6.30]

# 将采集得到的数据编入字典
late_time = {"A": [20.15, 12.53, 8.12, 9.46, 14.42], "B": [3.14, 2.58, 4.01, 6.66, 2.92], "C": [5.52, 7.96, 5.19, 5.25, 6.30]}

# 将数据写为可生成数据框的元组
late_dict = {"A": [20.15, 12.53, 8.12, 9.46, 14.42], "B": [3.14, 2.58, 4.01, 6.66, 2.92], "C": [5.52, 7.96, 5.19, 5.25, 6.30]}
h = 1
late_tuple_list = []
for i in range(len(late_dict)):
    for j in range(len(list(late_dict.values())[i])):
        late_tuple_list.append((h, list(late_dict.keys())[i], list(late_dict.values())[i][j]))
        h += 1

# 生成数据框
import numpy as np  # 导入numpy模块
df_pre = np.rec.array(late_tuple_list, dtype=[('idx', '<i4'), ('student', '|S8'), ('late_time', '<f8')])

import pandas as pd
late_df = pd.DataFrame(df_pre)
# 大功告成