我有一个数据框,其中列x
包含由数字组成的字符串,如此字母
x
1 a
2 b
3 a
34 c
35 d
我想将此列拆分为两个y
和z
,一个带有数值,另一个带有字符串,所以我做
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', '', '']
答案 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