如何从 pandas 中的列表创建接触点 DataFrame

How to create a touchpoint DataFrame from a list in pandas

我正在开发一个 Python 项目,它有一个像这样的 DataFrame:

row1 = ['BBB', 'AAA', 'CCC']
row2 = ['CCC']
row3 = ['DDD', 'AAA']
row4 = ['DDD', 'BBB', 'AAA', 'EEE', 'CCC']
row5 = ['EEE', 'AAA', 'EEE', 'CCC']
data = {'List': [row1, row2, row3, row4, row5],
        'Path_length':  [3, 1, 2, 5, 4]}

df = pd.DataFrame(data)

这导致:

|     |             List                   |   Path_length   | 
|  0  | ['BBB', 'AAA', 'CCC']              |       3         |  
|  1  | ['CCC']                            |       1         |   
|  2  | ['DDD','AAA']                      |       2         |   
|  3  | ['DDD','BBB', 'AAA', 'EEE', 'CCC'] |       5         |  
|  4  | ['EEE', 'AAA', 'EEE', 'CCC']       |       4         |

任务包括生成以下 DataFrame:

|     |   Content       |   Unique    |  Started  |  Middleway  |  Finished  |
|  0  |     AAA         |     0       |     0     |      3      |      1     | 
|  1  |     BBB         |     0       |     1     |      1      |      0     |
|  2  |     CCC         |     1       |     0     |      0      |      3     |
|  3  |     DDD         |     0       |     2     |      0      |      0     |
|  4  |     EEE         |     0       |     1     |      2      |      0     |

其中列包含以下内容:

我有点找到了这个任务的解决方案,但由于我使用了很多循环函数,我无法将该算法应用于更大的数据库,因为时间处理太长了。你能帮我推荐一个解决这个任务的代码吗?

这是一种方法:

你可以mask长度为1的路径(将条件为True的值替换为空字符串""这样你就可以explode列表来统计其中的值)。

然后对于这些行,使用 value_counts 计算“开始”、“中间”和“完成”值。

然后,对于长度为 1 的行,计算“唯一”值。

最后,删除虚拟 "" 索引,sort 并重新排列列以获得所需的结果:

masked_df = df['List'].mask(df['Path_length']==1, '')
out = masked_df.explode().value_counts().to_frame().rename(columns={'List': 'Finished'}).rename_axis(index=['Content'])
out['Started'] = masked_df.str[0].value_counts()
out['Middleway'] = masked_df.str[1:-1].explode().value_counts()
out['Finished'] -= out[['Started','Middleway']].sum(axis=1)
out['Unique'] = df['List'].where(df['Path_length']==1, '').explode().value_counts()
out = out.drop(index='').fillna(0).astype(int).sort_index().reset_index()[['Content','Unique','Started','Middleway','Finished']]

输出:

  Content  Unique  Started  Middleway  Finished
0     AAA       0        0          3         1
1     BBB       0        1          1         0
2     CCC       1        0          0         3
3     DDD       0        2          0         0
4     EEE       0        1          2         0

另一种解决方案。首先,我们在 List 列上应用 enumerate,分解它,然后 sum() boolean columns:

df = df.assign(List=df.List.apply(lambda x: [*enumerate(x, 1)])).explode("List")
df[["tmp", "Content"]] = df["List"].apply(pd.Series)

df["Unique"] = df.tmp.eq(1).eq(df.Path_length)
df["Started"] = df.tmp.eq(1) & ~df.Unique
df["Middleway"] = df.tmp.ne(1) & df.tmp.ne(df.Path_length)
df["Finished"] = df.tmp.eq(df.Path_length) & ~df.Unique

print(df.groupby("Content").sum().iloc[:, 2:].reset_index())

打印:

  Content  Unique  Started  Middleway  Finished
0     AAA       0        0          3         1
1     BBB       0        1          1         0
2     CCC       1        0          0         3
3     DDD       0        2          0         0
4     EEE       0        1          2         0