Pandas库使用

之前在大三的时候,就已经接触这个库了,但是那个时候我是拒绝使用的,因为感觉好复杂。Python命名有更加简单的库去处理excel和csv文件。但是后来发现无法绕过去,因为pandas在数据科学中被广泛使用,其功能特别强大。最近参加kaggele竞赛的时候,提交结果的时候通常是csv文件。想了想,算了系统的学习一下吧。

数据类型

Pandas库有很一些自定义的数据结构,例如DataFrame和Series。下面我们对这些数据结构进行详细的介绍。

Series

它是一维标记数组,可以存储任意数据类型:int/string/float/Python对象,创建Series方法例子:

1
2
s = Series(data, index = index)
# data可以是Python字典/ndarray/标量值

DataFrame

它是二维标记数据结构,列可以是不同的数据类型,是最常用的pandas对象,如同Series对象一样接受多种输入:lists/dicts/Series/DataFrame

属性

DataFrame有很多属性,下面我们介绍一下常用的属性。

index

index属性可以查看哪些值作为了行索引。例如

1
2
3
4
5
6
7
8
9
10
11
12
frame = pd.DataFrame(np.random.rand(4,4),index=list('abcd'),columns=list('ABCD'))

frame
Out[5]:
A B C D
a 0.542065 0.009684 0.764196 0.115261
b 0.470836 0.297647 0.899719 0.474166
c 0.101683 0.187357 0.638858 0.353924
d 0.227391 0.917419 0.592218 0.814630

frame.index
Out[6]: Index(['a', 'b', 'c', 'd'], dtype='object')

columns

columns属性可以查看哪些值作为了列索引。例如

1
2
frame.columns
Out[7]: Index(['A', 'B', 'C', 'D'], dtype='object')

索引

取DataFrame的方式主要有两种,第一种是借助loc方法,第二种方法是借助iloc方法。

loc

使用loc方法索引的时候,主要方法为

1
DataFrame.loc[行索引,列索引]

那么如何知道行索引和列索引取什么值呢?这里就用到了我们上面说到的indexcolumns属性。例如上面index属性值为Index(['a', 'b', 'c', 'd'], dtype='object'),那么我们就可以取'a''b''c''d'作为行索引。同样的,我们可以取'A''B''C''D'作为行索引。所以,例如

1
2
frame.loc['a','A']
Out[9]: 0.5420647140128387

这里的索引之所以加上'',为str类型,是因为在属性indexcolumns中这些值均为str类型。

另外,我们像在Python中Numpy和list那样采用切片的方式取数据,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 取前两行对应数据
frame.loc['a':'b',:]
Out[12]:
A B C D
a 0.542065 0.009684 0.764196 0.115261
b 0.470836 0.297647 0.899719 0.474166

# 取前两列对应数据
frame.loc[:,'A':'B']
Out[13]:
A B
a 0.542065 0.009684
b 0.470836 0.297647
c 0.101683 0.187357
d 0.227391 0.917419

# 取前两行和前两列对应数据
frame.loc['a':'b','A':'B']
Out[14]:
A B
a 0.542065 0.009684

上面的例子取的都是连续的行和列,若取第一行和第四行、第一列和第四列对应的数据,则

1
2
3
4
5
frame.loc[['a','d'],['A','D']]
Out[15]:
A D
a 0.542065 0.115261
d 0.227391 0.814630

iloc

使用iloc方法索引更加简单,无需知道我们的行索引和列索引,只需要知道坐标即可,主要方法为:

1
DataFrame.iloc[行标号,列标号]

这里的行标号和列标号即为要取的值在数据中的位置(行索引和列索引不占编号)。例如

1
2
frame.iloc[0,0]
Out[10]: 0.5420647140128387

同样的,我们像在Python中Numpy和list那样采用切片的方式取数据,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 取前两行对应数据
frame.iloc[0:2,:]
Out[16]:
A B C D
a 0.542065 0.009684 0.764196 0.115261
b 0.470836 0.297647 0.899719 0.474166

# 取前两列对应数据
frame.iloc[:,0:2]
Out[17]:
A B
a 0.542065 0.009684
b 0.470836 0.297647
c 0.101683 0.187357
d 0.227391 0.917419

# 取前两行和前两列对应数据
frame.iloc[0:2,0:2]
Out[18]:
A B
a 0.542065 0.009684
b 0.470836 0.297647

