Объедините два фрейма данных с перекрывающимися диапазонами и рассчитайте перекрытие, сгруппированное по категориям - PullRequest
2 голосов
/ 28 октября 2019

Опираясь на этот ответ
У меня есть два больших фрейма данных (100K строк), у df Assay есть значения, у df Strat есть 'Types'. Я хочу назначить «Тип» из Strat для столбца в Assay на основе глубины. Глубины указаны в столбцах «От» и «До». «Типы» также определяются глубиной «От» и «До». НО они НЕ одинаковые интервалы. Глубина анализа может охватывать несколько типов Strat.

Я хочу назначить Strat 'типы' для Assay df, и, если существует несколько типов, попробуйте также захватить эту информацию.

Я хочуцикл по данным, чтобы заполнить столбец Тип для каждого HOLE_ID.

Создать пример данных:

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

Пример желаемого результата:

  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%

Моя попытка приведена ниже, но не работает. Я не очень хорош в циклах, и у меня было несколько многообещающих попыток, но казалось, что код работает вечно (обратите внимание, мой фактический набор данных составляет ~ 100 тыс. Строк и 1500 HOLE_ID, поэтому может быть довольно требовательным в моей системе).

Я добавил np.arange, чтобы я мог использовать поплавки (с шагом 0,1 м для генерации вспомогательных рядов), и я думаю, что у меня есть проценты для расчета, но я немного не в своей глубине.

Немного предварительной обработки, чтобы убедиться, что используются только совпадающие идентификаторы отверстий (реальные данные большие, а также содержат дополнительные столбцы, не включенные в примерный набор данных.)

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()

убедитесь, что нет дополнительных значений


j=set(assay_Hole_IDs).symmetric_difference(set(strat_Hole_IDS))
print len(j)
j

, затем:

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

затем:

assay['Type'] = assay.groupby('HOLE_ID').apply(getType)

Кто-нибудь может понять, почему это не работает?

1 Ответ

1 голос
/ 28 октября 2019
def group(df1):
    df2 = Strat[Strat['HOLE_ID']==df1.iloc[0]['HOLE_ID']]
    df1[['FROM','TO']] = df1[['FROM','TO']].astype(float)
    df2[['FROM','TO']] = df2[['FROM','TO']].astype(float)

    temp =  pd.concat([df1[['FROM','TO']],df2[['FROM','TO']]]).unstack().reset_index(drop=True) \
              .drop_duplicates().sort_values().reset_index(drop=True) \
              .to_frame(name='FROM').merge(df2, how='outer').ffill()
   temp['TO'] = temp.shift(-1)['FROM']


    def tobins(x):
        agg = temp[(x.FROM <= temp.FROM) & (temp.FROM < x.TO)].groupby('Type') \
                .apply(lambda y: y['TO'].max() - y['FROM'].min()).reset_index(name='res')
        agg.res = agg.Type + ' ' + (agg.res/agg.res.sum()).map('{:.0%}'.format)
        return '; '.join(agg.res.tolist())

    df1['Type'] = df1.apply(tobins,axis=1)
    return df1

Assay.groupby('HOLE_ID').apply(group)

  HOLE_ID  FROM    TO    val          Type
0  Hole_1   1.0   2.5  0.001        A 100%
1  Hole_1   2.5   5.0  0.005  A 60%; B 40%
2  Hole_1   5.0   7.0  0.002  C 75%; D 25%
3  Hole_1   7.0  10.0  0.001  D 33%; E 67%
4  Hole_2   1.0   3.0  0.001        A 100%
5  Hole_2   3.0   5.0  0.005        B 100%
6  Hole_2   5.0   7.0  0.002  C 75%; D 25%
7  Hole_2   7.0  10.0  0.001  D 33%; E 67%

Ключевым моментом является построение временного DataFrame со всеми точками FROM и TO из обеих таблиц. Для HOLE_ID = 'Hole_1' это выглядит так, как показано ниже. Теперь мы можем получить для каждой строки Assay (x) эти строки временной таблицы с (x.FROM <= temp.FROM < x.TO), сгруппировать их по типу, вычислить доли и объединить в формат результата

   FROM HOLE_ID    TO Type
0   0.0  Hole_1   1.0    A
1   1.0  Hole_1   2.5    A
2   2.5  Hole_1   4.0    A
3   4.0  Hole_1   5.0    B
4   5.0  Hole_1   6.5    C
5   6.5  Hole_1   7.0    D
6   7.0  Hole_1   8.0    D
7   8.0  Hole_1  10.0    E
8  10.0  Hole_1   NaN    E
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...