问题描述
/Temp
我想按公司逐年比较句子列,以便得到逐年变化。
示例:对于公司 A,我想对 | year | sentences | company |
|------|-------------------|---------|
| 2020 | [list of strings] | A |
| 2019 | [list of strings] | A |
| 2018 | [list of strings] | A |
| ... | .... | ... |
| 2020 | [list of strings] | Z |
| 2019 | [list of strings] | Z |
| 2018 | [list of strings] | Z |
和 [list of strings]2020
,然后是 [list of strings]2019
和 [list of strings]2019
应用诸如句子相似度或某些距离度量之类的运算符。>
对于 B、C、... Z 公司也是如此。
如何实现?
编辑
[list of strings]2018
的长度是可变的。所以一些简单的量化运算符可能是
- 元素数量的差异 -->
[list of strings]
- 公共元素的数量 -->
length([list of strings]2020) - length([list of strings]2019)
比较应该是:
length(set([list of strings]2020,[list of strings]2019))
解决方法
TL;DR:查看底部的完整代码
您必须将您的任务分解为更简单的子任务。基本上,您希望在连续行的数据帧上应用一个或多个计算,这按公司分组。这意味着您必须使用 groupby
和 apply
。
让我们从生成示例数据帧开始。这里我使用小写字母作为“句子”列的单词。
import numpy as np
import string
df = pd.DataFrame({'date': np.tile(range(2020,2010,-1),3),'sentences': [np.random.choice(list(string.ascii_lowercase),size=np.random.randint(10)) for i in range(30)],'company': np.repeat(list('ABC'),10)})
df
输出:
date sentences company
0 2020 [z] A
1 2019 [s,f,g,a,d,h,o,c] A
2 2018 [b] A
…
26 2014 [q] C
27 2013 [i,w] C
28 2012 [o,p,i,w,k,d] C
29 2011 [l,p] C
连接下一行(上一年)的“句子”列:
pd.concat([df,df.shift(-1).add_suffix('_pre')],axis=1)
输出:
date sentences company date_pre sentences_pre company_pre
0 2020 [z] A 2019.0 [s,c] A
1 2019 [s,c] A 2018.0 [b] A
2 2018 [b] A 2017.0 [x,n,r,s,d] A
3 2017 [x,d] A 2016.0 [u,u,v,o] A
4 2016 [u,o] A 2015.0 [v,b,z,y,k] A
5 2015 [v,k] A 2014.0 [q,p] A
6 2014 [q,p] A 2013.0 [j,s] A
7 2013 [j,s] A 2012.0 [g,l,n] A
8 2012 [g,n] A 2011.0 [v,s] A
9 2011 [v,s] A 2020.0 [a,c,w] B
…
定义一个函数来计算多个距离度量(这里是问题中定义的两个)。捕获 TypeError 以处理没有要比较的行(每组出现一次)的情况。
def compare_lists(s):
l1 = s['sentences_pre']
l2 = s['sentences']
try:
return pd.Series({'years': '%d–%d' % (s['date'],s['date_pre']),'yoy_diff_len': len(l2)-len(l1),'yoy_nb_common': len(set(l1).intersection(set(l2))),'company': s['company'],})
except TypeError:
return
这适用于过滤为仅匹配一家公司的子数据框:
df2 = df.query('company == "A"')
pd.concat([df2,df2.shift(-1).add_suffix('_pre')],axis=1).dropna().apply(compare_lists,axis=1
输出:
years yoy_diff_len yoy_nb_common company
0 2020–2019 -4 0 A
1 2019–2018 6 1 A
2 2018–2017 1 0 A
3 2017–2016 1 0 A
4 2016–2015 -7 0 A
5 2015–2014 4 0 A
6 2014–2013 1 0 A
7 2013–2012 -1 0 A
8 2012–2011 -5 1 A
现在您可以创建一个函数来构造每个组的每个数据帧并应用计算:
def group_compare(df):
df2 = pd.concat([df,axis=1)
return df2.apply(compare_lists,axis=1)
并使用此功能应用于每个组:
df.groupby('company').apply(group_compare)
完整代码:
import numpy as np
import string
df = pd.DataFrame({'date': np.tile(range(2020,10)})
def compare_lists(s):
l1 = s['sentences_pre']
l2 = s['sentences']
try:
return pd.Series({'years': '%d–%d' % (s['date'],})
except TypeError:
return
def group_compare(df):
df2 = pd.concat([df,axis=1).dropna()
return df2.apply(compare_lists,axis=1)
## uncomment below to remove "company" index
df.groupby('company').apply(group_compare) #.reset_index(level=0,drop=True)
输出:
years yoy_diff_len yoy_nb_common company
company
A 0 2020–2019 -8 0 A
1 2019–2018 8 0 A
2 2018–2017 -5 0 A
3 2017–2016 -3 2 A
4 2016–2015 1 3 A
5 2015–2014 5 0 A
6 2014–2013 0 0 A
7 2013–2012 -2 0 A
8 2012–2011 0 0 A
B 10 2020–2019 3 0 B
11 2019–2018 -6 1 B
12 2018–2017 3 0 B
13 2017–2016 -5 1 B
14 2016–2015 2 2 B
15 2015–2014 4 1 B
16 2014–2013 3 0 B
17 2013–2012 -8 0 B
18 2012–2011 1 1 B
C 20 2020–2019 8 1 C
21 2019–2018 -7 0 C
22 2018–2017 0 1 C
23 2017–2016 7 0 C
24 2016–2015 -3 0 C
25 2015–2014 3 0 C
26 2014–2013 -1 0 C
27 2013–2012 -6 2 C
28 2012–2011 4 2 C