上面的例子取的都是连续的行和列,若取第一行和第四行、第一列和第四列对应的数据,则

1
2
3
4
5
frame.iloc[[0,3],[0,3]]
Out[19]:
A D
a 0.542065 0.115261
d 0.227391 0.814630

多级索引

多级索引(也称层次化索引)是pandas的重要功能,可以在Series、DataFrame对象上拥有2个以及2个以上的索引。
实质上,单级索引对应Index对象,多级索引对应MultiIndex对象。

MultiIndex对象

创建:

1
2
3
4
5
6
7
8
9
se1=pd.Series(np.random.randn(4),index=[list("aabb"),[1,2,1,2]])
se1

Out[20]:
a 1 -0.235996
2 -0.285382
b 1 -0.731392
2 0.111166
dtype: float64

子集的选取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
se1['a']
Out[21]:
1 -0.235996
2 -0.285382
dtype: float64

se1['a':'b']
Out[22]:
a 1 -0.235996
2 -0.285382
b 1 -0.731392
2 0.111166
dtype: float64

# 甚至能内层选取
se1[:,1]
Out[23]:
a -0.235996
b -0.731392
dtype: float64

loc

和单级索引相同的是,我们可以使用loc方法进行取值,那么哪些值可以作为索引值,也是需要indexcolumns属性得知。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
df1=pd.DataFrame(np.arange(12).reshape(4,3),index=[list("AABB"),[1,1,1,2]],columns=[list("XXY"),[10,11,10]])

df1
Out[27]:
X Y
10 11 10
A 1 0 1 2
1 3 4 5
B 1 6 7 8
2 9 10 11

df1.index
Out[28]:
MultiIndex(levels=[['A', 'B'], [1, 2]],
labels=[[0, 0, 1, 1], [0, 0, 0, 1]])

df1.columns
Out[29]:
MultiIndex(levels=[['X', 'Y'], [10, 11]],
labels=[[0, 0, 1], [0, 1, 0]])

注意到在属性index中,有两个标签分别为levelslabels,其中在levels标签有两个list,在第一个list中存放第一级索引,在第二个list中存放第二级索引。而在labels中也存着两个list,第一个list存放的是DataFrame中各行数据分别属于哪个第一级索引(以下标形式给出),同样的第一个list存放的是DataFrame中各行数据分别属于哪个第二级索引(以下标形式给出)。

另外,在我们生成该数据的时候,使用的index属性第一级索引为"AABB",但是放到levels标签的时候,是经过去重的,所以这也就是需要labels标签的原因。

有了这些准备工具,我们就可以随心所欲的取数据了,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
df1.loc[['A',1],['X',10]]
Out[33]:
X
10 11
A 1 0 1
1 3 4

# 只取行的外层索引,内层索引不可用
df1.loc[['A'],['X',10]]
Out[40]:
X
10 11
A 1 0 1
1 3 4

df1.loc[['A','B'],['X',10]]
Out[49]:
X
10 11
A 1 0 1
1 3 4
B 1 6 7
2 9 10

注意:行索引从行开始取,必须一层层取,取完行索引,才可以取列索引,先取列索引同理。

另外,还有一些高级用法。

例如,每一层都可以赋名

1
2
3
df1.columns.names=['XY','sum']
df1.index.names=['AB','num']
df1

运行结果:

可以创建MultiIndex对象再作为索引

1
2
df1.index=pd.MultiIndex.from_arrays([list("AABB"),[3,4,3,4]],names=["AB","num"])
df1

运行结果:

可以对各级索引进行互换

1
df1.swaplevel('AB','num')

运行结果:

iloc

同样的,我们也可以使用iloc的方法进行索引,这个时候,我们只需要知道数据的坐标即可。无需在乎他们的indexcolumns属性,例如

1
2
df1.iloc[0,0]
Out[39]: 0

处理csv文件

方法为:

1
pandas.read_csv(filepath_or_buffer, sep=', ', delimiter=None, header='infer', names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, iterator=False, chunksize=None, compression='infer', thousands=None, decimal=b'.', lineterminator=None, quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, tupleize_cols=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None)

可以看出这个方法的功能特别强大,我们这里只介绍一些常用的属性。

  • sep:csv文件中的分隔符,一般都是','

