Python数据科学库大全:NumPy、Pandas、Matplotlib详解
关键词:Python、数据科学库、NumPy、Pandas、Matplotlib
摘要:本文旨在全面深入地介绍Python中用于数据科学的三个核心库——NumPy、Pandas和Matplotlib。首先阐述这三个库在数据科学领域的重要性及背景,接着详细剖析它们的核心概念、算法原理,并结合Python源代码进行具体操作步骤的讲解。同时,给出相关的数学模型和公式,通过项目实战案例展示它们的实际应用。此外,还会介绍它们的实际应用场景、推荐学习所需的工具和资源,最后总结未来发展趋势与挑战,并解答常见问题。
1. 背景介绍
1.1 目的和范围
在当今数据驱动的时代,数据科学已成为各个领域不可或缺的一部分。Python作为一种功能强大且易于学习的编程语言,拥有丰富的数据科学库,为数据处理、分析和可视化提供了便捷的工具。本文的目的是详细介绍NumPy、Pandas和Matplotlib这三个核心库,涵盖它们的基本概念、使用方法、实际应用等方面,帮助读者全面掌握这些库在数据科学中的应用。
1.2 预期读者
本文适合对数据科学感兴趣的初学者,以及希望深入了解Python数据科学库的中级开发者。无论你是刚接触数据科学领域,还是已经有一定的编程基础,都能从本文中获取有价值的信息。
1.3 文档结构概述
本文将按照以下结构进行组织:首先介绍三个库的核心概念与联系,接着详细讲解它们的核心算法原理和具体操作步骤,然后给出相关的数学模型和公式,通过项目实战展示其实际应用,再介绍实际应用场景和推荐相关的工具和资源,最后总结未来发展趋势与挑战,并解答常见问题。
1.4 术语表
1.4.1 核心术语定义
NumPy:是Python的一个开源数值计算扩展库,提供了高性能的多维数组对象和处理这些数组的工具。Pandas:是基于NumPy的一种数据处理和分析工具,提供了高效的数据结构(如DataFrame和Series)来处理结构化数据。Matplotlib:是Python的一个绘图库,用于创建各种静态、动态、交互式的可视化图表。
1.4.2 相关概念解释
多维数组:NumPy中的核心数据结构,是由相同类型元素组成的多维表格。DataFrame:Pandas中的二维表格数据结构,类似于电子表格或SQL中的表。Series:Pandas中的一维数组对象,类似于NumPy的一维数组,但可以有索引标签。
1.4.3 缩略词列表
NDArray:NumPy中的多维数组对象(N-dimensional Array)。
2. 核心概念与联系
2.1 NumPy核心概念
NumPy的核心是多维数组(NDArray)。多维数组是一个由相同类型元素组成的多维表格,每个元素在内存中占据连续的空间,这使得NumPy能够高效地进行数值计算。例如,一个二维数组可以表示一个矩阵。
以下是一个简单的NumPy多维数组示例:
import numpy as np
# 创建一个二维数组
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr)
2.2 Pandas核心概念
Pandas主要提供了两种数据结构:DataFrame和Series。DataFrame是一个二维表格数据结构,它有行索引和列索引,可以存储不同类型的数据。Series是一维数组对象,它有一个索引标签,类似于字典。
以下是一个简单的Pandas DataFrame示例:
import pandas as pd
# 创建一个DataFrame
data = {'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35]}
df = pd.DataFrame(data)
print(df)
2.3 Matplotlib核心概念
Matplotlib的核心是绘图。它提供了多种绘图函数和工具,用于创建各种类型的图表,如折线图、柱状图、散点图等。Matplotlib的绘图过程通常包括创建图形对象、添加坐标轴、绘制图表和显示图表等步骤。
以下是一个简单的Matplotlib折线图示例:
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 创建图形对象和坐标轴
fig, ax = plt.subplots()
# 绘制折线图
ax.plot(x, y)
# 显示图表
plt.show()
2.4 三个库的联系
NumPy是Pandas和Matplotlib的基础。Pandas的数据结构(如DataFrame和Series)底层是基于NumPy的多维数组实现的,这使得Pandas能够高效地处理和分析数据。Matplotlib在绘图时,通常需要使用NumPy或Pandas的数据作为输入,将数据可视化展示出来。因此,这三个库相互协作,共同构成了Python数据科学的基础。
2.5 核心概念原理和架构的文本示意图
NumPy:以多维数组为核心,提供了各种数组操作函数,如数学运算、索引和切片等。Pandas:基于NumPy的多维数组,构建了DataFrame和Series数据结构,提供了数据处理和分析的工具,如数据筛选、排序、聚合等。Matplotlib:接收NumPy或Pandas的数据,通过绘图函数创建各种类型的图表。
2.6 Mermaid流程图
3. 核心算法原理 & 具体操作步骤
3.1 NumPy核心算法原理及操作步骤
3.1.1 数组创建
NumPy提供了多种创建数组的方法,如使用函数、
np.array()函数、
np.arange()函数等。
np.linspace()
import numpy as np
# 使用np.array()创建数组
arr1 = np.array([1, 2, 3])
# 使用np.arange()创建数组
arr2 = np.arange(0, 10, 2)
# 使用np.linspace()创建数组
arr3 = np.linspace(0, 1, 5)
print(arr1)
print(arr2)
print(arr3)
3.1.2 数组操作
NumPy支持各种数组操作,如数学运算、索引和切片等。
import numpy as np
# 创建两个数组
arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])
# 数组加法
result_add = arr1 + arr2
# 数组索引
element = arr1[1]
# 数组切片
slice_arr = arr1[0:2]
print(result_add)
print(element)
print(slice_arr)
3.2 Pandas核心算法原理及操作步骤
3.2.1 数据结构创建
Pandas可以使用字典、列表等数据创建DataFrame和Series。
import pandas as pd
# 创建Series
s = pd.Series([1, 3, 5, np.nan, 6, 8])
# 创建DataFrame
data = {'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35]}
df = pd.DataFrame(data)
print(s)
print(df)
3.2.2 数据处理和分析
Pandas提供了丰富的数据处理和分析功能,如数据筛选、排序、聚合等。
import pandas as pd
# 创建DataFrame
data = {'Name': ['Alice', 'Bob', 'Charlie'], 'Age': [25, 30, 35]}
df = pd.DataFrame(data)
# 数据筛选
filtered_df = df[df['Age'] > 28]
# 数据排序
sorted_df = df.sort_values(by='Age')
# 数据聚合
mean_age = df['Age'].mean()
print(filtered_df)
print(sorted_df)
print(mean_age)
3.3 Matplotlib核心算法原理及操作步骤
3.3.1 图表创建
Matplotlib创建图表的基本步骤包括创建图形对象、添加坐标轴、绘制图表和显示图表。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 创建图形对象和坐标轴
fig, ax = plt.subplots()
# 绘制折线图
ax.plot(x, y)
# 添加标题和标签
ax.set_title('Sine Wave')
ax.set_xlabel('X')
ax.set_ylabel('Y')
# 显示图表
plt.show()
3.3.2 图表定制
Matplotlib提供了丰富的图表定制功能,如修改线条颜色、样式,添加图例等。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
# 创建图形对象和坐标轴
fig, ax = plt.subplots()
# 绘制折线图
line1, = ax.plot(x, y1, color='blue', linestyle='-', label='Sine')
line2, = ax.plot(x, y2, color='red', linestyle='--', label='Cosine')
# 添加标题和标签
ax.set_title('Sine and Cosine Waves')
ax.set_xlabel('X')
ax.set_ylabel('Y')
# 添加图例
ax.legend()
# 显示图表
plt.show()
4. 数学模型和公式 & 详细讲解 & 举例说明
4.1 NumPy中的数学模型和公式
4.1.1 向量和矩阵运算
在NumPy中,多维数组可以表示向量和矩阵。向量和矩阵的运算遵循线性代数的规则。
向量加法:设 a=[a1,a2,⋯ ,an]mathbf{a} = [a_1, a_2, cdots, a_n]a=[a1,a2,⋯,an] 和 b=[b1,b2,⋯ ,bn]mathbf{b} = [b_1, b_2, cdots, b_n]b=[b1,b2,⋯,bn] 是两个 nnn 维向量,则它们的和为 a+b=[a1+b1,a2+b2,⋯ ,an+bn]mathbf{a} + mathbf{b} = [a_1 + b_1, a_2 + b_2, cdots, a_n + b_n]a+b=[a1+b1,a2+b2,⋯,an+bn]。
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
result = a + b
print(result)
矩阵乘法:设 Amathbf{A}A 是一个 m×nm imes nm×n 矩阵,Bmathbf{B}B 是一个 n×pn imes pn×p 矩阵,则它们的乘积 C=ABmathbf{C} = mathbf{A} mathbf{B}C=AB 是一个 m×pm imes pm×p 矩阵,其中 cij=∑k=1naikbkjc_{ij} = sum_{k=1}^{n} a_{ik} b_{kj}cij=∑k=1naikbkj。
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
result = np.dot(A, B)
print(result)
4.1.2 统计计算
NumPy提供了丰富的统计计算函数,如均值、方差、标准差等。
均值:设 x1,x2,⋯ ,xnx_1, x_2, cdots, x_nx1,x2,⋯,xn 是一组数据,则它们的均值为 xˉ=1n∑i=1nxiar{x} = frac{1}{n} sum_{i=1}^{n} x_ixˉ=n1∑i=1nxi。
import numpy as np
data = np.array([1, 2, 3, 4, 5])
mean = np.mean(data)
print(mean)
4.2 Pandas中的数学模型和公式
4.2.1 数据聚合
Pandas可以对数据进行聚合操作,如求和、求平均值等。
求和:设 x1,x2,⋯ ,xnx_1, x_2, cdots, x_nx1,x2,⋯,xn 是一组数据,则它们的和为 S=∑i=1nxiS = sum_{i=1}^{n} x_iS=∑i=1nxi。
import pandas as pd
data = {'Value': [1, 2, 3, 4, 5]}
df = pd.DataFrame(data)
sum_value = df['Value'].sum()
print(sum_value)
4.2.2 数据标准化
数据标准化是将数据转换为均值为0,标准差为1的分布。设 xxx 是原始数据,μmuμ 是均值,σsigmaσ 是标准差,则标准化后的数据为 z=x−μσz = frac{x – mu}{sigma}z=σx−μ。
import pandas as pd
import numpy as np
data = {'Value': [1, 2, 3, 4, 5]}
df = pd.DataFrame(data)
mean = df['Value'].mean()
std = df['Value'].std()
df['Standardized'] = (df['Value'] - mean) / std
print(df)
4.3 Matplotlib中的数学模型和公式
4.3.1 线性函数绘图
线性函数的一般形式为 y=mx+by = mx + by=mx+b,其中 mmm 是斜率,bbb 是截距。
import matplotlib.pyplot as plt
import numpy as np
# 定义斜率和截距
m = 2
b = 1
# 生成数据
x = np.linspace(0, 10, 100)
y = m * x + b
# 创建图形对象和坐标轴
fig, ax = plt.subplots()
# 绘制线性函数
ax.plot(x, y)
# 添加标题和标签
ax.set_title('Linear Function')
ax.set_xlabel('X')
ax.set_ylabel('Y')
# 显示图表
plt.show()
4.3.2 正弦函数绘图
正弦函数的一般形式为 y=Asin(ωx+φ)y = A sin(omega x + varphi)y=Asin(ωx+φ),其中 AAA 是振幅,ωomegaω 是角频率,φvarphiφ 是相位。
import matplotlib.pyplot as plt
import numpy as np
# 定义振幅、角频率和相位
A = 1
omega = 1
phi = 0
# 生成数据
x = np.linspace(0, 10, 100)
y = A * np.sin(omega * x + phi)
# 创建图形对象和坐标轴
fig, ax = plt.subplots()
# 绘制正弦函数
ax.plot(x, y)
# 添加标题和标签
ax.set_title('Sine Function')
ax.set_xlabel('X')
ax.set_ylabel('Y')
# 显示图表
plt.show()
5. 项目实战:代码实际案例和详细解释说明
5.1 开发环境搭建
在进行项目实战之前,需要搭建好开发环境。可以使用Anaconda来管理Python环境和安装相关库。具体步骤如下:
下载并安装Anaconda:从Anaconda官方网站(https://www.anaconda.com/products/individual)下载适合自己操作系统的Anaconda安装包,并按照安装向导进行安装。创建虚拟环境:打开Anaconda Prompt(Windows)或终端(Linux/Mac),运行以下命令创建一个新的虚拟环境:
conda create -n data_science python=3.8
激活虚拟环境:运行以下命令激活虚拟环境:
conda activate data_science
安装所需库:运行以下命令安装NumPy、Pandas和Matplotlib:
conda install numpy pandas matplotlib
5.2 源代码详细实现和代码解读
5.2.1 数据处理和分析项目
以下是一个使用NumPy和Pandas进行数据处理和分析的项目示例,我们将使用一个包含学生成绩的数据集。
import numpy as np
import pandas as pd
# 生成模拟数据
np.random.seed(0)
students = ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
subjects = ['Math', 'Physics', 'Chemistry']
data = np.random.randint(50, 100, size=(len(students), len(subjects)))
# 创建DataFrame
df = pd.DataFrame(data, index=students, columns=subjects)
# 计算每个学生的总分
df['Total'] = df.sum(axis=1)
# 计算每个学科的平均分
subject_avg = df[subjects].mean()
# 找出总分最高的学生
top_student = df['Total'].idxmax()
# 打印结果
print("学生成绩表:")
print(df)
print("
每个学科的平均分:")
print(subject_avg)
print(f"
总分最高的学生是:{top_student}")
代码解读:
数据生成:使用函数生成模拟的学生成绩数据。DataFrame创建:使用
np.random.randint()函数将数据转换为DataFrame,指定学生姓名为索引,学科名称为列名。总分计算:使用
pd.DataFrame()计算每个学生的总分,并将结果添加到新的列
df.sum(axis=1)中。平均分计算:使用
Total计算每个学科的平均分。最高分学生查找:使用
df[subjects].mean()找出总分最高的学生的姓名。
df['Total'].idxmax()
5.2.2 数据可视化项目
以下是一个使用Matplotlib进行数据可视化的项目示例,我们将对上述学生成绩数据进行可视化展示。
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# 生成模拟数据
np.random.seed(0)
students = ['Alice', 'Bob', 'Charlie', 'David', 'Eve']
subjects = ['Math', 'Physics', 'Chemistry']
data = np.random.randint(50, 100, size=(len(students), len(subjects)))
# 创建DataFrame
df = pd.DataFrame(data, index=students, columns=subjects)
# 绘制每个学生的成绩柱状图
fig, ax = plt.subplots()
x = np.arange(len(students))
width = 0.2
multiplier = 0
for attribute, measurement in df.items():
offset = width * multiplier
rects = ax.bar(x + offset, measurement, width, label=attribute)
ax.bar_label(rects)
multiplier += 1
# 添加标题和标签
ax.set_ylabel('Scores')
ax.set_title('Student Scores by Subject')
ax.set_xticks(x + width, students)
ax.legend(loc='upper left',bbox_to_anchor=(1, 1))
# 显示图表
plt.show()
代码解读:
数据生成和DataFrame创建:与数据处理和分析项目相同。柱状图绘制:使用函数绘制每个学生的成绩柱状图,通过循环遍历每个学科,为每个学科的成绩添加偏移量。图表定制:使用
ax.bar()、
ax.set_ylabel()等函数添加标题和标签,使用
ax.set_title()函数添加图例。图表显示:使用
ax.legend()函数显示图表。
plt.show()
5.3 代码解读与分析
5.3.1 数据处理和分析代码
数据生成部分:使用NumPy的随机数生成函数生成模拟数据,保证了数据的随机性和可重复性。DataFrame操作部分:Pandas的DataFrame提供了丰富的操作方法,如求和、索引等,使得数据处理和分析变得简单高效。结果输出部分:通过打印DataFrame和计算结果,直观地展示了数据处理和分析的结果。
5.3.2 数据可视化代码
数据准备部分:使用Pandas的DataFrame存储数据,方便后续的可视化操作。图表绘制部分:Matplotlib的函数用于绘制柱状图,通过循环和偏移量的设置,实现了多个学科成绩的并列显示。图表定制部分:通过设置标题、标签、图例等,使得图表更加清晰和易读。
ax.bar()
6. 实际应用场景
6.1 NumPy的实际应用场景
科学计算:NumPy的高性能多维数组和丰富的数学函数使得它在科学计算领域得到广泛应用,如物理模拟、数值分析等。机器学习:在机器学习中,NumPy用于存储和处理训练数据和模型参数,是许多机器学习库(如Scikit-learn、TensorFlow)的基础。
6.2 Pandas的实际应用场景
数据清洗和预处理:Pandas提供了强大的数据清洗和预处理功能,如缺失值处理、数据筛选、数据转换等,是数据科学项目中不可或缺的工具。数据分析和统计:Pandas的DataFrame和Series数据结构使得数据分析和统计变得简单高效,如数据聚合、分组分析等。
6.3 Matplotlib的实际应用场景
数据可视化:Matplotlib是Python中最常用的绘图库,用于创建各种类型的可视化图表,如折线图、柱状图、散点图等,帮助用户直观地理解数据。报告和演示:在数据科学项目的报告和演示中,Matplotlib生成的图表可以清晰地展示数据和分析结果,增强报告的可读性和说服力。
7. 工具和资源推荐
7.1 学习资源推荐
7.1.1 书籍推荐
《Python数据分析实战》:本书详细介绍了NumPy、Pandas和Matplotlib等库的使用方法,并通过实际案例展示了如何进行数据分析和可视化。《Python科学计算》:深入讲解了NumPy、SciPy等科学计算库的原理和应用,适合有一定编程基础的读者。
7.1.2 在线课程
Coursera上的“Python for Data Science”:由知名大学的教授授课,系统地介绍了Python在数据科学中的应用,包括NumPy、Pandas和Matplotlib等库的使用。慕课网上的“Python数据分析与挖掘实战”:结合实际项目,讲解了数据处理、分析和可视化的方法,适合初学者。
7.1.3 技术博客和网站
Python官方文档:NumPy、Pandas和Matplotlib的官方文档是学习这些库的最佳资源,提供了详细的函数说明和示例代码。Towards Data Science:是一个专注于数据科学领域的技术博客,发表了许多关于NumPy、Pandas和Matplotlib的使用技巧和案例分析。
7.2 开发工具框架推荐
7.2.1 IDE和编辑器
Jupyter Notebook:是一个交互式的开发环境,适合进行数据探索和可视化,支持Python代码的实时运行和结果展示。PyCharm:是一款功能强大的Python集成开发环境,提供了代码编辑、调试、版本控制等功能,适合开发大型数据科学项目。
7.2.2 调试和性能分析工具
IPython:是一个增强的Python交互式解释器,提供了丰富的调试和分析功能,如代码自动补全、错误追踪等。cProfile:是Python的内置性能分析工具,用于分析代码的运行时间和函数调用次数,帮助优化代码性能。
7.2.3 相关框架和库
Seaborn:是基于Matplotlib的高级数据可视化库,提供了更美观、更简洁的绘图接口,适合快速创建高质量的可视化图表。Plotly:是一个交互式的可视化库,支持创建动态、交互式的图表,适合在Web应用中展示数据。
7.3 相关论文著作推荐
7.3.1 经典论文
“The NumPy Array: A Structure for Efficient Numerical Computation”:详细介绍了NumPy多维数组的设计和实现原理,对理解NumPy的高性能计算机制有很大帮助。“Data Structures for Statistical Computing in Python”:阐述了Pandas数据结构的设计思想和应用场景,是学习Pandas的重要参考文献。
7.3.2 最新研究成果
关注ACM SIGKDD、IEEE ICDE等数据科学领域的顶级会议,这些会议上发表的最新研究成果可以帮助了解NumPy、Pandas和Matplotlib在最新算法和应用中的使用。
7.3.3 应用案例分析
Kaggle上有许多使用NumPy、Pandas和Matplotlib进行数据处理、分析和可视化的竞赛项目和案例分享,可以学习到实际应用中的技巧和经验。
8. 总结:未来发展趋势与挑战
8.1 未来发展趋势
集成化和自动化:未来,NumPy、Pandas和Matplotlib等库可能会与更多的工具和框架集成,实现数据处理、分析和可视化的自动化流程,提高数据科学工作的效率。可视化技术创新:随着数据量的不断增加和数据类型的多样化,Matplotlib等可视化库可能会引入更多的创新技术,如3D可视化、交互式可视化等,提供更丰富的可视化体验。与机器学习和深度学习的融合:NumPy和Pandas作为数据处理的基础库,将与机器学习和深度学习框架更加紧密地融合,为模型训练和评估提供更高效的数据支持。
8.2 挑战
性能优化:随着数据量的不断增大,NumPy和Pandas在处理大规模数据时可能会面临性能瓶颈,需要不断优化算法和数据结构,提高处理效率。可视化复杂性:当数据维度和复杂度增加时,如何选择合适的可视化方法和技术,以清晰地展示数据信息,是Matplotlib等可视化库面临的挑战。跨平台和兼容性:随着不同操作系统和硬件平台的不断发展,保证NumPy、Pandas和Matplotlib在各种平台上的兼容性和稳定性也是一个重要的挑战。
9. 附录:常见问题与解答
9.1 NumPy常见问题
问题:如何创建一个指定形状的全零数组?
解答:可以使用函数创建一个指定形状的全零数组,例如:
np.zeros()
import numpy as np
arr = np.zeros((3, 4))
print(arr)
问题:如何进行数组的转置?
解答:可以使用或
arr.T函数进行数组的转置,例如:
np.transpose()
import numpy as np
arr = np.array([[1, 2, 3], [4, 5, 6]])
transposed_arr = arr.T
print(transposed_arr)
9.2 Pandas常见问题
问题:如何处理DataFrame中的缺失值?
解答:可以使用函数删除包含缺失值的行或列,也可以使用
dropna()函数填充缺失值,例如:
fillna()
import pandas as pd
import numpy as np
data = {'Value': [1, np.nan, 3, 4, np.nan]}
df = pd.DataFrame(data)
# 删除包含缺失值的行
df_dropna = df.dropna()
# 填充缺失值为0
df_fillna = df.fillna(0)
print(df_dropna)
print(df_fillna)
问题:如何对DataFrame进行分组统计?
解答:可以使用函数对DataFrame进行分组,然后使用聚合函数(如
groupby()、
sum()等)进行统计,例如:
mean()
import pandas as pd
data = {'Category': ['A', 'B', 'A', 'B'], 'Value': [1, 2, 3, 4]}
df = pd.DataFrame(data)
grouped = df.groupby('Category')
sum_value = grouped.sum()
print(sum_value)
9.3 Matplotlib常见问题
问题:如何调整图表的大小?
解答:可以在创建图形对象时使用参数指定图表的大小,例如:
figsize
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y = np.sin(x)
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, y)
plt.show()
问题:如何添加图例到图表中?
解答:可以在绘制图表时使用参数指定每个曲线的标签,然后使用
label函数添加图例,例如:
ax.legend()
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
fig, ax = plt.subplots()
ax.plot(x, y1, label='Sine')
ax.plot(x, y2, label='Cosine')
ax.legend()
plt.show()
10. 扩展阅读 & 参考资料
NumPy官方文档:https://numpy.org/doc/Pandas官方文档:https://pandas.pydata.org/docs/Matplotlib官方文档:https://matplotlib.org/stable/contents.html《Python数据科学手册》,Jake VanderPlas著Kaggle官方网站:https://www.kaggle.com/