使用apply计算大量额外的列pandas dataframe



我有一个2列的数据框架-索引,文本块。我希望创建50个额外的列,列名是1980到2030之间的数字。每一列本质上包含该数字的次数(例如。2015)出现在文本块中。因为我想对每一行都这样做,所以我可以使用.apply()函数。

函数如下:

def funct(row):
mydict = {}
to_return_list = []
textcont = row['textblock']
for no in range(1980,2031):
mydict[no] = textcont.count(no)
to_return_list.append(textcont.count(no))
return tuple(to_return_list)
# or maybe return pd.Series(mydict) ? 
通常,如果我希望通过在pandas中应用一个函数来计算额外的列,代码如下:
(df['col1'], df['col2'], df['col3']) = zip(*dfs.apply(funct, axis=1))

如果我希望对我的函数做同样的事情,我必须手动添加列名,即

(df['1980'], df['1981'], df['1982'] .... ) = zip(*dfs.apply(funct, axis=1))

这显然是非常麻烦的。(另外,如果我以后希望将范围改为:1970到2030,我必须再次手动添加名称)。有没有一种方法可以做到这一点,而无需手动输入名称,也许使用字典?

玩具例子:

import pandas as pd
dataframe = pd.DataFrame([{'index' : 541, 'textblock' : '2019, 2713, hello there general 3120 1980 to 2020'}, {'index' : 6361, 'textblock' : 'Here is some more 2000 dummy text 2029 and additional 1975 text'}])

我所解释的输出应该包含以下列

index | textblock | 1980 | 1981 ..... | 2030

注释:我不喜欢手动遍历每一行的解决方案。这只是一个突出我的问题的小例子。我的原始数据框架有超过20列,其中还包含其他数据,因此必须创建一个新字典来复制现有数据仍然不是很优雅,尽管任何有效的解决方案都将受到赞赏。

  1. 使用regexp查找所有no.
  2. 使用explode将类列表转换为行,复制索引值
  3. 然后groupby ['index', 'textblock', 'no']计算大小,然后解栈
pat =r'b%sb' % r'b|b'.join(map(str, range(1980,2031)))
dataframe['no'] = dataframe['textblock'].str.findall(pat)
df = dataframe.explode('no').groupby(['index', 'textblock', 'no']).size().unstack(fill_value=0).reset_index()
df.columns.name = None
print(df)

index                                          textblock  1980  2000  2019  
0    541  2019, 2713, hello there general 3120 1980 to 2020     1     0     1   
1   6361  Here is some more 2000 dummy text 2029 and add...     0     1     0   
2020  2029  
0     1     0  
1     0     1

我的建议是:

for no in range(1980,2031):
df[i]=df.textblock.apply(lambda x: x.count(str(i)))

**kwargstoassign()工作良好

import pandas as pd
df = pd.DataFrame([{'index' : 541, 'textblock' : '2019, 2713, hello there general 3120 1980 to 2020'}, {'index' : 6361, 'textblock' : 'Here is some more 2000 dummy text 2029 and additional 1975 text'}])
df2 = df.assign(**{str(c):df.textblock.str.count(str(c)) for c in range(2015,2030)})

最新更新