Building on this answer
I have two big dataframes (100K rows), df Assay has values, df Strat has 'Types'. I want to assign a 'Type' from Strat to a column in Assay based on depth. The depths are given as depth 'From' and depth 'To' columns. The 'types' are also defined by depth 'From' and 'To'. BUT they are NOT the same intervals. Assay depths may span multiple Strat types.
I want to assign the Strat 'types' to the Assay df, and if there are multiple types, try and capture that information too.
I want to loop over the data to populate the Type column for each HOLE_ID.
Generate example data:
import pandas as pd
import numpy as np
Assay=pd.DataFrame(np.array([['Hole_1',1.0,2.5,0.001],['Hole_1',2.5,5.0,0.005],['Hole_1',5.0,7.0,0.002],['Hole_1',7.0,10.0,0.001],['Hole_2',1.0,3.0,0.001],['Hole_2',3.0,5.0,0.005],['Hole_2',5.0,7.0,0.002],['Hole_2',7.0,10.0,0.001]]),columns=['HOLE_ID','FROM', 'TO', 'val'])
Strat=pd.DataFrame(np.array([['Hole_1',0.0,4.0,'A'],['Hole_1',4.0,5.0,'B'],['Hole_1',5.0,6.5,'C'],['Hole_1',6.5,8.0,'D'],['Hole_1',8.0,10.0,'E'],['Hole_2',0.0,4.0,'A'],['Hole_2',4.0,5.1,'B'],['Hole_2',5.1,6.0,'C'],['Hole_2',6.0,8.0,'D'],['Hole_2',8.0,10.0,'E']]),columns=['HOLE_ID','FROM', 'TO', 'Type'])
Assay
Out[1]:
HOLE_ID FROM TO val
0 Hole_1 1.0 2.5 0.001
1 Hole_1 2.5 5.0 0.005
2 Hole_1 5.0 7.0 0.002
3 Hole_1 7.0 10.0 0.001
4 Hole_2 1.0 3.0 0.001
5 Hole_2 3.0 5.0 0.005
6 Hole_2 5.0 7.0 0.002
7 Hole_2 7.0 10.0 0.001
Strat
Out[2]:
HOLE_ID FROM TO Type
0 Hole_1 0.0 4.0 A
1 Hole_1 4.0 5.0 B
2 Hole_1 5.0 6.5 C
3 Hole_1 6.5 8.0 D
4 Hole_1 8.0 10.0 E
5 Hole_2 0.0 4.0 A
6 Hole_2 4.0 5.1 B
7 Hole_2 5.1 6.0 C
8 Hole_2 6.0 8.0 D
9 Hole_2 8.0 10.0 E
Example of desired output:
HOLE_ID FROM TO val Type
0 Hole_1 1.0 2.5 0.001 A 100%
1 Hole_1 2.5 5 0.005 A 60%,B 44%
2 Hole_1 5.0 7.0 0.002 C 80%, D 20%
3 Hole_1 7.0 10.0 0.001 D 30%, E 70%
4 Hole_2 1.0 3.0 0.001 A 100%
5 Hole_2 3.0 5.0 0.005 A 50%, B50%
6 Hole_2 5.0 7.0 0.002 B 5%, C 45%, D 50%
7 Hole_2 7.0 10.0 0.001 D 30% E 70%
My attempt is below, but doesn't work. I am not very good at loops and I have had a few promising attempts but the code seemed to run forever (note, my actual dataset is ~100k rows and 1500 HOLE_ID's so may be quite demanding on my system).
I have added np.arange so that I can use floats (0.1 m increments to generate the auxiliary series) and I think I have the percentages calculating but I am a bit out of my depth.
A bit of pre-processing to make sure only matching hole IDs are used (real data is big, and also contains additional cols not included in the example data set.)
assay_Hole_IDs =Assay['HOLE_ID'].unique().tolist()
strat_Hole_IDS =Strat['HOLE_ID'].unique().tolist()
Strat=Strat[Strat['HOLE_ID'].isin(assay_Hole_IDs)]
Assay=Assay[Assay['HOLE_ID'].isin(assay_Hole_IDs)]
assay_Hole_IDs =Assay['HOLE_ID'].unique().tolist()
strat_Hole_IDS =Strat['HOLE_ID'].unique().tolist()
check that there are no additional values
j=set(assay_Hole_IDs).symmetric_difference(set(strat_Hole_IDS))
print len(j)
j
then:
all_holes= Strat['HOLE_ID'].unique().tolist()
def getType(row):
for hole in all_holes:
df=Strat.loc[Strat['HOLE_ID']==hole]
units = df.set_index('Type').apply(lambda row: pd.Series(
np.arange(row.FROM, row.TO,0.1)), axis=1).stack()\
.reset_index(level=1, drop=True)
gr = units[units.ge(row.FROM) & units.lt(row.TO)].groupby(level=0)
if gr.ngroups == 1:
return gr.ngroup().index[0]
txt = []
counts = []
pct=[]
for key, grp in gr:
siz = grp.size
un = 'unit' if siz == 1 else 'units'
counts.append(float(siz))
for x in counts:
p=(float(x)/float(sum(counts))*100)
pct.append(float(p))
return pct
then:
assay['Type'] = assay.groupby('HOLE_ID').apply(getType)
Can anyone see why this isn't working?