【问题标题】:python pandas data frame: assign function return tuple to two columns of a data framepython pandas dataframe:将函数返回元组分配给数据框的两列
【发布时间】:2021-06-23 15:19:05
【问题描述】:

我想使用返回 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 是根据语言模型计算出来的,我需要纯文本。

【问题讨论】:

  • result2 取决于结果 1 是否可以编写两个(矢量化)函数,一个获取result1,一个分别获取result2。那你可以data['c'] = func1(data['b']); data['d'] = func2(data['c'])?
  • 跟进@QuangHoang 所说的话。我像这样矢量化data.assign(c=lambda d: d.b.str[0:3], d=lambda d: d.c.str.upper())

标签: python pandas performance apply assign


【解决方案1】:

您可以在这里尝试列表理解:

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

【讨论】:

    【解决方案2】:

    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) 的 calables。

    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)
    

    【讨论】:

    • 似乎第二个是要走的路。在我的特殊情况下,第三个是不可能的
    • 这里的第一个和第二个解决方案给出:/opt/conda/lib/python3.8/site-packages/numpy/core/_asarray.py:102: VisibleDeprecationWarning: Creating an ndarray from ragged nested不推荐使用序列(它是具有不同长度或形状的列表或元组或 ndarray 的列表或元组)。如果您打算这样做,则必须在创建 ndarray 时指定“dtype=object”。 return array(a, dtype, copy=False, order=order) 是什么意思?
    • 这意味着您的元组不是长度为 2 的玩具示例不代表您的实际情况。
    • 您可以这样做以确保您始终只获得两个,data['c'], data['d'] = zip(*[x[:2] for x in map(givetup, data['b'])])
    【解决方案3】:

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

    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))
    

    【讨论】:

    • 这种方法可能效率很低。首先,您为每一行创建一个pd.Series。然后你要求 Pandas 为每一行对齐这些新列。此外,column1 = column[0:3] 已经对字符串进行了切片。当您column2 = column[0:3].upper() 时,您再次执行此操作,这样做是浪费每一行。这样做的时间要慢 1000 倍。
    猜你喜欢
    • 2020-09-30
    • 2021-04-12
    • 2023-03-15
    • 2018-12-23
    • 2020-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-10
    相关资源
    最近更新 更多