簡體   English   中英

壓縮 Pandas 數據框中的列

[英]Condensing columns in a Pandas Dataframe

我正在通過 VerisPy 處理來自 Veris 項目的數據,但在將其重新格式化以用於其他應用程序時遇到了一些麻煩。

VerisPy 輸出一個數據幀,其中包含來自提交給 Veris 的 JSON 文件的解析事件信息。 數據框中的每一行都對應一個事件,詳細說明它是如何/何時發生的。 問題是它最終有數千個帶有布爾標志的列。

所以每個事件行可能有如下列:

事件編號 惡意軟件 動作黑客 誤用 演員.外部.競爭對手 演員.外部犯罪 演員.內部.員工 演員.內部.客戶 目標
1 真的 錯誤的 錯誤的 錯誤的 錯誤的 真的 錯誤的 微軟
2 錯誤的 真的 錯誤的 真的 錯誤的 錯誤的 錯誤的 美國銀行

我想折疊/組合這些並將列值用作實際數據。 在上面的例子中,我們可能會這樣:

事件編號 行動 演員 目標
1 惡意軟件 內部 - 員工 微軟
2 黑客攻擊 外部 - 競爭對手 美國銀行

我是 Pandas 的新手,但從文檔中嘗試了相當多的東西,結果喜憂參半。 Melt 看起來很有希望,但我不確定如何將列名放入實際的行級數據中。 有人有指點嗎?

單程:

  1. ['event_id', 'target']index
  2. splitexpand columns以創建hierarchical columns (我們將在點積中使用它)。
  3. hierarchical columns extract level 1值並使用dataframe進行dot product
  4. 執行一些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
筆記:

您還可以使用level=0列值,而不是通過rename renaming columnsrename renaming columns -

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個目標,您可以使用多個值pivot_table ,而不是stack / unstack

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)
)

您可以將代碼從寬翻轉為長,僅過濾True所在的行,進行一些修改以獲得輸出。

 # flip from wide to long
(pd.wide_to_long(df,
                 stubnames=['action','actor'], 
                 i=['event_id','target'],
                 j='subs', 
                 sep='.', 
                 suffix='.+')
  .loc[lambda df: df.any(1)] # keeps only rows that have `True`
   # if any row has `True`, 
   # replace it with values from `subs` index
  .where(lambda df: df.isna(), 
         lambda df: df.index.get_level_values('subs'))
  .fillna('')
  .droplevel('subs') # served its purpose, let it go
  # use the groupby with the agg to reduce to single rows
  .groupby(['event_id', 'target'])
  .agg("".join)
  .reset_index()
)
: 
   event_id           target   action                actor
0         1        Microsoft  malware    internal.employee
1         2  Bank of America  hacking  external.competitor

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM