给定此示例数据集:
id col1 col2 col3
0 [1999, 2000, 2001] [1989, 2000, 2005] [1999, 2004, 2005]
我正在尝试创建第四列,其中包含其他三列中每个列表中不同年份的总数。因此,类似于将所有这些列表组合在一起,然后获取len(list(set(所有col列表的组合列表((,在这种情况下,得到以下输出:
id col1 col2 col3 total_years
0 [1999, 2000, 2001] [1989, 2000, 2005] [1999, 2004, 2005] 6
我可以生成单独的列来计算每个列表中的所有值,但简单地取所有列列表的十个值的总和,会给出错误的值,因为有些列表中的年份重复。
理想的操作是将所有列表合并为一个列表,然后从中得到一个集合,以及在我看来这个集合的长度。但是,我不知道这在熊猫身上会如何工作。
有一次尝试没有成功:
for col in df.columns[1:]:
new_col = str(col) + "_length"
df[new_col] = df[col].apply(len)
df['new_col_name'] = df.iloc[:,9:].sum(axis=1)
将所有列列表合并为一列中的单个列表后的第二次尝试。我试着得到那一列的长度,不,没用。
df['Total_years'] = len(set(total_lst_col))
stack
将所有列表合并为一列,然后合并为explode
。然后可以沿着原始索引groupby
+nunique
。即使你有一年没有list
,这也会起作用。
import pandas as pd
df = pd.DataFrame({'id': ['A', 'B', 'C'],
'col1': [[1999, 2000, 2001], [1999, 2001], 2000],
'col2': [[1989, 2000, 2005], [1989, 2000, 2005], [2001, 2002]],
'col3': [[1999, 2004, 2005], [1999], [2005]]})
#.iloc[:, 1:] to ignore the `id` column
df['total_years'] = df.iloc[:, 1:].stack().explode().groupby(level=0).nunique()
id col1 col2 col3 total_years
0 A [1999, 2000, 2001] [1989, 2000, 2005] [1999, 2004, 2005] 6
1 B [1999, 2001] [1989, 2000, 2005] [1999] 5
2 C 2000 [2001, 2002] [2005] 4
这里有一个解释:
第一个stack
步骤将所有内容放入一个具有MultiIndex的系列中,第0级是原始DataFrame索引,第1级是它所属的列(我们并不真正关心(。
df.iloc[:, 1:].stack()
0 col1 [1999, 2000, 2001]
col2 [1989, 2000, 2005]
col3 [1999, 2004, 2005]
1 col1 [1999, 2001]
col2 [1989, 2000, 2005]
col3 [1999]
2 col1 2000
col2 [2001, 2002]
col3 [2005]
explode
然后将这些列表扩展为每个值一行,并保持非列表值不变。对于相同列表的每个元素,重复上述系列的索引
df.iloc[:, 1:].stack().explode()
0 col1 1999 # index `0` `col1` had 3 elements in
col1 2000 # the list which get expanded to
col1 2001 # these three rows
col2 1989
...
2 col1 2000 # This value wasn't a list, explode keeps as is
col2 2001
col2 2002
col3 2005
最后,.groupby(level=0)
在该级别上分组,,该级别基于原始DataFrame索引,我们计算唯一值的数量,基于该系列的唯一值是在这些列中的任何列中找到的唯一年份。
您可以在每行上使用apply
chain
所有子列表合一set
保留uniqueslen
获取计数
from itertools import chain
df['total_years'] = df.apply(lambda x: len(set(chain(*x))), axis=1)