python pandas dataframe:将函数返回元组分配给数据框的两列
Posted
技术标签:
【中文标题】python pandas dataframe:将函数返回元组分配给数据框的两列【英文标题】:python pandas data frame: assign function return tuple to two columns of a data frame 【发布时间】: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
分成两个函数
如何只调用一次函数就将 result1
和 result2
一次性分配到新列 c 和 d 中?
最有效的方法是什么?
请记住,result1
和 result2
是非常耗时的字符串计算。
编辑 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())
【参考方案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.str
和 assign
这是特定于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 倍。以上是关于python pandas dataframe:将函数返回元组分配给数据框的两列的主要内容,如果未能解决你的问题,请参考以下文章
python 将Numpy数组转换为Pandas Dataframe
python pandas中如何将dataframe中的一列字符串类型转换为浮点类型?
python 将Pandas Dataframe导出到csv(无索引)
python 将Pandas Dataframe导出到Excel文件中