- 2.1 新建dataframe
- 2.2 pandas 与 cuDF切换
- 2.3 选中某行列
- 2.4 apply_rows和apply_chunks
- 2.5 groupby
1 cuDF背景与安装
1.1 背景
cuDF在过去一年中的发展速度非常之快。每个版本都加入了令人兴奋的新功能、优化和错误修复。0.10版本也不例外。cuDF 0.10版本的一些新功能包括 groupby.quantile()、Series.isin()、从远程/云文件系统(例如hdfs、gcs、s3)读取、Series和DataFrame isna()、按分组功能中的任意长度Series分组 、Series 协方差和Pearson相关性以及从DataFrame / Series .values 属性返回 CuPy数组。此外,apply UDF函数API经过了优化,并且加入了通过.iloc访问器的收集和散播方法。
除了提供所有上述出色的功能、优化和错误修复之外,cuDF 0.10版本还花费大量的精力构建未来。该版本将cuStrings存储库合并到cuDF中,并为合并两个代码库做好了准备,使字符串功能能够被更紧密地集成到cuDF中,以此提供更快的加速和更多的功能。此外,RAPIDS添加了cuStreamz元数据包,因此可以使用cuDF和Streamz库简化GPU加速流处理。cuDF继续改进其Pandas API兼容性和Dask DataFrame互操作性,使我们的用户可以最大程度地无缝使用cuDF。
在幕后,libcudf的内部架构正在经历一次重大的重新设计。0.10版本加入了最新的cudf :: column和cudf :: table类,这些类大大提高了内存所有权控制的强健性,并为将来支持可变大小数据类型(包括字符串列、数组和结构)奠定了基础。由于已构建对整个libcudf API中的新类的支持,这项工作将在下一个版本周期中继续进行。此外,libcudf 0.10添加了许多新的API和算法,包括基于排序、支持空数据的分组功能、分组功能分位数和中位数、cudf :: unique_count,cudf :: repeat、cudf :: scatter_to_tables等。与以往一样,此版本还包括许多其他改进和修复。
RAPIDS内存管理器库RMM也正在进行一系列重组。这次重组包括一个基于内存资源的新架构,该架构与C 17 std :: pmr :: memory_resource大多兼容。这使该库更容易在公共接口之后添加新类型的内存分配器。0.10还用Cython取代了CFFI Python绑定,从而使C 异常可以传播到Python异常,使更多可调整的错误被传递给应用程序。下一个版本将继续提高RMM中的异常支持。
最后,你会注意到cuDF在这个版本中速度有了显著提升,包括join(最多11倍)、gather和scatter on tables(速度也快2-3倍)的大幅性能改进,以及更多如图5所示的内容。
图5:单个NVIDIA Tesla V100(立即免费试用) GPU与双路Intel Xeon E5–2698 v4 CPU(20核)上的cuDF vs Pandas加速
1.2 安装
有conda可以直接安装,也可以使用docker,参考:https://github.com/rapidsai/cudf
conda版本,cudf version == 0.10
代码语言:javascript复制# for CUDA 9.2
conda install -c rapidsai -c nvidia -c numba -c conda-forge
cudf=0.10 python=3.6 cudatoolkit=9.2
# or, for CUDA 10.0
conda install -c rapidsai -c nvidia -c numba -c conda-forge
cudf=0.10 python=3.6 cudatoolkit=10.0
# or, for CUDA 10.1
conda install -c rapidsai -c nvidia -c numba -c conda-forge
cudf=0.10 python=3.6 cudatoolkit=10.1
docker版本,可参考:https://rapids.ai/start.html#prerequisites
代码语言:javascript复制docker pull rapidsai/rapidsai:cuda10.1-runtime-ubuntu16.04-py3.7
docker run --gpus all --rm -it -p 8888:8888 -p 8787:8787 -p 8786:8786
rapidsai/rapidsai:cuda10.1-runtime-ubuntu16.04-py3.7
2 一些demo
2.1 新建dataframe
代码语言:javascript复制import cudf
import numpy as np
from datetime import datetime, timedelta
t0 = datetime.strptime('2018-10-07 12:00:00', '%Y-%m-%d %H:%M:%S')
n = 5
df = cudf.DataFrame({
'id': np.arange(n),
'datetimes': np.array([(t0 timedelta(seconds=x)) for x in range(n)])
})
df
Build DataFrame via list of rows as tuples:
代码语言:javascript复制>>> import cudf
>>> df = cudf.DataFrame([
(5, "cats", "jump", np.nan),
(2, "dogs", "dig", 7.5),
(3, "cows", "moo", -2.1, "occasionally"),
])
>>> df
0 1 2 3 4
0 5 cats jump null None
1 2 dogs dig 7.5 None
2 3 cows moo -2.1 occasionally
2.2 pandas 与 cuDF切换
pandas到 cuDF
代码语言:javascript复制>>> import pandas as pd
>>> import cudf
>>> pdf = pd.DataFrame({'a': [0, 1, 2, 3],'b': [0.1, 0.2, None, 0.3]})
>>> df = cudf.from_pandas(pdf)
>>> df
a b
0 0 0.1
1 1 0.2
2 2 nan
3 3 0.3
cuDF 到pandas
代码语言:javascript复制>>> import cudf
>>> gdf = cudf.DataFrame({'a': [1, 2, None], 'b': [3, None, 5]})
>>> gdf.fillna(4).to_pandas()
a b
0 1 3
1 2 4
2 4 5
>>> gdf.fillna({'a': 3, 'b': 4}).to_pandas()
a b
0 1 3
1 2 4
2 3 5
2.3 选中某行列
代码语言:javascript复制df = cudf.DataFrame({'a': list(range(20)),
'b': list(range(20)),
'c': list(range(20))})
df
代码语言:javascript复制df.iloc[1]
a 1
b 1
c 1
Name: 1, dtype: int64
2.4 apply_rows和apply_chunks
apply_rows
代码语言:javascript复制import cudf
import numpy as np
from numba import cuda
df = cudf.DataFrame()
df['in1'] = np.arange(1000, dtype=np.float64)
def kernel(in1, out):
for i, x in enumerate(in1):
print('tid:', cuda.threadIdx.x, 'bid:', cuda.blockIdx.x,
'array size:', in1.size, 'block threads:', cuda.blockDim.x)
out[i] = x * 2.0
outdf = df.apply_rows(kernel,
incols=['in1'],
outcols=dict(out=np.float64),
kwargs=dict())
print(outdf['in1'].sum()*2.0)
print(outdf['out'].sum())
>>> 999000.0
>>> 999000.0
apply_chunks
代码语言:javascript复制import cudf
import numpy as np
from numba import cuda
df = cudf.DataFrame()
df['in1'] = np.arange(100, dtype=np.float64)
def kernel(in1, out):
print('tid:', cuda.threadIdx.x, 'bid:', cuda.blockIdx.x,
'array size:', in1.size, 'block threads:', cuda.blockDim.x)
for i in range(cuda.threadIdx.x, in1.size, cuda.blockDim.x):
out[i] = in1[i] * 2.0
outdf = df.apply_chunks(kernel,
incols=['in1'],
outcols=dict(out=np.float64),
kwargs=dict(),
chunks=16,
tpb=8)
print(outdf['in1'].sum()*2.0)
print(outdf['out'].sum())
>>> 9900.0
>>> 9900.0
2.5 groupby
代码语言:javascript复制from cudf import DataFrame
df = DataFrame()
df['key'] = [0, 0, 1, 1, 2, 2, 2]
df['val'] = [0, 1, 2, 3, 4, 5, 6]
groups = df.groupby(['key'], method='cudf')
# Define a function to apply to each row in a group
def mult(df):
df['out'] = df['key'] * df['val']
return df
result = groups.apply(mult)
print(result)
输出:
代码语言:javascript复制 key val out
0 0 0 0
1 0 1 0
2 1 2 2
3 1 3 3
4 2 4 8
5 2 5 10
6 2 6 12
之后,用到的时候再追加。。