在Pandas DataFrame中构建复杂的子集

时间:2017-09-19 14:07:21

标签: python pandas dataframe pandas-groupby split-apply-combine

我正在绕过GroupBy,但我仍需要一些帮助。假设我有一个包含Group列的DataFrame,给出了对象组号,一些参数R和球面坐标RADec。这是一个模拟DataFrame:

df = pd.DataFrame({ 
    'R'    : (-21.0,-21.5,-22.1,-23.7,-23.8,-20.4,-21.8,-19.3,-22.5,-24.7,-19.9),
    'RA': (154.362789,154.409301,154.419191,154.474165,154.424842,162.568516,8.355454,8.346812,8.728223,8.759622,8.799796),
    'Dec': (-0.495605,-0.453085,-0.481657,-0.614827,-0.584243,8.214719,8.355454,8.346812,8.728223,8.759622,8.799796),
    'Group': (1,1,1,1,1,2,2,2,2,2,2) 
})

我想构建一个包含每个组的“最亮”对象的选择,即具有最小R(或绝对值最大,因为R为负)的对象,以及最接近的3对象组的对象(所以我在每组中保留4个对象 - 我们可以假设如果需要,没有小于4个对象的组)。

我们在此假设我们已经定义了以下函数:

#deg to rad
def d2r(x):
    return x * np.pi / 180.0

#rad to deg
def r2d(x):
    return x * 180.0 / np.pi

#Computes separation on a sphere
def calc_sep(phi1,theta1,phi2,theta2):
    return np.arccos(np.sin(theta1)*np.sin(theta2) + 
                     np.cos(theta1)*np.cos(theta2)*np.cos(phi2 - phi1) )

并且r2d(calc_sep(RA1,Dec1,RA2,Dec2))给出了两个对象之间的分隔,第一个对象的RA1RA,依此类推。

我无法弄清楚如何使用GroupBy来实现这一目标......

2 个答案:

答案 0 :(得分:2)

你可以在这里做的是构建一个更具体的辅助函数,它应用于每个“子框架”(每个组)。

GroupBy实际上只是一个创建类似于( group id ,DataFrame)对的迭代器的工具,当你调用{{1}时,会对每个对象应用一个函数}}。 (关于很多细节的釉面,如果您有兴趣,请参阅here了解内部细节的一些细节。)

因此,在定义了三个基于NumPy的函数之后,还要定义:

.groupby().apply

然后只需应用并获得一个MultiIndex DataFrame,其中第一个索引级别是组。

def sep_df(df, keep=3):
    min_r = df.loc[df.R.argmin()]
    RA1, Dec1 = min_r.RA, min_r.Dec
    sep = r2d(calc_sep(RA1,Dec1,df['RA'], df['Dec']))
    idx = sep.nsmallest(keep+1).index
    return df.loc[idx]

点缀了一些评论:

print(df.groupby('Group').apply(sep_df))
              Dec  Group     R         RA
Group                                    
1     3  -0.61483      1 -23.7  154.47416
      2  -0.48166      1 -22.1  154.41919
      0  -0.49561      1 -21.0  154.36279
      4  -0.58424      1 -23.8  154.42484
2     8   8.72822      2 -22.5    8.72822
      10  8.79980      2 -19.9    8.79980
      6   8.35545      2 -21.8    8.35545
      9   8.75962      2 -24.7    8.75962

如果结果仍适用于你,速度为consider passing sort=False到GroupBy。

答案 1 :(得分:2)

  

我想构建一个包含每个组的选项"最明亮的"对象...和组中最近的3个对象

第1步:

为每个组中最亮的对象创建一个数据框

maxR = df.sort_values('R').groupby('Group')['Group', 'Dec', 'RA'].head(1)

第2步:

合并Group上的两个框架&计算分离

merged = df.merge(maxR, on = 'Group', suffixes=['', '_max'])
merged['sep'] = merged.apply(
    lambda x: r2d(calc_sep(x.RA, x.Dec, x.RA_max, x.Dec_max)), 
    axis=1
)

第3步:

订购数据框,按'Group'分组,(可选)丢弃中间字段&从每组中取出前4行

finaldf = merged.sort_values(['Group', 'sep'], ascending=[1,1]
).groupby('Group')[df.columns].head(4)

使用您的样本数据生成以下数据框:

         Dec  Group     R          RA
4  -0.584243      1 -23.8  154.424842
3  -0.614827      1 -23.7  154.474165
2  -0.481657      1 -22.1  154.419191
0  -0.495605      1 -21.0  154.362789
9   8.759622      2 -24.7    8.759622
8   8.728223      2 -22.5    8.728223
10  8.799796      2 -19.9    8.799796
6   8.355454      2 -21.8    8.355454