我有一个巨大的数据框,其中包含product_id及其property_id。请注意,对于每个属性,都以新索引开头。我需要同时针对每个product_id按不同的property_id值进行过滤。有什么办法可以快速做到吗?
out_df
product_id property_id
0 3588 1
1 3588 2
2 3588 5
3 3589 1
4 3589 3
5 3589 5
6 3590 1
7 3590 2
8 3590 5
例如,想要通过每个属性(例如out_df.loc[(out_df['property_id'] == 1) & (out_df['property_id'] == 2)]
分配给不同行的两个属性来过滤每个product_id的方法)。
我需要类似的东西,但同时要为每个product_id列的所有行工作。
我知道可以通过groupby
进入列表
3587 [2, 1, 5]
3588 [1, 3, 5]
3590 [1, 2, 5]
并在列表中查找交集。
gp_df.apply(lambda r: {1, 2} < (set(r['property_id'])), axis=1)
但是这需要花费时间,同时Pandas的通用过滤已为速度进行了极大的优化(请相信在ElasticSearch,Sphinx等搜索引擎内部使用一些棘手的向右和反向索引)。
预期的输出:{1和2}都在其中。
3587 [2, 1, 5]
3590 [1, 2, 5]
答案 0 :(得分:1)
你的意思是这样吗?
Private Sub find_occurance(ByVal Country As String)
Dim next_free_row As Long
For Each Cell In Sheets("Sheet1").ListObjects("Table1").ListColumns(2).DataBodyRange
If Trim(LCase(Cell.Value2)) = Trim(LCase(Country)) Then
next_free_row = Sheets("Sheet2").Cells(Rows.Count, 1).End(xlUp).Row + 1
Sheets("Sheet2").Cells(next_free_row, "A") = Cell.Offset(0, -1).Value2
Sheets("Sheet2").Cells(next_free_row, "B") = Cell.Value2
End If
Next Cell
End Sub
如果需要,您可以根据product_id删除重复项...
答案 1 :(得分:1)
最简单的方法是将GroupBy.transform
与比较集一起使用:
s = {1, 2}
a = df[df.groupby('product_id')['property_id'].transform(lambda r: s < set(r))]
print (a)
product_id property_id
0 3588 1
1 3588 2
2 3588 5
6 3590 1
7 3590 2
8 3590 5
另一种解决方案是仅过滤集合的值,首先删除重复项:
df1 = df[df['property_id'].isin(s) & ~df.duplicated(['product_id', 'property_id'])]
然后需要检查每个组的长度是否与this solution设置的长度相同:
f, u = df1['product_id'].factorize()
ids = df1.loc[np.bincount(f)[f] == len(s), 'product_id'].unique()
根据条件最后过滤带有product_id
的所有行
a = df[df['product_id'].isin(ids)]
print (a)
product_id property_id
0 3588 1
1 3588 2
2 3588 5
6 3590 1
7 3590 2
8 3590 5
答案 2 :(得分:1)
由于这与功能性问题一样具有性能,因此我将采用这样的交叉方法:
df = pd.DataFrame({'product_id': [3588, 3588, 3588, 3589, 3589, 3589, 3590, 3590,3590],
'property_id': [1, 2, 5, 1, 3, 5, 1, 2, 5]})
df = df.set_index(['property_id'])
print("The full DataFrame:")
print(df)
start = time()
for i in range(1000):
s1 = df.loc[(1), 'product_id']
s2 = df.loc[(2), 'product_id']
s_done = pd.Series(list(set(s1).intersection(set(s2))))
print("Overlapping product_id's")
print(time()-start)
在ThinkPad T450上迭代查找1000次需要 0.93秒。我冒昧地测试了@jezrael的两个建议,它们分别在2.11和2.00秒时出现,groupby的方法在软件工程上是明智的,但是更优雅。
根据数据集的大小和性能的重要性,您还可以切换到更简单的数据类型,例如经典字典,以提高速度。
Jupyter笔记本可以在这里找到:pandas_fast_lookup_using_intersection.ipynb