Python 外/内环组之间成对比较的双熊猫分组操作
我正试着做一个有点复杂的分组操作。下面是一些功能性但速度较慢的代码Python 外/内环组之间成对比较的双熊猫分组操作,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,我正试着做一个有点复杂的分组操作。下面是一些功能性但速度较慢的代码 #构建一个玩具数据框 idx1=[“bar”、“baz”、“foo”] idx2=列表(范围(100104)) idx3=列表(范围(3)) num_data=len(idx1)*len(idx2)*len(idx3) index=pd.MultiIndex.from_乘积((idx1,idx2,idx3),name=[“第一”,“第三”,“第四”]) np.random.seed(0) x=np.random.randint(
#构建一个玩具数据框
idx1=[“bar”、“baz”、“foo”]
idx2=列表(范围(100104))
idx3=列表(范围(3))
num_data=len(idx1)*len(idx2)*len(idx3)
index=pd.MultiIndex.from_乘积((idx1,idx2,idx3),name=[“第一”,“第三”,“第四”])
np.random.seed(0)
x=np.random.randint(低=0,高=2,大小=num\u数据,数据类型=bool)
input_df=pd.DataFrame(index=index,data={“x”:x}).reset_index()
输入_df[“秒”]=“正”
输入测向[“第二”][输入测向[“第三”!=100]=“负”
输入测向[“第三”][输入测向[“第三”]==101]=100
#并发症:并非所有按“第四”分组的组都有相同的指数。大多数索引将由Most共享
#“第四”组,但交叉点不完整。
掩码=np.ones(num_数据,dtype=bool)
掩码[[17,18]]=False
input_df=input_df[掩码]
input_df=input_df.设置索引([“第一”、“第二”、“第三”、“第四”])
input_df
如下所示:
x
first second third fourth
bar positive 100 0 False
1 False
2 True
negative 100 0 True
1 False
2 True
102 0 False
1 True
2 False
103 0 True
1 False
2 True
baz positive 100 0 False
1 False
2 False
negative 100 0 False # Notice some missing rows here
1 True
102 1 True
2 True
103 0 True
1 True
2 False
foo positive 100 0 False
1 False
2 True
negative 100 0 True
1 False
2 False
102 0 False
1 True
2 True
103 0 True
1 True
2 True
数据帧保证/属性:
- 在每个“第一组”中,总有一个积极的“第三组”
- 每个“第一组”中有N个(可变)负“第三组”
- 对于每个“第一”组:
- 将所有负“第三”组与单个正“第三”组进行比较(参见代码了解“比较”的含义)
dfs=[]
#对于每个“第一”组:
对于first,input_df.groupby中的first_df(“first”):
#将阳性组和阴性组分开
正掩码=第一个索引。获取级别值(“第二个”)=“正”
first_df=first_df.液滴液位([“first”])
正折射率=第一折射率[正折射率]
负的_dfs=第一个_df[~正的_掩码]
正测向=正测向液滴液位([“第二”、“第三”])
#对每个负“第三”组及其对应的正组进行一些计算。
对于第三个,负dfs.groupby中的负df(“第三个”):
负折射率=负折射率液滴水平([“第二”、“第三”])
#仅根据“第四”指数比较阳性/阴性组
#请注意,对于不在交点处的索引,将指定“False”。
真=负方向[“x”]和正方向[“x”]
真假=负方向[“x”]&正方向[“x”]
false\u false=~负的\u df[“x”]&正的\u df[“x”]
false\u true=~负的\u df[“x”]和正的\u df[“x”]
df=pd.DataFrame({
“真的”:真的,
“真假”:真假,
“假假”:假假假,
“false\u true”:false\u true
}).reset_index()
df[“第一”]=第一
df[“秒”]=“负”
df[“第三”]=第三
dfs.append(df)
#输出:所有负“第三”组的计算值的大数据帧。
输出_df=pd.concat(dfs)
output_df=output_df.设置索引([“第一”、“第二”、“第三”、“第四”],验证完整性=真)。排序索引()
这意味着,output\u df
如下所示。请注意,在原始数据帧中缺少“第四个”索引的地方,所有行都为false
true_true true_false false_false false_true
first second third fourth
bar negative 100 0 False True False False
1 False False True False
2 True False False False
102 0 False False True False
1 False True False False
2 False False False True
103 0 False True False False
1 False False True False
2 True False False False
baz negative 100 0 False False True False
1 False True False False
2 False False False False # All false from missing data
102 0 False False False False # All false from missing data
1 False True False False
2 False True False False
103 0 False True False False
1 False True False False
2 False False True False
foo negative 100 0 False True False False
1 False False True False
2 False False False True
102 0 False False True False
1 False True False False
2 True False False False
103 0 False True False False
1 False True False False
2 True False False False
在循环中执行此操作的速度非常慢:(不仅是循环本身,而且分析显示,由于索引必须对齐,因此在执行内部循环比较操作时花费了大量时间
有没有一种更有效的方法来执行这种计算,也许不需要太多的循环
编辑:为确定性示例数据和更新的输入/输出数据添加随机种子。您可以尝试此方法,但不确定是否更有效:
dfi = input_df['x'].unstack(level=['second','fourth'])
dfi.update(dfi.groupby('first').ffill()[['positive']])
dfi = dfi.stack()
neg_nulls = dfi['negative'].isna()
pos_nulls = dfi['positive'].isna()
dfi = dfi.fillna(False)
dfi['true_true'] = dfi["negative"] & dfi["positive"]
dfi['true_false'] = dfi["negative"] & ~dfi["positive"]
dfi['false_false'] = ~dfi["negative"] & ~dfi["positive"]
dfi['false_true'] = ~dfi["negative"] & dfi["positive"]
dfi[neg_nulls] = False
dfi[pos_nulls] = False
df_out = dfi.rename_axis([None], axis=1)\
.assign(second='negative')\
.set_index('second', append=True)\
.reorder_levels([0,3,1,2])\
.drop(['positive', 'negative'], axis=1)
带计时的输出(使用np.random.seed(0)更新):
计时
每个回路21.8 ms±549µs(7次运行的平均值±标准偏差,每个10个回路)每个回路50.2 ms±2.91 ms(7次运行的平均值±标准偏差,每个10个回路) 细节
- 重新调整输入数据框的形状,使正片和负片并排 “第四”
- 每“三分之一”填写正向数据并更新数据帧
- 重塑形状,堆叠“四分之一”,使其旁边有一列正值 底片
- 应用真-真…假-假逻辑
- 为缺失的负片和正片设置所有FALSE
- 重塑以获得所需的输出数据帧
(无循环,但对数据帧进行了相当大的重塑)请在共享数据中添加一个
np.random.seed(一些数字)
,以便reproducible@sammywemmy谢谢,很好的建议,Doneth这真的很重要;-)@cydonian这个解决方案对你有帮助吗?你的数据运行速度快了一倍吗?@ScottBoston还在计算。我可能需要更新问题-在我的真实数据中,“第四个”索引只在每个“第一个”组中匹配,因此第一步拆下数据框会给出O(N_firsts)列。我将看看是否可以修改您的答案并发布结果。@ScottBoston此答案对于我提出的问题非常适合,因此选择正确。还有一些额外的输入数据特征使得这个答案不适用于我的特定用例,即每个“第一”组从不同的集合中提取其“第三”和“第四”索引。我试图找出一种方法来适应你的答案,但是,唉,我是个笨蛋。我想重新问修改过的问题会更干净,我在这里做过:
true_true true_false false_false false_true
first second third fourth
bar negative 100 0 False True False False
1 False False True False
2 True False False False
102 0 False False True False
1 False True False False
2 False False False True
103 0 False True False False
1 False False True False
2 True False False False
baz negative 100 0 False False True False
1 False True False False
2 False False False False
102 0 False False False False
1 False True False False
2 False True False False
103 0 False True False False
1 False True False False
2 False False True False
foo negative 100 0 False True False False
1 False False True False
2 False False False True
102 0 False False True False
1 False True False False
2 True False False False
103 0 False True False False
1 False True False False
2 True False False False
all(df_out==output_df)
True