数据科学

加速数据分析:使用 RAPID cuDF 加速数据探索

这篇文章是 加速数据分析 系列文章的一部分:

气候建模、医疗保健、金融和零售业的数字进步正在产生前所未有的数据量和类型。 IDC 表示,到 2025 年,将有 180 ZB 的数据,而 2020 年为 64 ZB ,这将扩大对数据分析的需求,将所有数据转化为见解。

NVIDIA 提供 RAPIDS 开源软件库和 API 套件,使数据科学家能够完全在 GPU 上执行端到端的数据科学和分析管道。这包括使用我们的 DataFrame API : RAPIDS cuDF 进行分析和数据科学的常见数据准备任务。

在典型的数据分析工作流程中,速度高达 40 倍,加速的数据分析为您节省了时间,并增加了可能受到当前分析工具限制的迭代机会。

为了解释加速数据分析的价值,我们在本文中使用 RAPIDS cuDF 进行了一个简单的探索性数据分析( EDA )教程。

如果您现在使用 Spark 3.0 来处理大型数据集,请参阅 RAPIDS accelerator for Spark 。如果您现在已经准备好开始使用 RAPIDS ,请参阅 Step-by-Step Guide to Building a Machine Learning Application with RAPIDS

为什么 RAPIDS cuDF 适用于 EDA ?

如今,大多数数据科学家使用 pandas ,这是在 Python 之上构建的 popular 开源软件库,专门用于 EDA 任务的数据操作和分析。它的 flexible and expressive data structures 旨在使处理关系数据或标记数据变得简单直观,尤其是对于 EDA 等开放式工作流。

然而, pandas 被设计为在单核上运行,当数据大小达到 1-2GB 时,速度会开始减慢,这限制了它的适用性。如果数据大小超过 10-20 GB 的范围,则应考虑使用 DaskApache Spark 等分布式计算工具。缺点是它们需要重写代码,这可能会成为采用的障碍。

对于 2-10 GB 的中间值, RAPIDS cuDF 是 Goldilocks 的解决方案。

