转置数据框并融化
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
我有一个数据框。每个日期和公司始终有可用的数据。但是不能保证给定的行具有数据;如果该公司为真,则该行只有数据。
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