更有效地拆分列

时间:2015-12-17 14:39:24

标签: python string pandas dataframe

我有一个数据框,其中列x包含由数字组成的字符串,如此字母

x
1 a
2 b
3 a
34 c
35 d

我想将此列拆分为两个yz,一个带有数值,另一个带有字符串,所以我做

df['y']=df['x'].str.strip().str.split(' ').str.get(0)          
df['z']=df['x'].str.split(' ').str.get(1)

有更有效的方法吗?在大文件中应用此操作时需要几分钟。

更新:字符串和数字是可选的,并不总是出现。可以有一个数字或一个字符串 例如:

x =['6.1 a', ' d', '6.5', '5.6 c', '6.9', '6.1', '5.9 b', '4.5', '4.3', '4.3', '5.7', '5.7', '4.7 x', '5.1', '5.1']

y=['6.1', '', '6.5', '5.6', '6.9', '6.1', '5.9', '4.5', '4.3', '4.3', '5.7', '5.7', '4.7', '5.1', '5.1']
z=['a', 'd', '', 'c', '', '', 'b', '', '', '', '', '', 'x', '', '']

2 个答案:

答案 0 :(得分:2)

你可以使用apply with lambda,比你的解决方案更快:

df["y"] = df.x.apply(lambda x:x.split()[0])
df["z"] = df.x.apply(lambda x:x.split()[1] if len(x.split())>1 else "ND")
df
     x    y   z
0   1 a    1   a
1   2 b    2   b
2   3 a    3   a
3  34 c   34   c
4  35 d   35   d
5   1.5  1.5  ND

我无法与扩展版本进行比较,因为我没有最新的pandas版本。 它比我想的提取版本更快。

如果您不关心使用pandas方法,那么使用字符串方法和列表理解会更快:

y, z = zip(*[(i.split()[0], i.split()[1] if " " in i else "") for i in x])

你可以轻松地把它放在df中。

时序

使用

def ori(df):
    df['y']=df['x'].str.strip().str.split(' ').str.get(0)          
    df['z']=df['x'].str.split(' ').str.get(1)


def lam(df):
    df["y"] = df.x.apply(lambda x:x.split()[0])
    df["z"] = df.x.apply(lambda x:x.split()[1] if len(x.split())>1 else "ND")

编辑:条件相对时间相同。

len(df)= 5

%timeit lam(df)
1000 loops, best of 3: 818 µs per loop

%timeit ori(df)
1000 loops, best of 3: 1.63 ms per loop

len(df)= 10000

%timeit lam(df)
10 loops, best of 3: 16.4 ms per loop

%timeit ori(df)
10 loops, best of 3: 33.1 ms per loop

答案 1 :(得分:1)

我认为原生申请是最好的,但不是。我找到了更快的方法:

df[['y', 'z']] = pd.DataFrame([ x.split(' ') for x in df['x'].tolist()])
df['z'] = df['z'].fillna('')

我的测试:

import pandas as pd

#testing list
x =['6.1 a', ' d', '6.5', '5.6 c', '6.9', '6.1', '5.9 b', '4.5', '4.3', '4.3', '5.7', '5.7', '4.7 x', '5.1', '5.1']
#10000 lists
x = x*10000
#Dataframe from list x
df = pd.DataFrame({'x': x})
print df.head()
       x
0  6.1 a
1      d
2    6.5
3  5.6 c
4    6.9
def OR(df):
    #original
    df['y']=df['x'].str.strip().str.split(' ').str.get(0)          
    df['z']=df['x'].str.split(' ').str.get(1)


def AL(df):
    #incorrect parse second value as number instead string
    df["y"] = df.x.apply(lambda x:x.split()[0])
    df["z"] = df.x.apply(lambda x:x.split()[1] if len(x.split())>1 else "")

def EX(df):
    #extract by reg exprresions - number and string
    df['y'] = df['x'].str.extract('(\d+\.?\d*)')  
    df['z'] = df['x'].str.extract('([A-z]+)')
    #remove NaN from columns y, z
    df['y'] = df['y'].fillna('')
    df['z'] = df['z'].fillna('')

def DF(df):
    #create new columns by converting column x to list and spliting 
    #correct parse second value, because before string is space (I think)
    df[['y', 'z']] = pd.DataFrame([ x.split(' ') for x in df['x'].tolist()])
    #remove NaN - convert it to ''
    df['z'] = df['z'].fillna('')
        
OR(df)
print df.head()
       x    y    z
0  6.1 a  6.1    a
1      d    d    d
2    6.5  6.5  NaN
3  5.6 c  5.6    c
4    6.9  6.9  NaN

AL(df)
print df.head()
       x    y  z
0  6.1 a  6.1  a
1      d    d   
2    6.5  6.5   
3  5.6 c  5.6  c
4    6.9  6.9   

EX(df)
print df.head()
       x    y  z
0  6.1 a  6.1  a
1      d       d
2    6.5  6.5   
3  5.6 c  5.6  c
4    6.9  6.9   
DF(df)
print df.head()
       x    y  z
0  6.1 a  6.1  a
1      d       d
2    6.5  6.5   
3  5.6 c  5.6  c
4    6.9  6.9   

定时:

In [118]: %timeit DF(df)
     ...: %timeit AL(df)
     ...: %timeit OR(df)
     ...: %timeit EX(df)
     ...: 
10 loops, best of 3: 95.4 ms per loop
10 loops, best of 3: 143 ms per loop
1 loops, best of 3: 338 ms per loop
1 loops, best of 3: 459 ms per loop