压缩Pandas数据框中的列
我正在通过 VerisPy 处理来自 Veris 项目的数据,但在将其重新格式化以用于其他应用程序时遇到了一些麻烦。
VerisPy 输出一个数据帧,其中包含来自提交给 Veris 的 JSON 文件的解析事件信息。数据框中的每一行都对应一个事件,详细说明它是如何/何时发生的。问题是它最终有数千个带有布尔标志的列。
所以每个事件行可能有如下列:
| 事件编号 | 恶意软件 | 动作黑客 | 误用 | 演员.外部.竞争对手 | 演员.外部犯罪 | 演员.内部.员工 | 演员.内部.客户 | 目标 |
|---|---|---|---|---|---|---|---|---|
| 1 | 真的 | 错误的 | 错误的 | 错误的 | 错误的 | 真的 | 错误的 | 微软 |
| 2 | 错误的 | 真的 | 错误的 | 真的 | 错误的 | 错误的 | 错误的 | 美国银行 |
回答
单程:
- 设置
['event_id', 'target']为index。 split并expand columns创建hierarchical columns(我们将需要在点积中使用它)。extract中的level 1值hierarchical columns并dot product使用dataframe.- 做一些
string manipulations和rename的columns
(我已经添加了2种方式重命名列),以获得所需output。
df1 = df.set_index(['event_id', 'target'])
df1.columns = df1.columns.str.split('.', expand=True, n=1)
df = (
df1.dot(df1.columns.get_level_values(1) + ',')
.str.strip(',')
.str.split(',', expand=True)
.rename(columns={0: 'Action', 1: 'Actor'})
.reset_index()
)
输出:
event_id target Action Actor
0 1 Microsoft malware internal.employee
1 2 Bank of America hacking external.competitor
笔记:
除了renaming columns通过rename您还可以使用这样的level=0列值 -
df1 = df.set_index(['event_id', 'target'])
df1.columns = df1.columns.str.split('.', expand=True, n=1)
df = (
df1.dot(df1.columns.get_level_values(1) + ',')
.str.strip(',')
.str.split(',',expand=True)
)
df.columns = dict.fromkeys(df1.columns.get_level_values(0)).keys()
df = df.reset_index()
另一种选择是使用mul:
df1 = df.set_index(['event_id', 'target'])
df1.columns = df1.columns.str.split('.', expand=True, n=1)
df = (
df1.mul(df1.columns.get_level_values(1))
.replace('', np.NAN)
.droplevel(1, axis =1)
.stack()
.unstack()
)
笔记:
如果您有 1 个目标的 actor 和 agent 的多个值,您可以使用/pivot_table代替:stackunstack
df1 = df.set_index(['event_id', 'target'])
df1.columns = df1.columns.str.split('.', expand=True, n=1)
(
df1.mul(df1.columns.get_level_values(1))
.replace('', np.NAN)
.droplevel(1, axis =1)
.stack()
.reset_index()
.pivot_table(index = ['event_id', 'target'], columns = 'level_2' , values = 0, aggfunc = ', '.join)
)