Introduction
过去的几期推文中我们对Python的基本语法进行了介绍,由于该部分内容的缺失,导致在NumPy的更新中一直受到基本语法的掣肘。
在我们对这些内容基本有了基本了解之后,这次开坑的Pandas部分我们将更加自由和游刃有余地实现更多功能。
Pandas是一个建立在 NumPy 基础之上用于数据分析和操作的 Python 软件库,它为操作数值表格和时间序列提供数据结构和运算操作,并具有一定的可视化能力。
❝关于Pandas
说起Pandas这个名字,本身就有够奇怪的。为什么一个处理表格的库会叫做「熊猫」?是出于致敬传奇创始人的爱好吗?
实际上,由于Pandas的设计初衷是用于计量经济学的数据分析中,因此从该领域的专业术语「Panel Data」(面板数据)中派生出了Pandas的名字。
此外,还有一个像模像样但是并非事实的说法就是:Pandas指的是「Python Data Analysis」的缩写。
对于地球科学领域而言,我们实际工作中会涉及到各式各样的数据处理。但是我们最终都需要将它们统计出特定的特征以用于描述现象,或解释原理。
如某个要素的均值、总和等,A与B之间的关系,某个时间段内的变化趋势等。
Pandas可以帮助我们快速、高效地处理这些数据,从而便于从中提取有价值的信息。
今天的故事,就从Pandas的基本数据结构和索引开始吧!
Pandas的数据结构
Pandas中有3种基本的数据结构,分别是Series、DataFrame和MultiIndex。
简而言之,Series可以看做一个只有一列的表格;DataFrame则与我们常用的Excel表格类似,是一个较为自由的二维表格;MultiIndex则是一种多级索引的表格结构。
由于MultiIndex的复杂性本期暂不做深入介绍,Series和DataFrame即可满足我们大多数的应用场景。
Series
前面我们提到,Series(序列)可以看做一个只有一列的表格。与一维数组不同,Series拥有行名和列名。
Series和DataFrame既可以使用标签(行、列名)索引,也可以使用位置索引(第M行,第N列),因此可以更便捷地索引和操作数据。
我们可以使用多种方式来创建Series,下面我们来看一些例子。
import pandas as pd
# 使用列表创建Series
temperature = [10, 15, 20, 25, 30]
ser = pd.Series(temperature, index=["2021-01-01", "2021-01-02", "2021-01-03", "2021-01-04", "2021-01-05"], name="Temperature")
print(ser, '\n')
print(ser.index) # 行索引
print(ser.values) # 值
print(ser.name) # 名称
print(ser.dtype) # 数据类型
print(ser.shape) # 形状
print(ser.ndim) # 维度
print(ser.size) # 大小
2021-01-01 10
2021-01-02 15
2021-01-03 20
2021-01-04 25
2021-01-05 30
Name: Temperature, dtype: int64
Index(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05'], dtype='object')
[10 15 20 25 30]
Temperature
int64
(5,)
1
5
这里我们使用了列表来创建Series,并指定了行列名。同时,输出了部分Series的基本信息。
我们也可以使用字典和数组等来创建Series:
# 使用数组创建Series
import numpy as np
data = np.random.rand(5) * 10
ser = pd.Series(data)
print(ser, '\n')
# 使用字典创建Series
precipitation = {'2019-01-01': 0.5, '2019-01-02': 0.6, '2019-01-03': 0.7}
ser = pd.Series(precipitation)
print(ser)
0 8.206034
1 4.538582
2 2.943366
3 5.961249
4 1.947226
dtype: float64
2019-01-01 0.5
2019-01-02 0.6
2019-01-03 0.7
dtype: float64
可以看到,我们使用数组创建Series时没有指定index
,因此默认的index
是从0开始的。如果我们想指定index
,除了创建时对Series()函数传入index
参数外,还可以对Series的index
参数赋值来指定,name
参数和Series的值同理。
而我们使用字典创建时,由于字典的键值本身就存在对应关系,因此字典的key
自动成为了index
。
data = np.random.rand(5) * 10
ser = pd.Series(data)
print(ser, '\n')
ser.name = 'Random Data' # 赋值修改Series的name属性
ser.index = ['A', 'B', 'C', 'D', 'E'] # 赋值修改Series的index属性
ser['A'] = 100
print(ser)
0 8.465683
1 9.895826
2 7.659089
3 7.852485
4 0.819119
dtype: float64
A 100.000000
B 9.895826
C 7.659089
D 7.852485
E 0.819119
Name: Random Data, dtype: float64
DataFrame
DataFrame(数据帧,或数据框)是Pandas中最重要的数据结构,它可以用来存储和处理表格数据。DataFrame可以理解为一组有序的、长度相同的二维数据,每一列可以有不同的类型(数值、字符串、布尔值等)。
使用DataFrame简化数据处理步骤,可以极大地解放我们在Excel中拖表计算的繁琐工作。
DataFrame的创建方式同样多样化,下面我们也来看看简单的例子:
# 使用列表创建DataFrame
temperature = [20, 21, 19, 22, 20, 21, 20]
humidity = [60, 65, 55, 70, 60, 65, 60]
precipitation = [0.5, 0.6, 0.4, 0.7, 0.5, 0.6, 0.5]
df = pd.DataFrame([temperature, humidity, precipitation], index=['temperature', 'humidity', 'precipitation'])
print(df, '\n')
df = df.T
print(df)
0 1 2 3 4 5 6
temperature 20.0 21.0 19.0 22.0 20.0 21.0 20.0
humidity 60.0 65.0 55.0 70.0 60.0 65.0 60.0
precipitation 0.5 0.6 0.4 0.7 0.5 0.6 0.5
temperature humidity precipitation
0 20.0 60.0 0.5
1 21.0 65.0 0.6
2 19.0 55.0 0.4
3 22.0 70.0 0.7
4 20.0 60.0 0.5
5 21.0 65.0 0.6
6 20.0 60.0 0.5
这里我们假定了某个地区的气温、湿度和降水,并将这三要素的列表整合到了同一个DataFrame中。由于列表默认按行排列,因此我们使用转置.T
对该数据帧进行了旋转(实际上,当我们后面了解了Pandas的索引方式后,就可以按列添加数据而不需要进行这样的操作了)。
# 从数组创建DataFrame
data = np.random.rand(5, 3) * 100
df = pd.DataFrame(data, columns=['A', 'B', 'C'])
print(df, '\n')
# 从字典创建DataFrame
data = {'temperature': [22, 23, 21, 20, 19], 'humidity': [60, 65, 70, 75, 80], 'pressure': [1013, 1015, 1018, 1020, 1022]}
df = pd.DataFrame(data)
print(df)
A B C
0 50.327108 2.472678 77.686190
1 57.443441 79.428833 40.798433
2 7.028998 32.522689 73.435392
3 97.450968 17.192801 62.600331
4 14.854463 63.912453 90.014157
temperature humidity pressure
0 22 60 1013
1 23 65 1015
2 21 70 1018
3 20 75 1020
4 19 80 1022
数组和字典同样可以创建Pandas数据帧,对于数组而言,其排列方式与DataFrame一致;而字典的键key
依然被读取为列名(DataFrame中,实际上列名的差异才代表各数据间的本质区别,而行名只是同一列数据下特定内容的标签),值value
则被读取为数据。
我们在使用数组创建DataFrame时,通过传入columns
参数指定了列名。这是DataFrame与Series不一样的地方,由于Series只有一列,因此使用name
参数来表示唯一的列名。
同样,我们可以通过赋值对columns
等参数进行修改、赋值等操作。
data = {'longitude': [10.0, 20.0, 30.0],
'latitude': [40.0, 50.0, 60.0],
'elevation': [70.0, 80.0, 90.0],
'temperature': [100.0, 110.0, 120.0],
'humidity': [130.0, 140.0, 150.0],
'pressure': [160.0, 170.0, 180.0]
}
df = pd.DataFrame(data)
print(df, '\n')
df.index = ['A', 'B', 'C']
df.columns = ['Longitude', 'Latitude', 'Elevation', 'Temperature', 'Humidity', 'Pressure']
print(df, '\n')
longitude latitude elevation temperature humidity pressure
0 10.0 40.0 70.0 100.0 130.0 160.0
1 20.0 50.0 80.0 110.0 140.0 170.0
2 30.0 60.0 90.0 120.0 150.0 180.0
Longitude Latitude Elevation Temperature Humidity Pressure
A 10.0 40.0 70.0 100.0 130.0 160.0
B 20.0 50.0 80.0 110.0 140.0 170.0
C 30.0 60.0 90.0 120.0 150.0 180.0
Pandas数据索引
学习了NumPy的索引机制后,Pandas是索引机制则也简单明了。但由于行、列名的存在,Pandas的索引机制相较数组更为灵活。
Pandas的索引机制可以分为两类:
-
标签索引:通过标签(行、列名)来索引数据。
-
位置索引:通过位置(行、列位置)来索引数据。
下面我们直接通过案例来说明其基本用法:
data = {'longitude': [10.0, 20.0, 30.0],
'latitude': [40.0, 50.0, 60.0],
'elevation': [70.0, 80.0, 90.0],
'temperature': [100.0, 110.0, 120.0],
'humidity': [130.0, 140.0, 150.0],
'pressure': [160.0, 170.0, 180.0]
}
df = pd.DataFrame(data)
print(df, '\n')
# 使用标签索引
print(df['longitude'], '\n') # 使用中括号索引单列
print(df.loc[:, 'latitude'], '\n') # 使用loc索引特定行、列标签
print(df.loc[1, ['temperature', 'pressure']], '\n') # 索引特定行、列标签
print(df.loc[:2, 'humidity':], '\n') # 标签索引的范围为闭区间
# 使用位置索引
print(df.iloc[0, 0], '\n') # 使用iloc索引特定行、列位置
print(df.iloc[1:, 1:3], '\n') # 位置索引的范围为左闭右开(与数组索引一致)
print(df.iloc[:2, 2:-1:2], '\n')
longitude latitude elevation temperature humidity pressure
0 10.0 40.0 70.0 100.0 130.0 160.0
1 20.0 50.0 80.0 110.0 140.0 170.0
2 30.0 60.0 90.0 120.0 150.0 180.0
0 10.0
1 20.0
2 30.0
Name: longitude, dtype: float64
0 40.0
1 50.0
2 60.0
Name: latitude, dtype: float64
temperature 110.0
pressure 170.0
Name: 1, dtype: float64
humidity pressure
0 130.0 160.0
1 140.0 170.0
2 150.0 180.0
10.0
latitude elevation
1 50.0 80.0
2 60.0 90.0
elevation humidity
0 70.0 130.0
1 80.0 140.0
以上就是DataFrame的基本索引操作,Series与之类似。
ser = pd.Series([10.5, 20.7, -5, 3.14, 7.89], index=['a', 'b', 'c', 'd', 'e'], name='Temperature')
print(ser, '\n')
print(ser['a'], '\n') # 由于仅有一列,中括号索引默认为行标签
print(ser[['a', 'b', 'c']], '\n')
print(ser.loc['b'], '\n')
print(ser.loc['d':], '\n')
print(ser.iloc[:-1:2], '\n')
a 10.50
b 20.70
c -5.00
d 3.14
e 7.89
Name: Temperature, dtype: float64
10.5
a 10.5
b 20.7
c -5.0
Name: Temperature, dtype: float64
20.7
d 3.14
e 7.89
Name: Temperature, dtype: float64
a 10.5
c -5.0
Name: Temperature, dtype: float64
于是,我们可以使用索引机制来灵活赋值和修改数据。
df = pd.DataFrame()
df['temperature'] = [20, 21, 19, 22, 20, 21, 20]
df['humidity'] = [60, 65, 55, 70, 60, 65, 60]
df['wind_speed'] = [10, 15, 5, 20, 10, 15, 10]
df['rainfall'] = [0, .1, 0, 2, 0, .5, 0]
df['weather'] = 'Sunny'
df.index = ['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05', '2020-01-06', '2020-01-07']
print(df, '\n')
df.loc['2020-01-01', 'temperature'] += 273.15
df.loc['2020-01-02', 'rainfall'] *= 1000
df.iloc[3, 1] = 1e4
df.loc['2020-01-04', 'weather'] = 'Rainy'
print(df)
temperature humidity wind_speed rainfall weather
2020-01-01 20 60 10 0.0 Sunny
2020-01-02 21 65 15 0.1 Sunny
2020-01-03 19 55 5 0.0 Sunny
2020-01-04 22 70 20 2.0 Sunny
2020-01-05 20 60 10 0.0 Sunny
2020-01-06 21 65 15 0.5 Sunny
2020-01-07 20 60 10 0.0 Sunny
temperature humidity wind_speed rainfall weather
2020-01-01 293.15 60 10 0.0 Sunny
2020-01-02 21.00 65 15 100.0 Sunny
2020-01-03 19.00 55 5 0.0 Sunny
2020-01-04 22.00 10000 20 2.0 Rainy
2020-01-05 20.00 60 10 0.0 Sunny
2020-01-06 21.00 65 15 0.5 Sunny
2020-01-07 20.00 60 10 0.0 Sunny
后记
结束了NumPy和Python基本语法的学习后,后续我们的内容将具有更为实际的使用价值,本次关于Pandas的引入将为我们后续深入学习Pandas处理各种类型的表格打下基础。
毫无疑问,表格在任何学科中都不可或缺,Pandas为解放手动拖表计算的繁琐操作提供了一种高效、易用、直观的处理方式。后续我们将涉猎表格的计算、数据清洗、平滑去噪、时间序列分析等内容,相较于数组和基本语法这些更为底层的概念,这些内容更贴近我们的实际工作中最直接的工具。相信会有助于我们学习、科研工作的开展。
那么,我们下期再见!
Manuscript: RitasCake
Proof: Philero; RitasCake
获取更多资讯,欢迎订阅微信公众号:Westerlies
跳转和鲸社区,云端运行本文案例。https://www.heywhale.com/mw/project/66221ce2e584e69fbfef87ba