我正在尝试堆叠、熔化、g​​rouby 或重塑 Pandas DataFrame

I am trying to Stack, Melt, grouby or reshape a Pandas DataFrame

我正在尝试重塑下面的数据框(从 .csv 导入),将东距、北距和节点名称值保持在同一行,但所有内容 'stacked' 都在 4 列中。因此,我希望 V0e、V0n 和 Vd 列中的数据位于 S0_Pe、S0_Pn 和 S0_Pd 列中的数据之上。实际上有 8 组这样的 easting/northing/node 三重奏。 我是否需要将 V0e、V0n、S0_Pe 和 S0_Pn 重命名为 'Easting' 和 'Northing' 以及 Vd & S0_Pd 为 'Node'? 我已经尝试过 grouby、stack 和 melt,但要么所有内容都变成两列('shot' 和其他所有内容),要么无法按照我的意愿进行分组。
我还查看了 MultiIndex,节点位于 easting/northing 对之上的级别,但我未能将其应用于从我的 .csv 文件加载的现有 df。

Index   shot    V0e         V0n         Vd   S0_Pe      S0_Pn       S0_Pd
0       1001    530811.1    6764623.3   Vd   nan        nan         S0_Pd
1       1002    530808.8    6764617.4   Vd   530771.3   6764510.4   S0_Pd
2       1003    530806.6    6764611.4   Vd   nan        nan         S0_Pd
3       1004    530804.2    6764605.8   Vd   530765.6   6764499.1   S0_Pd

我不介意它看起来像这样:

Index   shot    V0e         V0n         Vd   
0       1001    530811.1    6764623.3   Vd   
1       1002    530808.8    6764617.4   Vd   
2       1003    530806.6    6764611.4   Vd   
3       1004    530804.2    6764605.8   Vd   
4       1001    nan         nan         S0_Pd
5       1002    530771.3    6764510.4   S0_Pd
6       1003    nan         nan         S0_Pd
7       1004    530765.6    6764499.1   S0_Pd

或者这个,我只需要坐标对和节点一起移动:

Index   shot    V0e         V0n         Vd   
0       1001    530811.1    6764623.3   Vd   
1       1001    nan         nan         S0_Pd    
2       1002    530808.8    6764617.4   Vd   
3       1002    530771.3    6764510.4   S0_Pd    
4       1003    530806.6    6764611.4   Vd
5       1003    nan         nan         S0_Pd
6       1004    530804.2    6764605.8   Vd
7       1004    530765.6    6764499.1   S0_Pd

您可以这样做 pd.wide_to_long 并重命名一个小列以标准化:

df_rc = df.rename(columns={'V0e':'V0e:Vd', 
                   'V0n':'V0n:Vd',
                   'S0_Pe':'V0e:S0_Pd',
                   'S0_Pn':'V0n:S0_Pd'})

df_rc = df_rc.drop(['Vd', 'S0_Pd'], axis=1)

df_out = pd.wide_to_long(df_rc, 
                          ['V0e', 'V0n'], 
                          ['Index', 'shot'], 
                          'Vd', 
                          ':', 
                          '.*')\
            .reset_index()

输出:

   Index  shot     Vd       V0e        V0n
0      0  1001     Vd  530811.1  6764623.3
1      0  1001  S0_Pd       NaN        NaN
2      1  1002     Vd  530808.8  6764617.4
3      1  1002  S0_Pd  530771.3  6764510.4
4      2  1003     Vd  530806.6  6764611.4
5      2  1003  S0_Pd       NaN        NaN
6      3  1004     Vd  530804.2  6764605.8
7      3  1004  S0_Pd  530765.6  6764499.1

您可以使用经常被遗忘的 pd.lreshape 来做到这一点:

此函数是 pd.wide_to_long 的通用版本,您可以在其中传递 {new_column name: [*columns to vertically stack]} 的字典。然后melt编辑此字典中任何未指定的列以适合输出。

import pandas as pd

out = pd.lreshape(
    df, 
    {'V0e': ['V0e', 'S0_Pe'], 
     'V0n': ['V0n', 'S0_Pn'], 
     'Vd': ['Vd', 'S0_Pd']}, 
    dropna=False
)

print(out)
   Index  shot       V0e        V0n     Vd
0      0  1001  530811.1  6764623.3     Vd
1      1  1002  530808.8  6764617.4     Vd
2      2  1003  530806.6  6764611.4     Vd
3      3  1004  530804.2  6764605.8     Vd
4      0  1001       NaN        NaN  S0_Pd
5      1  1002  530771.3  6764510.4  S0_Pd
6      2  1003       NaN        NaN  S0_Pd
7      3  1004  530765.6  6764499.1  S0_Pd

一个有效的选择是使用 pivot_longer from pyjanitor 转换为长格式,将新列 headers 的列表传递给 names_to,并在 names_pattern 中使用相应的正则表达式模式:

# pip install pyjanitor
import pandas as pd
import janitor

df.pivot_longer(index = 'shot', 
                names_to = ('V0e', 'V0n', 'Vd'), 
                names_pattern = ('e$', 'n$', 'd$'),
                sort_by_appearance = True)

   shot       V0e        V0n     Vd
0  1001  530811.1  6764623.3     Vd
1  1001       NaN        NaN  S0_Pd
2  1002  530808.8  6764617.4     Vd
3  1002  530771.3  6764510.4  S0_Pd
4  1003  530806.6  6764611.4     Vd
5  1003       NaN        NaN  S0_Pd
6  1004  530804.2  6764605.8     Vd
7  1004  530765.6  6764499.1  S0_Pd