如何从 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 |
其中列包含以下内容:
- 内容:在列表
中找到的元素
- Unique: 元素在列表中单独出现的次数
- Started: 元素出现在开头的次数
- Finished: 元素出现在末尾的次数
- Middleway: 元素在开始和结束之间出现的次数。
我有点找到了这个任务的解决方案,但由于我使用了很多循环函数,我无法将该算法应用于更大的数据库,因为时间处理太长了。你能帮我推荐一个解决这个任务的代码吗?
这是一种方法:
你可以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
我正在开发一个 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 |
其中列包含以下内容:
- 内容:在列表 中找到的元素
- Unique: 元素在列表中单独出现的次数
- Started: 元素出现在开头的次数
- Finished: 元素出现在末尾的次数
- Middleway: 元素在开始和结束之间出现的次数。
我有点找到了这个任务的解决方案,但由于我使用了很多循环函数,我无法将该算法应用于更大的数据库,因为时间处理太长了。你能帮我推荐一个解决这个任务的代码吗?
这是一种方法:
你可以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