[英]Python datatable/pandas reshaping problem
我需要重塑我的df。
这是我的输入 df:
import pandas as pd
import datatable as dt
DF_in = dt.Frame(name=['name1', 'name1', 'name1', 'name1', 'name2', 'name2', 'name2', 'name2'],
date=['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08'],
type=['a', 'b', 'a', 'b', 'b', 'a', 'b', 'a'],
value=[1, 2, 3, 4, 5, 6, 7, 8])
| name date type value
-- + ----- ---------- ---- -----
0 | name1 2021-01-01 a 1
1 | name1 2021-01-02 b 2
2 | name1 2021-01-03 a 3
3 | name1 2021-01-04 b 4
4 | name2 2021-01-05 b 5
5 | name2 2021-01-06 a 6
6 | name2 2021-01-07 b 7
7 | name2 2021-01-08 a 8
这是所需的 output df:
DF_out = dt.Frame(name=['name1', 'name1', 'name2', 'name2'],
date_a=['2021-01-01', '2021-01-03', '2021-01-06', '2021-01-08'],
date_b=['2021-01-02', '2021-01-04', '2021-01-07', None],
value_a=[1, 3, 6, 8],
value_b=[2, 4, 7, None])
| name date_a date_b value_a value_b
-- + ----- ---------- ---------- ------- -------
0 | name1 2021-01-01 2021-01-02 1 2
1 | name1 2021-01-03 2021-01-04 3 4
2 | name2 2021-01-06 2021-01-07 6 7
3 | name2 2021-01-08 NA 8 NA
如有必要,可以将数据表帧转换为 pandas DataFrame:
DF_in = DF_in.to_pandas()
转型:
我希望这个解释是可以理解的。
先感谢您
让我们使用数据框,所以首先加载数据
df = pd.DataFrame(dict(name=['name1', 'name1', 'name1', 'name1', 'name2', 'name2', 'name2', 'name2'],
date=['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08'],
type=['a', 'b', 'a', 'b', 'b', 'a', 'b', 'a'],
value=[1, 2, 3, 4, 5, 6, 7, 8]))
然后在下面我们执行以下步骤
b
sset_index
+ unstack
df1 = df[~((df['type'] == 'b') & (df['type'].shift() == 'b'))].copy()
df1['g'] = np.arange(len(df1))//2
df2 = df1.set_index(['g','type']).unstack(level=1)
df2.columns = ['_'.join(tup).rstrip('_') for tup in df2.columns.values]
df2.drop(columns = 'name_b').rename(columns = {'name_a':'name'})
output
name date_a date_b value_a value_b
g
0 name1 2021-01-01 2021-01-02 1.0 2.0
1 name1 2021-01-03 2021-01-04 3.0 4.0
2 name2 2021-01-06 2021-01-07 6.0 7.0
3 name2 2021-01-08 NaN 8.0 NaN
数据表没有允许在垂直和水平位置之间翻转的重塑功能; 因此,pandas 是您最好的选择。
以下是我对您的挑战的尝试:
from datatable import dt
import pandas as pd
df = DF_in.to_pandas()
(df
.assign(temp = df.index, # needed for ranking
b_first = lambda df: df.groupby('name')['type'].transform('first'))
.assign(temp = lambda df: df.groupby('name')['temp'].rank())
# get rid of rows in groups where b is first
.query('~(temp==1 and b_first=="b")')
# needed to get unique values in index when pivoting
.assign(temp = lambda df: df.groupby(['name','type']).cumcount())
.pivot(['name','temp'], ['type'], ['date','value'])
.pipe(lambda df: df.set_axis(df.columns.to_flat_index(), axis='columns')
.rename(columns = lambda df: "_".join(df)))
.droplevel('temp')
.reset_index()
)
name date_a date_b value_a value_b
0 name1 2021-01-01 2021-01-02 1 2
1 name1 2021-01-03 2021-01-04 3 4
2 name2 2021-01-06 2021-01-07 6 7
3 name2 2021-01-08 NaN 8 NaN
概括:
过滤掉“b”是组中第一个条目的行
为避免在旋转(重新索引)时由于重复索引而导致错误,请创建一个临时 cumcount 列
rest 依赖于 pivot 和一些名称编辑(设置轴和重命名功能)。 您可以使用pyjanitor的 pivot_wider function进一步抽象:
# pip install pyjanitor import janitor (df.assign(temp = df.index, b_first = lambda df: df.groupby('name')['type'].transform('first')).assign(temp = lambda df: df.groupby('name')['temp'].rank()).query('~(temp==1 and b_first=="b")').assign(temp = lambda df: df.groupby(['name','type']).cumcount()).pivot_wider(index=['name', 'temp'], names_from=['type'], values_from=['date','value'], names_sep="_", names_from_position='last').drop(columns='temp') )
非常感谢大家的回答。 与此同时,我开发了一个仅使用数据表 package 的解决方案,针对当前限制使用了一些解决方法:
代码:
import math
import datatable as dt
from datatable import dt, f, by, update, join
DF_in = dt.Frame(name=['name1', 'name1', 'name1', 'name1', 'name2', 'name2', 'name2', 'name2'],
date=['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08'],
type=['a', 'b', 'a', 'b', 'b', 'a', 'b', 'a'],
value=[1, 2, 3, 4, 5, 6, 7, 8])
def group_id(n):
l = [x for x in range(0, math.floor(n / 2))]
l = sorted(l * 2)
if n % 2 != 0:
try:
l.append(l[-1] + 1)
except IndexError:
l.append(0)
return l
DF_in['id'] = range(DF_in.nrows)
first_row = f.id==dt.min(f.id)
row_eq_b = dt.first(f.type)=="b"
remove_rows = first_row & row_eq_b
DF_in[:, update(remove_rows = ~remove_rows), 'name']
DF_in = DF_in[f[-1]==1, :-1]
group_count = DF_in[:, {"Count": dt.count()}, by('name')][:, 'Count'].to_list()[0]
group_id_column = []
for x in group_count:
group_id_column = group_id_column + group_id(x)
DF_in['group_id'] = dt.Frame(group_id_column)
df1 = DF_in[f.type == 'a', ['name', 'date', 'value', 'group_id']]
df2 = DF_in[f.type == 'b', ['name', 'date', 'value', 'group_id']]
df2.key = ['name', 'group_id']
DF_out = df1[:, :, join(df2)]
DF_out.names = {'date': 'date_a', 'value': 'value_a', 'date.0': 'date_b', 'value.0': 'value_b'}
DF_out[:, ['name', 'date_a', 'date_b', 'value_a', 'value_b']]
| name date_a date_b value_a value_b
-- + ----- ---------- ---------- ------- -------
0 | name1 2021-01-01 2021-01-02 1 2
1 | name1 2021-01-03 2021-01-04 3 4
2 | name2 2021-01-06 2021-01-07 6 7
3 | name2 2021-01-08 NA 8 NA
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.