在列上使用`split`太慢 - 我怎样才能获得更好的性能?

tub*_*adc 2 python performance split pandas

我有一个数据集(大约10Gb)的通话记录.有ip地址的列我想分成四个新列.我正在尝试使用:

df['ip'].fillna('0.0.0.0', inplace=True)
df = df.join(df['ip'].apply(lambda x: Series(x.split('.'))))
Run Code Online (Sandbox Code Playgroud)

但是它太慢了...... fillna速度很快,就像10秒一样,但它会在5分钟内保持分裂...

有没有更好的方法呢?

cge*_*cge 11

事实证明,str.split熊猫(在core/strings.pyas中str_split)实际上非常缓慢; 它不再有效,并且仍然使用Python进行迭代,不提供任何加速.

实际上,见下文.熊猫在这方面的表现简直悲惨; 它不只是Python vs C迭代,因为使用Python列表做同样的事情是最快的方法!

有趣的是,有一个技巧解决方案要快得多:将系列编写成文本,然后再用'.'再次读取它.作为分隔符:

df[['ip0', 'ip1', 'ip2', 'ip3']] = \
    pd.read_table(StringIO(df['ip'].to_csv(None,index=None)),sep='.')
Run Code Online (Sandbox Code Playgroud)

为了比较,我使用Marius的代码并生成20,000 ips:

import pandas as pd
import random
import numpy as np
from StringIO import StringIO

def make_ip():
    return '.'.join(str(random.randint(0, 255)) for n in range(4))

df = pd.DataFrame({'ip': [make_ip() for i in range(20000)]})

%timeit df[['ip0', 'ip1', 'ip2', 'ip3']] = df.ip.str.split('.', return_type='frame')
# 1 loops, best of 3: 3.06 s per loop

%timeit df[['ip0', 'ip1', 'ip2', 'ip3']] = df['ip'].apply(lambda x: pd.Series(x.split('.')))
# 1 loops, best of 3: 3.1 s per loop

%timeit df[['ip0', 'ip1', 'ip2', 'ip3']] = \
    pd.read_table(StringIO(df['ip'].to_csv(None,index=None)),sep='.',header=None)
# 10 loops, best of 3: 46.4 ms per loop
Run Code Online (Sandbox Code Playgroud)

好吧,所以我想比较所有这些只是使用Python列表和Python拆分,这应该比使用更高效的Pandas慢:

iplist = list(df['ip'])
%timeit [ x.split('.') for x in iplist ]
100 loops, best of 3: 10 ms per loop
Run Code Online (Sandbox Code Playgroud)

什么!?显然,对大量字符串进行简单字符串操作的最佳方法是完全抛弃Pandas.使用Pandas会使进程慢400倍.但是,如果你想使用Pandas,你也可以转换为Python列表并返回:

%timeit df[['ip0', 'ip1', 'ip2', 'ip3']] = \
    pd.DataFrame([ x.split('.') for x in list(df['ip']) ])
# 100 loops, best of 3: 18.4 ms per loop
Run Code Online (Sandbox Code Playgroud)

这里有一些非常错误的东西.