参数可选int, list of int, default ‘infer’。用作列名和数据开头的行号,默认行为是推断列名:如果未传递任何名称,则行为与HEADER=0相同,并且从文件的第一行推断列名;如果显式传递列名,则该行为与HEADER=NONE相同。显式传递Header=0以能够替换现有名称。标头可以是整数列表,这些整数指定列上的多索引的行位置,例如[0,1,3]。将跳过未指定的中间行(例如,跳过本例中的2)。请注意,如果SKIP_BLARE_LINES=True,此参数将忽略注释行和空行,因此HEADER=0表示数据的第一行,而不是文件的第一行。

例如,文件ceshi.csv的内容如下:

tc1c2c3
a0510
b1611
c2712
d3813
e4914

默认

默认情况下,读取该csv文件的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
obj_4=pd.read_csv('ceshi.csv')

obj_4
Out[89]:
t c1 c2 c3
0 a 0 5 10
1 b 1 6 11
2 c 2 7 12
3 d 3 8 13
4 e 4 9 14

obj_4.index
Out[90]: RangeIndex(start=0, stop=5, step=1)

obj_4.columns
Out[91]: Index(['t', 'c1', 'c2', 'c3'], dtype='object')

obj_4.loc[0, 't']
Out[88]: 'a'

obj_4.loc[:, 't']
Out[92]:
0 a
1 b
2 c
3 d
4 e
Name: t, dtype: object

obj_4.loc[0, :]
Out[93]:
t a
c1 0
c2 5
c3 10
Name: 0, dtype: object

obj_4.iloc[0, 0]
Out[95]: 'a'

也就是在默认参数情况下,该函数会自动的添加行索引,并将第一行作为列索引。

0

当指定该参数为0的时候,其表现与默认情况下一致:

1
2
3
4
5
6
7
obj_3=pd.read_csv('ceshi.csv',header=0)

obj_4.index
Out[97]: RangeIndex(start=0, stop=5, step=1)

obj_4.columns
Out[98]: Index(['t', 'c1', 'c2', 'c3'], dtype='object')

None

当指定该参数为None的时候,读取数据的时候,不会将第一行作为列索引,而是会作为其数据的一部分。而行索引还是自动分配的。其代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
obj=pd.read_csv('ceshi.csv', header=None)

obj
Out[99]:
0 1 2 3
0 t c1 c2 c3
1 a 0 5 10
2 b 1 6 11
3 c 2 7 12
4 d 3 8 13
5 e 4 9 14

obj.index
Out[100]: RangeIndex(start=0, stop=6, step=1)

obj.columns
Out[101]: Int64Index([0, 1, 2, 3], dtype='int64')

obj.loc[0, 0]
Out[103]: 't'

int

当指定该参数为一个int值的时候,会将改行作为列索引,并忽略之前行。而行索引还是自动分配的。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
obj_5=pd.read_csv('ceshi.csv',header=2)

obj_5
Out[105]:
b 1 6 11
0 c 2 7 12
1 d 3 8 13
2 e 4 9 14

obj_5.index
Out[106]: RangeIndex(start=0, stop=3, step=1)

obj_5.columns
Out[107]: Index(['b', '1', '6', '11'], dtype='object')

list

当header为list的时候,情况为将list中的值对应的行作为列的多级索引。当list中的整数从小到大排列,忽略掉list中没有出现的数字,例如当header=[0,2]的时候,会忽略第2行。其余情况情况并不会忽略,只是会将list中对应的行作为列的多重索引。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
obj_6=pd.read_csv('ceshi.csv',header=[0,2])

obj_6
Out[109]:
t c1 c2 c3
b 1 6 11
0 c 2 7 12
1 d 3 8 13
2 e 4 9 14

obj_6.index
Out[110]: RangeIndex(start=0, stop=3, step=1)

obj_6.columns
Out[111]:
MultiIndex(levels=[['c1', 'c2', 'c3', 't'], ['1', '11', '6', 'b']],
labels=[[3, 0, 1, 2], [3, 0, 2, 1]])

obj_6=pd.read_csv('ceshi.csv',header=[1,2])

obj_6
Out[115]:
a 0 5 10
b 1 6 11
0 c 2 7 12
1 d 3 8 13
2 e 4 9 14