RAPIDS cuDF 将计算并行到 GPU 中的多个核心,并抽象为类似 pandas 的API。 cuDF 的功能模仿了 pandas 中许多最流行和标准的操作,[ZBK9的运行方式与[ZBK5类似,但速度更快。将 RAPIDS 视为当前 pandas 工作负载的涡轮增压按钮。

带有 RAPIDS cuDF 的 EDA

这篇文章展示了 cuDF 在采用 EDA 方法时是多么容易。

根据本文所述的操作,与 pandas 相比,我们观察到使用 cuDF 时的操作速度提高了 15 倍。这种适度的收益可以帮助您在处理多个项目时节省时间。

有关进行时间序列分析的更多信息,请参阅 Exploratory Data Analysis Using cuDF GitHub 存储库中的完整笔记本 Exploratory Data Analysis Using cuDF 和 RAPIDS 。在整个工作流程中,观察到的加速速度增加到了 15 倍。

数据集

Meteonet 是一个天气数据集,汇集了 2016-2018 年巴黎各地气象站的读数。这是一个真实的数据集,有缺失和无效的数据。

分析方法

对于这篇文章,假设你是一名数据科学家,阅读这些汇总数据并评估其质量。用例是开放式的;这些读数可以用于报告、天气预报或土木工程用例。

通过以下步骤构建您的分析以将数据置于情境中:

  • 了解变量。
  • 识别数据集中的差距。
  • 分析变量之间的关系。

步骤 1. 了解变量

首先,导入 cuDF 库并读取数据集。要下载并创建 NW.csv ,其中包含西北站 2016 年、 2017 年和 2018 年的数据,请参阅 Exploratory Data Analysis Using cuDF 笔记本。

# Import cuDF and CuPy
import cudf
import cupy as cp

# Read in the data files into DataFrame placeholders
gdf_2016 = cudf.read_csv('./NW.csv')

查看数据集并了解您正在使用的变量。这有助于您了解 DataFrame 中数据的维度和类型。整个语法与 pandas 有相似之处。

使用. info 命令查看整个 DataFrame 结构,该命令与 pandas 中的命令相同:

GS_cudf.info()
<class 'cudf.core.dataframe.DataFrame'>
RangeIndex: 22034571 entries, 0 to 22034570
Data columns (total 12 columns):
# Column Dtype
--- ------ -----
0 number_sta int64
1 lat float64
2 lon float64
3 height_sta float64
4 date datetime64[ns]
5 dd float64
6 ff float64
7 precip float64
8 hu float64
9 td float64
10 t float64
object
dtypes: datetime64[ns](1), float64(9), int64(1), object(1)
memory usage: 6.5+ GB

从输出中,观察到了 12 个变量,您可以看到它们的标题。

要进一步了解数据,请确定 DataFrame 的整体形状:逐行逐列。

# Checking the DataFrame dimensions. Millions of rows by 12 columns.
GS_cudf.shape
(65826837, 12)

在这一点上,数据集的维度是已知的,但每个变量的数据范围是未知的。由于有 65826837 行,您无法一次可视化整个数据集。

相反,查看 DataFrame 的前五行,以检查耗材样本中的变量输入:

# Display the first five rows of the DataFrame to examine details
GS_cudf.head()
  number_sta lat lon height_sta date dd ff precip hu td t psl
0 14066001 49.33 -0.43 2.0 2016-01-01 210.0 4.4 0.0 91.0 278.45 279.85 <NA>
1 14126001 49.15 0.04 125.0 2016-01-01 <NA> <NA> 0.0 99.0 278.35 278.45 <NA>
2 14137001 49.18 -0.46 67.0 2016-01-01 220.0 0.6 0.0 92.0 276.45 277.65 102360.0
3 14216001 48.93 -0.15 155.0 2016-01-01 220.0 1.9 0.0 95.0 278.25 278.95 <NA>
4 14296001 48.80 -1.03 339.0 2016-01-01 <NA> <NA> 0.0 <NA> <NA> 278.35 <NA>

表 1 。输出结果

现在,您可以了解每一行包含的内容。有多少数据来源?看看收集所有这些数据的台站数量:

# How many weather stations are covered in this dataset? 
# Call nunique() to count the distinct elements along a specified axis.

number_stations = GS_cudf['number_sta'].nunique()
print("The full dataset is composed of {} unique weather stations.".format(GS_cudf['number_sta'].nunique()))

完整的数据集由 287 个独特的气象站组成。这些电台多久更新一次数据?

## Investigate the frequency of one specific station's data
## date column is datetime dtype, and the diff() function calculates the delta time 
## TimedeltaProperties.seconds can help get the delta seconds between each record, divide by 60 seconds to see the minutes difference.
delta_mins = GS_cudf['date'].diff().dt.seconds.max()/60
print(f"The data is recorded every {delta_mins} minutes")

每 6.0 分钟记录一次数据。气象站每小时产生 10 个记录。

现在,您了解了以下数据特征:

  • 数据类型
  • 数据集的维度
  • 获取数据集的来源数量
  • 数据集更新频率

然而,您仍然必须探究这些数据是否存在重大缺口,无论是数据输入缺失还是无效。这些问题会影响这些数据是否可以单独用作可靠的来源。

步骤 2. 确定差距

这些气象站有多个传感器。任何一个传感器都可能在一年中出现故障或提供不可靠的读数。一些缺失的数据是可以接受的,但如果监测站过于频繁地关闭,这些数据可能会歪曲全年的真实情况。

要了解此数据源的可靠性,请分析数据丢失率和无效输入的数量。

要评估数据丢失率,请将读数数量与预期读数数量进行比较。

数据集包括 271 个独特的站点,每小时输入 10 条记录(每 6 分钟输入一条)。假设传感器没有停机时间,预计记录的数据条目数量为 271 x 10 x 24 x 365 = 23739600 。但是,正如前面从. shape 操作中观察到的那样,您只有 22034571 行数据。

# Theoretical number of records is... 
theoretical_nb_records = number_stations * (60 / delta_mins) * 365 * 24 
actual_nb_of_rows = GS_cudf.shape[0]
missing_record_ratio = 1 - (actual_nb_of_rows/theoretical_nb_records)
print("Percentage of missing records of the NW dataset is: {:.1f}%".format(missing_record_ratio * 100))
print("Theoretical total number of values in dataset is: {:d}".format(int(theoretical_nb_records)))

Percentage of missing records of the NW dataset is: 12.7%

当对全年进行上下文分析时, 12.7% 表示每年约有 19.8 周的数据缺失。

你知道,在 36 个月中,大约有 5 个月的数据根本没有被记录下来。对于其他数据点,您有一些缺失的数据,其中记录了一些变量,但没有记录其他变量。您在查看数据集的前五行时看到了这一点,其中包含 NA 。

要了解你有多少 NA 数据,首先要确定哪些变量有 NA 读数。评估每个类别有多少无效读数。在这部分分析中,将数据集缩减为仅考虑 2018 年的数据。

# Finding which items have NA value(s) during year 2018
NA_sum = GS_cudf[GS_cudf['date'].dt.year==2018].isna().sum()
NA_data = NA_sum[NA_sum>0]
NA_data.index

StringIndex(['dd' 'ff' 'precip' 'hu' 'td' 't' 'psl'], dtype='object')
NA_data
dd         8605703
ff         8598613
precip     1279127
hu         8783452
td         8786154
t          2893694
psl       17621180
dtype: int64

您可以看到 PSL (海平面压力)的缺失读数数量最多。大约 80% 的总读数没有被记录。在低端,降水有约 6% 的无效读数,这表明传感器是稳健的。

这两个指标有助于您了解数据集中存在的差距以及在分析过程中需要依赖哪些参数。有关数据有效性每月变化的综合分析,请参阅笔记本。

现在你已经很好地掌握了数据的样子及其差距,你可以看看可能影响统计分析的变量之间的关系。

步骤 3. 分析变量之间的关系

所有 ML 应用程序都依赖于统计建模以及许多分析应用程序。对于任何用例,都要注意高度相关的变量,因为它们可能会扭曲结果。

对于这篇文章来说,分析气象类别的读数是最相关的。为整个 3 年数据集生成一个相关矩阵,以评估需要注意的任何依赖关系。

# Only analyze meteorological columns
Meteo_series = ['dd', 'ff', 'precip' ,'hu', 'td', 't', 'psl']
Meteo_df = cudf.DataFrame(GS_cudf,columns=Meteo_series)
Meteo_corr = Meteo_df.dropna().corr()

# Check the items with correlation value > 0.7 
Meteo_corr[Meteo_corr>0.7]
  dd ff precip hu td t psl
dd 1.0 <NA> <NA> <NA> <NA> <NA> <NA>
ff <NA> 1.0 <NA> <NA> <NA> <NA> <NA>
precip <NA> <NA> 1.0 <NA> <NA> <NA> <NA>
hu <NA> <NA> <NA> 1.0 <NA> <NA> <NA>
td <NA> <NA> <NA> <NA> 1.0 0.840558357 <NA>
t <NA> <NA> <NA> <NA> 0.840558357 1.0 <NA>
psl <NA> <NA> <NA> <NA> <NA> <NA>  
表 2 。输出结果

在矩阵中,td(露点)和t(温度)之间存在显著的相关性。如果您正在使用任何假设变量是独立的未来算法,如 linear regression ,请考虑这一点。你可以回到无效数据分析,看看其中一个是否比另一个有更多的缺失读数作为选择的指标。

经过基本的探索,您现在了解了数据的维度和变量,并查看了变量相关矩阵。还有更多的 EDA 技术,但本文中的方法是通用的,有一组任何数据科学家都熟悉的典型起点。正如您在整个教程中看到的那样, cuDF 与 pandas 语法几乎相同。

EDA 基准 RAPIDS cuDF

如前所述,这篇文章是完整笔记本中完整工作流程的简化演练。在这篇文章中,我们观察到了 9.55 倍的加速。这些结果是在 NVIDIA A6000 GPU 上实现的。

Bar chart showing speedup results for EDA performed on pandas and RAPIDS cuDF.
图 1 。勘探数据分析的基准结果

表 3 显示了一个性能比较,包括本帖和完整笔记本的结果。

Full Notebook (15x speed-up)

Pandas on CPU (Intel Core i7-7800X CPU)

user 1 min 15 sec

sys: 14.3 sec

total: 1 min 30 sec

RAPIDS cuDF on NVIDIA A6000

user 3.92 sec

sys: 2.03 sec

total: 5.95 sec

表 3 。在 NVIDIA RTX A6000 GPU 上使用 RAPID cuDF 执行的 EDA 实现了 15 倍的加速

主要收获

来自真实来源的真实数据存在差距、信息缺失和相关性,在对其进行建模以发展见解之前,必须解决这些问题。

通过观察到的 15 倍的加速,您可以推断出为更长、更复杂的工作负载节省的时间。如果运行 EDA 步骤需要 1 小时,那么您可以在 4 分钟内完成这项工作。这让您有 56 分钟的时间来解决数据中不可预见的问题,完成数据处理,向该集合中再添加一年的数据以最大限度地减少差距,并开始设计数据集以适应您的用例。最棒的是,你可以重新控制自己的时间。

为了在探索性数据分析中进一步研究 cuDF ,请查阅完整的笔记本, Exploratory Data Analysis Using cuDF Register for NVIDIA GTC 2023 for free ,并于 3 月 20-23 日加入我们的相关 data science sessions

要查看 cuDF 与时间序列数据的作用,请参见 Accelerated Data Analytics: Faster Time Series Analysis with RAPIDS cuDF

鸣谢

彭美然、 David Taubenheim 、 Sheng Luo 和 Jay Rodge 对此帖子做出了贡献。

 

Tags