在 Pandas DataFrame 中构建复杂的子集
Building complex subsets in Pandas DataFrame
我正在努力 GroupBy
,但我仍然需要一些帮助。假设我有一个包含列 Group
的 DataFrame,提供对象组编号、一些参数 R
和球坐标 RA
和 Dec
。这是一个模拟数据框:
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)
})
我想为每个组构建一个包含 "brightest" 对象的选择,即具有最小 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))
给出,RA1
作为第一个对象的 RA
,依此类推。
我不知道如何使用 GroupBy
来实现这个...
您在这里可以做的是构建一个更具体的辅助函数,应用于每个 "sub-frame"(每个组)。
GroupBy
实际上只是一个工具,它创建类似于 (group id, DataFrame) 对的迭代器,并且当你打电话给 .groupby().apply
。 (这掩盖了很多细节,如果您有兴趣,请参阅 here 了解一些内部细节。)
所以在定义了三个基于 NumPy 的函数之后,还要定义:
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]
然后只需申请,您就会得到一个 MultiIndex DataFrame,其中第一个索引级别是组。
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
穿插一些评论:
def sep_df(df, keep=3):
# Applied to each sub-Dataframe (this is what GroupBy does under the hood)
# Get RA and Dec values at minimum R
min_r = df.loc[df.R.argmin()] # Series - row at which R is minimum
RA1, Dec1 = min_r.RA, min_r.Dec # Relevant 2 scalars within this row
# Calculate separation for each pair including minimum R row
# The result is a series of separations, same length as `df`
sep = r2d(calc_sep(RA1,Dec1,df['RA'], df['Dec']))
# Get index values of `keep` (default 3) smallest results
# Retain `keep+1` values because one will be the minimum R
# row where separation=0
idx = sep.nsmallest(keep+1).index
# Restrict the result to those 3 index labels + your minimum R
return df.loc[idx]
为了提高速度,consider passing sort=False
如果结果仍然适合您,请使用 GroupBy。
I want to built a selection containing for each group the "brightest" object...and the 3 closest objects of the group
第 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
我正在努力 GroupBy
,但我仍然需要一些帮助。假设我有一个包含列 Group
的 DataFrame,提供对象组编号、一些参数 R
和球坐标 RA
和 Dec
。这是一个模拟数据框:
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)
})
我想为每个组构建一个包含 "brightest" 对象的选择,即具有最小 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))
给出,RA1
作为第一个对象的 RA
,依此类推。
我不知道如何使用 GroupBy
来实现这个...
您在这里可以做的是构建一个更具体的辅助函数,应用于每个 "sub-frame"(每个组)。
GroupBy
实际上只是一个工具,它创建类似于 (group id, DataFrame) 对的迭代器,并且当你打电话给 .groupby().apply
。 (这掩盖了很多细节,如果您有兴趣,请参阅 here 了解一些内部细节。)
所以在定义了三个基于 NumPy 的函数之后,还要定义:
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]
然后只需申请,您就会得到一个 MultiIndex DataFrame,其中第一个索引级别是组。
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
穿插一些评论:
def sep_df(df, keep=3):
# Applied to each sub-Dataframe (this is what GroupBy does under the hood)
# Get RA and Dec values at minimum R
min_r = df.loc[df.R.argmin()] # Series - row at which R is minimum
RA1, Dec1 = min_r.RA, min_r.Dec # Relevant 2 scalars within this row
# Calculate separation for each pair including minimum R row
# The result is a series of separations, same length as `df`
sep = r2d(calc_sep(RA1,Dec1,df['RA'], df['Dec']))
# Get index values of `keep` (default 3) smallest results
# Retain `keep+1` values because one will be the minimum R
# row where separation=0
idx = sep.nsmallest(keep+1).index
# Restrict the result to those 3 index labels + your minimum R
return df.loc[idx]
为了提高速度,consider passing sort=False
如果结果仍然适合您,请使用 GroupBy。
I want to built a selection containing for each group the "brightest" object...and the 3 closest objects of the group
第 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