Python 熊猫-转换数据视图
我有一个数据框,如下所示,其中id和date是索引Python 熊猫-转换数据视图,python,numpy,pandas,Python,Numpy,Pandas,我有一个数据框,如下所示,其中id和date是索引 id name date gross1 gross2 net1 net2 balance1 balance2 1 abc 01/01/2001 100 101 50 51 200 201 2 def 01/02/2001 201 202 40 41 300
id name date gross1 gross2 net1 net2 balance1 balance2
1 abc 01/01/2001 100 101 50 51 200 201
2 def 01/02/2001 201 202 40 41 300 3001
3 ghi 01/03/2001 300 303 99 98 1000 10001
我希望对其进行转换,使数据按如下方式进行转换:
id date level parent category name value1 value1
1 01/01/2001 0 NaN gross abc 100 101
2 01/01/2001 1 1 net abc 50 51
3 01/01/2001 1 1 balance abc 200 201
4 01/02/2001 0 NaN gross def 201 201
5 01/02/2001 1 4 net def 40 41
6 01/02/2001 1 4 balance def 300 3001
7 01/03/2001 0 NaN gross ghi 300 303
8 01/03/2001 1 7 net ghi 99 98
9 01/03/2001 1 7 balance ghi 1000 10001
我试着旋转和卸垛……但没能完全正确。我来的时候做的事情如下:
df_gross = df['name','gross1','gross2']
df_gross.columns = ['name', 'value1', 'value2']
df_gross['level']=0
df_gross['category']='gross'
df_net = df['name', 'net1','net2']
df_net.columns = ['name', 'value1', 'value2']
df_gross['level']=1
df_gross['category']='net'
df_balance = df['name', 'balance1','balance2']
df_balance.columns = ['name', 'value1', 'value2']
df_balance['level']=1
df_balance['category']='balance'
df = pandas.concat(df_gross, df_net, df_balance)
然而,我面临的问题是如何高效地生成新id,并将父列设置为新生成的id。我可以..在concat之后,重置_索引,然后删除'id'列,然后将索引设置为pandas生成的索引(应该是值1..n)。然后我想我做了一个dataframe.apply,通过'date'和'level=0'找到父对象,并相应地设置父对象。这是最有效的方法吗?我认为最好的方法是通过pandas重塑索引和名称,并使用numpy重塑值 首先,让我们在numpy中重塑数值:
arr = df.ix[:,'gross1':'balance2'].values.reshape(9,2)
array([[ 100, 101],
[ 50, 51],
[ 200, 201],
[ 201, 202],
[ 40, 41],
[ 300, 3001],
[ 300, 303],
[ 99, 98],
[ 1000, 10001]], dtype=int64)
现在,让我们在pandas中重塑数据帧,以便索引和列名更接近我们想要的:
df2 = df.set_index(['id','date','name']).stack().iloc[::2].reset_index().iloc[:,:-1]
id date name level_3
0 1 01/01/2001 abc gross1
1 1 01/01/2001 abc net1
2 1 01/01/2001 abc balance1
3 2 01/02/2001 def gross1
4 2 01/02/2001 def net1
5 2 01/02/2001 def balance1
6 3 01/03/2001 ghi gross1
7 3 01/03/2001 ghi net1
8 3 01/03/2001 ghi balance1
这基本上是90%,现在只需将它们结合起来:
df2[['value1','value2']] = pd.DataFrame(arr)
id date name level_3 value1 value2
0 1 01/01/2001 abc gross1 100 101
1 1 01/01/2001 abc net1 50 51
2 1 01/01/2001 abc balance1 200 201
3 2 01/02/2001 def gross1 201 202
4 2 01/02/2001 def net1 40 41
5 2 01/02/2001 def balance1 300 3001
6 3 01/03/2001 ghi gross1 300 303
7 3 01/03/2001 ghi net1 99 98
8 3 01/03/2001 ghi balance1 1000 10001
我不确定您打算如何使用级别/父级Colunn,但以下是如何设置它们:
df2['parent'] = df2.groupby('id').cumcount()
df2['parent_index'] = df2[ df2.parent == 0 ].index.to_series()
df2['parent_index'] = df2.parent_index.fillna(method='ffill')
df2['parent'] = np.where( df2.parent > 1, 1, df2.parent )
df2['parent_index'] = np.where( df2.parent == 0, np.nan, df2.parent_index )
id date name level_3 value1 value2 parent parent_index
0 1 01/01/2001 abc gross1 100 101 0 NaN
1 1 01/01/2001 abc net1 50 51 1 0
2 1 01/01/2001 abc balance1 200 201 1 0
3 2 01/02/2001 def gross1 201 202 0 NaN
4 2 01/02/2001 def net1 40 41 1 3
5 2 01/02/2001 def balance1 300 3001 1 3
6 3 01/03/2001 ghi gross1 300 303 0 NaN
7 3 01/03/2001 ghi net1 99 98 1 6
8 3 01/03/2001 ghi balance1 1000 10001 1 6
这完全可以用熊猫来完成
import numpy as np
import pandas as pd
# assuming your dataframe is called `df`, first stack the dataframe
dfnew = df.set_index(['id', 'date','name']).stack().reset_index()
# split the category information into category and value level, then delete column level_3
dfnew[['category', 'valuelevel']] = dfnew.level_3.apply(
lambda x: pd.Series([x[:-1], x[-1]]))
del dfnew['level_3']
# reshape data to meet required format and reset_index
dfnew = dfnew.set_index(['id', 'date', 'name', 'category', 'valuelevel']).unstack(level=-1).reset_index()
# fix MultiIndex mess by flattening the column names,
# note: renaming id to parent because that is what it will end up being, new id will be the index.
dfnew.columns = ['parent', 'date', 'name', 'category', 'value1', 'value2']
# reorder the data frame according to parent_id & category ['gross', 'net', 'balance'],
# using a second data frame
# then get rid of the extra fields `index` & `catlevel`
cat_level = pd.DataFrame({'category': ['gross', 'net', 'balance'], 'catlevel': [0, 1, 2]})
dfnew = dfnew.merge(cat_level)
dfnew = dfnew.sort(['parent', 'catlevel']).reset_index()
del dfnew['index']
del dfnew['catlevel']
# generate the new row id from index
dfnew['id'] = dfnew.reset_index()['index'] + 1
# reset the parent column to point to the current parent id
dfnew['parent'] = dfnew.groupby('parent')['id'].transform(min)
# add new column level
dfnew['level'] = 1
# update the parent & level columns based on the mask parent == id
mask = dfnew.parent == dfnew.id
dfnew.level[mask] = 0
dfnew.parent[mask] = np.NaN
最后的数据帧如下所示:
parent date name category value1 value2 id level
0 NaN 01/01/2001 abc gross 100 101 1 0
1 1 01/01/2001 abc net 50 51 2 1
2 1 01/01/2001 abc balance 200 201 3 1
3 NaN 01/02/2001 def gross 201 202 4 0
4 4 01/02/2001 def net 40 41 5 1
5 4 01/02/2001 def balance 300 3001 6 1
6 NaN 01/03/2001 ghi gross 300 303 7 0
7 7 01/03/2001 ghi net 99 98 8 1
8 7 01/03/2001 ghi balance 1000 10001 9 1
列顺序与您指定的不同,但形状和值正确。我不知道如何移动列,但我们可以轻松创建具有正确列顺序的新数据帧
column_ordered = ['id', 'date', 'level', 'parent', 'category', 'name', 'value1', 'value2']
finaldf = pd.DataFrame()
for col in columns_ordered:
finaldf[col] = dfnew[col]
为什么第一个家长ID是NaN?这是需要的吗?是..空..表示顶层。我想我可以自己做。我刚刚注意到“可信和/或官方消息来源”的说明。不确定这意味着什么,但我的答案中的所有内容都是numpy/pandas的标准用法。
父行
是否必须是带有category=gross
的那一行?谢谢。我很好奇,基于我迄今为止所取得的成就,我将如何做到这一点?通过选择相关列将数据帧拆分为3个数据帧。考虑到这一点,我如何才能以我想要的方式生成ID和父ID?我不确定我是否遵循了这个问题,但可以说两件事:(1)通常,最好将相关的东西保持在同一个数据帧中,而不是将它们分开。(2) 您可能希望发布一个新的后续问题,确切地显示您希望如何处理此数据。有时,最好是询问如何在保留pandas中的方法的同时获得一些结果。也就是说,您可以使用类似于df_-gross=df[['id'、'date'、'name'、'gross1'、'gross2']]
或df_-gross=df2[df2.level_3='gross1']
的内容剥离原始数据集中的“gross”。但是我怀疑你最好把东西放在一起,使用groupby('id')
进行处理——不过我也不知道你到底想在这里做什么。现在发生的是,数据出现在一个包含43列的大表中!前3列可视为关键,以下40列可分为4类,每类10列可叠加在其他列上(即10列显示世界数据,10列显示北美数据,10列显示欧洲数据,10列显示亚洲数据)。我想做的是在树状视图网格中这样显示它们..其中“世界”数据是父数据,如果用户需要,它们可以展开以查看细分。嗯,您可以选择。如果我是你,我会发布一个新问题,但你可以将所有内容都保存在同一个数据集中,并使用选择技术,或者每次都将它们分开然后重新合并。您可能希望在每一行中保留重复的父数据,但如果您的数据不是那么大,这并不是一个真正的问题,并且可能会简化一些事情(这样您就不必每次都重新合并)。我推测这就是为什么可能最好只做一个后续问题并准确显示您想要的内容。