参数list不是从小到大排列的时候,可以看到比较混乱,因为b 1 6 11不仅出现在了索引行,还出现在了数据中,不建议这么使用,可能会出现意想不到的情况。如下:

1
2
3
4
5
6
7
8
9
10
11
obj_6=pd.read_csv('ceshi.csv',header=[2,0])

obj_6
Out[113]:
b 1 6 11
t c1 c2 c3
0 a 0 5 10
1 b 1 6 11
2 c 2 7 12
3 d 3 8 13
4 e 4 9 14

index_col

可选参数:int, sequence or bool, optional,列用作DataFrame的行标签。如果给定序列,则使用多级索引。如果您有一个在每行末尾都有分隔符的格式错误的文件,您可能会考虑INDEX_COL=FALSE,以强制熊猫不使用第一列作为索引(行名)。

从上面可以看到控制header参数,我们可以控制属性columns,即使用那些行作为列的索引。当未指定index_col属性的时候,会自动添加索引。那么如何自定义属性index呢?答案是使用index_col属性。下面的介绍还是以ceshi.csv文件为例。

默认

默认情况下,读取该csv文件的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
obj_4=pd.read_csv('ceshi.csv')

obj_4
Out[89]:
t c1 c2 c3
0 a 0 5 10
1 b 1 6 11
2 c 2 7 12
3 d 3 8 13
4 e 4 9 14

obj_4.index
Out[90]: RangeIndex(start=0, stop=5, step=1)

obj_4.columns
Out[91]: Index(['t', 'c1', 'c2', 'c3'], dtype='object')

obj_4.loc[0, 't']
Out[88]: 'a'

obj_4.loc[:, 't']
Out[92]:
0 a
1 b
2 c
3 d
4 e
Name: t, dtype: object

obj_4.loc[0, :]
Out[93]:
t a
c1 0
c2 5
c3 10
Name: 0, dtype: object

obj_4.iloc[0, 0]
Out[95]: 'a'

也就是在默认参数情况下,该函数会自动的添加行索引,并将第一行作为列索引。

False

当该参数取值为True的时候,会报错,所以只能为False。代码如下,可以看到这种情况下,其结果与默认情况一致。自动的添加行索引,并将第一行作为列索引。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
obj=pd.read_csv('ceshi.csv', index_col=False)

obj
Out[118]:
t c1 c2 c3
0 a 0 5 10
1 b 1 6 11
2 c 2 7 12
3 d 3 8 13
4 e 4 9 14

obj.index
Out[119]: RangeIndex(start=0, stop=5, step=1)

obj.columns
Out[120]: Index(['t', 'c1', 'c2', 'c3'], dtype='object')

int

当该参数为int的时候,会将该参数对应的列作为索引行,并且该列在数据中并不会在出现。并且index属性有可能有name标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
obj_5=pd.read_csv('ceshi.csv',index_col=2)

obj_5
Out[122]:
t c1 c3
c2
5 a 0 10
6 b 1 11
7 c 2 12
8 d 3 13
9 e 4 14

obj_5.index
Out[126]: Int64Index([5, 6, 7, 8, 9], dtype='int64', name='c2')

obj_5.columns
Out[127]: Index(['t', 'c1', 'c3'], dtype='object')

obj_5.loc[5, 't']
Out[128]: 'a'

list

当该参数为list的时候,会将list中对应的列作为行的多级索引,并且这些列不会出现在数据中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
obj_2=pd.read_csv('ceshi.csv',index_col=[0,2])

obj_2.index
Out[130]:
MultiIndex(levels=[['a', 'b', 'c', 'd', 'e'], [5, 6, 7, 8, 9]],
labels=[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4]],
names=['t', 'c2'])

obj_2.columns
Out[131]: Index(['c1', 'c3'], dtype='object')

obj_2.loc[['a',5],'c1']
Out[135]:
t c2
a 5 0
Name: c1, dtype: int64

总结

read_csv函数中,我们使用header参数控制那些行的值作为列索引,默认为第一行作的列索引。而可以使用index_col参数控制哪些列作为行索引,默认为生成编号作为行索引。

参考

pandas.read_csv
python pandas 中 loc & iloc 用法区别
python:pandas——read_csv方法
Pandas详解十三之多级索引MultiIndex(层次化索引)

------ 本文结束------
坚持原创技术分享,您的支持将鼓励我继续创作!

欢迎关注我的其它发布渠道