转置数据框并融化

Transpose a dataframe and melt

我有一个数据框。每个日期和公司始终有可用的数据。但是不能保证给定的行具有数据;如果该公司为真,则该行只有数据。

    date        IBM       AAPL_total_amount    IBM_total_amount   AAPL_count_avg  IBM_count_avg 
    2013-01-31  True    False    29                9
    2013-01-31  True    True     29                9                 27               5
    2013-02-31  False   True                                         27               5
    2013-02-08  True    True     2                 3                  5                6
      ...

如何将上述数据帧转换为长格式? 预期输出:

     date        Firm     total_amount  count_avg
    2013-01-31   IBM         9              5   
    2013-01-31   AAPL        29             27
      ...

可能需要添加一些逻辑来删除所有布尔掩码,但一旦你有了它就只是一个 stack


u = df.set_index('date').drop(['IBM', 'AAPL'], 1)
u.columns = u.columns.str.split('_', expand=True)
u.stack(0)

                 count  total
date
2013-01-31 IBM     9.0   29.0
           AAPL    5.0   27.0
           IBM     9.0   29.0
2013-02-31 AAPL    5.0   27.0
2013-02-08 AAPL    6.0    5.0
           IBM     3.0    2.0

如果您没有键列表,要删除所有掩码,可以使用 select_dtypes

df.select_dtypes(exclude=[bool])

这是一个不寻常的 table 设计。假设 table 被称为 df.

所以你首先要找到代码列表:

或者你在别处有:

tickers = ['AAPL','IBM']

或者您可以从 table:

中提取它们
tickers = [c for c in df.columns 
    if not c.endswith('_count') and 
    not c.endswith('_total') and 
    c != 'date']

现在你必须遍历代码:

res = []
for tic in tickers:
    sub = df[df[tic]][ ['date', f'{tic}_total','f{tic}_count'] ].copy()
    sub.columns = ['date', 'Total','Count']
    sub['Firm'] = tic
    res.append(sub)

res = pd.concat(res, axis=0)

最后,您可能希望对列重新排序:

res = res[['date','Item','Total','Count']]

您可能想要处理重复项。从我在你的例子中读到的内容,你想删除它们:

res = res.drop_duplicates()

使用 wide_to_long 预处理 columns 和 post - 切片处理和 dropna

df.columns = ['_'.join(col[::-1]) for col in df.columns.str.split('_')]
df_final = (pd.wide_to_long(df.reset_index(), stubnames=['total','count'], 
                            i=['index','date'], 
                            j='firm', sep='_', suffix='\w+')[['total', 'count']]
              .reset_index(level=[1,2]).dropna())

Out[59]:
             date  firm  total  count
index
0      2013-01-31   IBM   29.0    9.0
1      2013-01-31   IBM   29.0    9.0
1      2013-01-31  AAPL   27.0    5.0
2      2013-02-31  AAPL   27.0    5.0
3      2013-02-08   IBM    2.0    3.0
3      2013-02-08  AAPL    5.0    6.0