Python 在多级数据帧中设置值

Python 在多级数据帧中设置值,python,pandas,Python,Pandas,我最近一直在研究多级数据帧,我发现它们可以显著减少大型数据集的计算时间。例如,考虑简单的数据帧: df = pd.DataFrame([ [1, 111, 0], [2, 222, 0], [1, 111, 0], [2, 222, 1], [1, 111, 1], [2, 222, 2] ], columns=["ID", "A", "B"], index=[1, 1, 2, 2, 3, 3] ) df.head(6) ID A B

我最近一直在研究多级数据帧,我发现它们可以显著减少大型数据集的计算时间。例如,考虑简单的数据帧:

df = pd.DataFrame([
        [1, 111, 0], [2, 222, 0], [1, 111, 0],
        [2, 222, 1], [1, 111, 1], [2, 222, 2]
    ], columns=["ID", "A", "B"], index=[1, 1, 2, 2, 3, 3]
)
df.head(6)

    ID   A    B
1   1   111   0
1   2   222   0
2   1   111   0
2   2   222   1
3   1   111   1
3   2   222   2
pivot_df = df.pivot(columns="ID")
pivot_df.head()

     A        B
ID   1   2    1   2
1   111 222   0   0
2   111 222   0   1
3   111 222   1   2
可通过ID旋转以创建多级数据框:

df = pd.DataFrame([
        [1, 111, 0], [2, 222, 0], [1, 111, 0],
        [2, 222, 1], [1, 111, 1], [2, 222, 2]
    ], columns=["ID", "A", "B"], index=[1, 1, 2, 2, 3, 3]
)
df.head(6)

    ID   A    B
1   1   111   0
1   2   222   0
2   1   111   0
2   2   222   1
3   1   111   1
3   2   222   2
pivot_df = df.pivot(columns="ID")
pivot_df.head()

     A        B
ID   1   2    1   2
1   111 222   0   0
2   111 222   0   1
3   111 222   1   2
以这种格式保存数据的好处在于,我可以通过引用0级列跨所有ID执行“向量”操作:

pivot_df["A"] * (1 + pivot_df["B"])**2

ID  1   2
1   111 222
2   111 888
3   444 999
这些操作对我真的很有帮助!在现实生活中,我的计算要复杂得多,需要对>1000个ID执行计算。我使用的一个通用数据帧大小包含10列(级别0)和1000个ID(级别1)以及350行

我对做两件事感兴趣:在这个数据透视框架中更新特定字段的值;为此数据帧创建一个新列。差不多

pivot_df["A"] = pivot_df["A"] * (1 + pivot_df["B"])**2

当我执行这些操作时,我没有得到任何错误,但是数据帧保持不变。我也尝试过使用.loc和.iloc,但没有成功

我认为问题在于维护计算数据帧的多级结构,但我对使用多级数据帧非常陌生,不知道如何有效地解决这个问题。我有一个笨拙的解决办法,但效率不高(创建一个计算数据帧字典,然后将它们合并在一起

df_dict = OrderedDict()
df_dict["A"] = pivot_df["A"]
df_dict["B"] = pivot_df["B"]
df_dict["C"] = pivot_df["A"] * (1 + pivot_df["B"])**2

dfs = [val.T.set_index(np.repeat(key, val.shape[1]), append=True).T for key, val in df_dict.iteritems()]
final_df = reduce(lambda x, y: pd.merge(x, y, left_index=True, right_index=True), dfs)
final_df.columns = final_df.columns.swaplevel(0, 1)
或者类似地

df_dict = OrderedDict()
df_dict["A"] = pivot_df["A"] * (1 + pivot_df["B"])**2
df_dict["B"] = pivot_df["B"]

dfs = [val.T.set_index(np.repeat(key, val.shape[1]), append=True).T for key, val in df_dict.iteritems()]
final_df = reduce(lambda x, y: pd.merge(x, y, left_index=True, right_index=True), dfs)
final_df.columns = final_df.columns.swaplevel(0, 1)

这不一定很笨重(我有点为这种解决方法感到骄傲),但这肯定不是有效的或计算优化的。有人有什么建议吗?

选项1
不要先转动轴!
您说过,透视很方便,因为您可以在新的透视形式中执行向量计算。这是一种错误的表示,因为您可以在透视之前轻松执行这些计算

df['C'] = df["A"] * (1 + df["B"]) ** 2
df.pivot(columns='ID')

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998
如果您愿意,也可以用管道式单内衬

df.assign(C=df.A * (1 + df.B) ** 2).pivot(columns='ID')

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998

选项2
pd.concat

但要回答你的问题

pdf = df.pivot(columns='ID')
pd.concat([
        pdf.A, pdf.B, pdf.A * (1 + pdf.B) ** 2
    ], axis=1, keys=['A', 'B', 'C'])

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998

选项3
更多
pd.concat

在concat之前向列添加另一个标高

pdf = df.pivot(columns='ID')
c = pdf.A * (1 + pdf.B) ** 2
c.columns = [['C'] * len(c.columns), c.columns]

pd.concat([pdf, c], axis=1)

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998

选项1
不要先转动轴!
您说过,透视很方便,因为您可以在新的透视形式中执行向量计算。这是一种错误的表示,因为您可以在透视之前轻松执行这些计算

df['C'] = df["A"] * (1 + df["B"]) ** 2
df.pivot(columns='ID')

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998
如果您愿意,也可以用管道式单内衬

df.assign(C=df.A * (1 + df.B) ** 2).pivot(columns='ID')

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998

选项2
pd.concat

但要回答你的问题

pdf = df.pivot(columns='ID')
pd.concat([
        pdf.A, pdf.B, pdf.A * (1 + pdf.B) ** 2
    ], axis=1, keys=['A', 'B', 'C'])

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998

选项3
更多
pd.concat

在concat之前向列添加另一个标高

pdf = df.pivot(columns='ID')
c = pdf.A * (1 + pdf.B) ** 2
c.columns = [['C'] * len(c.columns), c.columns]

pd.concat([pdf, c], axis=1)

      A       B       C      
ID    1    2  1  2    1     2
1   111  222  0  0  111   222
2   111  222  0  1  111   888
3   111  222  1  2  444  1998

你的代码没有生成你正在显示的数据帧。哎呀,我一定是从我的Jupyter笔记本中复制了错误的代码。我应该替换
df=pd.dataframe([[1111,0],[2222,0],[1111,0],[2222,1],[1111,1],[2222]],columns=[“ID”,“A”,“B”],index=[1,1,2,3])
您的代码没有生成您正在显示的数据帧。哎呀,我一定是从我的Jupyter笔记本中复制了错误的代码。我应该替换
df=pd.dataframe([[1111,0],[2222,0],[1111,0],[2222,1],[1111,1],[2222,2]],columns=[“ID”,“A”,“B”],index=[1,1,2,2,3,3])
作为我流程的一部分,我需要执行
cumsum()
cumprod()
在我的计算过程中的不同点按ID进行计算,因此这是我需要旋转而不是直接执行计算的另一个原因。我通过lD执行一些自定义的自回归计算。PD concat可能更有效,但是直接更改?@RMAT的值如何才有意义。选项2和3应该我会帮你处理的。在我的过程中,我需要执行
cumsum()
cumprod()
在我的计算过程中的不同点按ID进行计算,因此这是我需要旋转而不是直接执行计算的另一个原因。我通过lD执行一些自定义的自回归计算。PD concat可能更有效,但是直接更改?@RMAT的值如何才有意义。选项2和3应该我会帮你处理的。