python pandas 数据框:将函数 return 元组分配给数据框的两列

python pandas data frame: assign function return tuple to two columns of a data frame

我想使用返回 tuple 的函数将两列添加到 pandas Dataframe

data=pd.DataFrame({'a':[1,2,3,4,5,6],'b':['ssdfsdf','bbbbbb','cccccccccccc','ddd','eeeeee','ffffff']})

def givetup(string):
    
    result1 = string[0:3]
    # please imagine here a bunch of string functions concatenated.
    # including nlp methods with SpaCy 
    result2 = result1.upper()
    # the same here, imagine a bunch of steps to calculate result2 based on result 1
    
    return (result1,result2)

data['c'] = data['b'].apply(lambda x: givetup(x)[0])
data['d'] = data['b'].apply(lambda x: givetup(x)[1])

这是非常低效的(我正在处理数百万行),因为我调用了同一个函数两次并进行了两次计算。 由于 result2 依赖于 result 1 我最好不要将 givetup 分成两个函数 我如何一次性将 result1result2 分配到新列 cd 中,只需调用一次功能? 最有效的方法是什么?

请记住 result1result2 是非常耗时的字符串计算。

编辑 1: 我知道这个: Apply pandas function to column to create multiple new columns?

即应用向量化函数。在我的特殊情况下,这是非常不受欢迎的,甚至可能是不可能的。假设结果1和结果2是基于语言模型计算的,我需要纯文本。

您可以在此处尝试列表理解:

data[['c','d']] = [givetup(a) for a in data['b']]

输出:

   a             b    c    d
0  1       ssdfsdf  ssd  SSD
1  2        bbbbbb  bbb  BBB
2  3  cccccccccccc  ccc  CCC
3  4           ddd  ddd  DDD
4  5        eeeeee  eee  EEE
5  6        ffffff  fff  FFF

zip/map

data['c'], data['d'] = zip(*map(givetup, data['b']))

data

   a             b    c    d
0  1       ssdfsdf  ssd  SSD
1  2        bbbbbb  bbb  BBB
2  3  cccccccccccc  ccc  CCC
3  4           ddd  ddd  DDD
4  5        eeeeee  eee  EEE
5  6        ffffff  fff  FFF

Series.strassign

这特定于 givetup 中给出的示例。但如果可以解开,那么它可能是值得的。

assign 方法参数可以采用引用在参数中创建的列的可扩展性(NEAT)。

data.assign(c=lambda d: d.b.str[0:3], d=lambda d: d.c.str.upper())

   a             b    c    d
0  1       ssdfsdf  ssd  SSD
1  2        bbbbbb  bbb  BBB
2  3  cccccccccccc  ccc  CCC
3  4           ddd  ddd  DDD
4  5        eeeeee  eee  EEE
5  6        ffffff  fff  FFF

时间

data = pd.concat([data] * 10_000, ignore_index=True)

%timeit data['c'], data['d'] = zip(*map(givetup, data['b']))
%timeit data[['c','d']] = [givetup(a) for a in data['b']]
%timeit data.assign(c=lambda d: d.b.str[0:3], d=lambda d: d.c.str.upper())

69.7 ms ± 865 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
137 ms ± 937 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
34.6 ms ± 235 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

另一种方法是对系列使用应用函数:

import pandas as pd

data=pd.DataFrame({'a':[1,2,3,4,5,6],'b':['ssdfsdf','bbbbbb','cccccccccccc','ddd','eeeeee','ffffff']})

def givetup(column):
    
    column1 = column[0:3]
    column2 = column[0:3].upper()
    
    return pd.Series([column1, column2])

data[['c','d']] = data['b'].apply(lambda x: givetup(x))