Векторизация функции для кадра данных Pandas GroupBy - PullRequest
0 голосов
/ 20 июня 2019

У меня есть кадр данных Pandas, отсортированный по столбцу datetime. Несколько строк будут иметь одинаковую дату и время, но значение столбца «тип отчета» будет другим. Мне нужно выбрать только одну из этих строк на основе списка предпочтительных типов отчетов. Список в порядке предпочтения. Таким образом, если одна из этих строк имеет первый элемент в списке, то это строка, выбранная для добавления в новый фрейм данных.

Я пробовал GroupBy и очень медленный цикл Python for для обработки каждой группы, чтобы найти предпочтительный тип отчета и добавить эту строку в новый фрейм данных. Я думал о numpy vectorize (), но я не знаю, как включить в него группу. Я действительно не очень разбираюсь в данных, но учусь. Любые идеи о том, как сделать это быстрее? Могу ли я зарегистрировать группу?

Пример кадра данных

OBSERVATIONTIME       REPTYPE   CIGFT
2000-01-01 00:00:00 AUTO    73300
2000-01-01 00:00:00 FM-15   25000
2000-01-01 00:00:00 FM-12   3000
2000-01-01 01:00:00 SAO 9000
2000-01-01 01:00:00 FM-16   600
2000-01-01 01:00:00 FM-15   5000
2000-01-01 01:00:00 AUTO    5000
2000-01-01 02:00:00 FM-12   12000
2000-01-01 02:00:00 FM-15   15000
2000-01-01 02:00:00 FM-16   8000
2000-01-01 03:00:00 SAO 700
2000-01-01 04:00:00 SAO 3000
2000-01-01 05:00:00 FM-16   5000
2000-01-01 06:00:00 AUTO    15000
2000-01-01 06:00:00 FM-12   12500
2000-01-01 06:00:00 FM-16   12000
2000-01-01 07:00:00 FM-15   20000

#################################################
# The function to loop through and find the row
################################################
    def select_the_one_ob(df):
    ''' select the preferred observation '''
    tophour_df = pd.DataFrame()
    preferred_order = ['FM-15', 'AUTO', 'SAO', 'FM-16', 'SAOSP', 'FM-12', 
'SY-MT', 'SY-SA']
    grouped = df.groupby("OBSERVATIONTIME", as_index=False)

    for name, group in grouped:
        a_group_df = pd.DataFrame(grouped.get_group(name))

        for reptype in preferred_order:
            preferred_found = False
            for i in a_group_df.index.values:
                if a_group_df.loc[i, 'REPTYPE'] == reptype:
                    tophour_df = 
tophour_df.append(a_group_df.loc[i].transpose())
                    preferred_found = True
                    break

            if preferred_found:
                break

        del a_group_df



    return tophour_df

################################################
### The function which calls the above function
################################################
def process_ceiling(plat, network):
    platformcig.data_pull(CONNECT_SRC, PULL_CEILING)
    data_df = platformcig.df

    data_df = select_the_one_ob(data_df)

При полном наборе данных в 300 000 строк функция занимает более 4 часов. Мне нужно, чтобы это было намного быстрее. Могу ли я включить группу с помощью функции numpy vectorize ()?

Ответы [ 2 ]

0 голосов
/ 02 июля 2019

Обнаружено, что создавая отдельный фрейм данных одинаковой формы, заполненный каждым часом времени наблюдения, я мог бы использовать команду pandas dataframe merge (), а после первого прохода использовать pandas dataframe comb_first (). Это заняло всего несколько минут вместо часов.

def select_the_one_ob (df): '' 'выберите предпочтительное наблюдение Параметры: df (объект Pandas), кадр данных Pandas

Returns Pandas Dataframe
'''
dshelldict = {'DateTime': pd.date_range(BEG_POR, END_POR, freq='H')}
dshell = pd.DataFrame(data = dshelldict)

dshell['YEAR'] = dshell['DateTime'].dt.year  
dshell['MONTH'] = dshell['DateTime'].dt.month
dshell['DAY'] = dshell['DateTime'].dt.day
dshell['HOUR'] = dshell['DateTime'].dt.hour
dshell = dshell.set_index(['YEAR','MONTH','DAY','HOUR'])
df = df.set_index(['YEAR','MONTH','DAY','HOUR'])

#tophour_df = pd.DataFrame()
preferred_order = ['FM-15', 'AUTO', 'SAO', 'FM-16', 'SAOSP', 'FM-12', 'SY-MT', 'SY-SA']
reptype_list = list(df.REPTYPE.unique())

# remove the preferred report types from the unique ones
for rep in preferred_order:
    if rep in reptype_list:
        reptype_list.remove(rep)

# If there are any unique report types left, append them to the preferred list
if len(reptype_list) > 0:
    preferred_order = preferred_order + reptype_list

## i is flag to make sure a report type is used to transfer columns to new DataFrame
## (Merge has to happen before combine first)
first_pass = True
for reptype in preferred_order:
    if first_pass:
        ## if there is data in dataframe
        if df[(df['MINUTE']==00)&(df['REPTYPE']==reptype)].shape[0]>0:
            first_pass = False
            # Merge shell with first df with data, the dataframe is sorted by original 
            # obstime and drop any dup's keeping first aka. first report chronologically
            tophour_df = dshell.merge( df[ (df['MINUTE']==00)&(df['REPTYPE']==reptype) ].sort_values(['OBSERVATIONTIME'],ascending=True).drop_duplicates(subset=['ROLLED_OBSERVATIONTIME'],keep='first'),how ='left',left_index = True,right_index=True ).drop('DateTime',axis=1)
    else:
        # combine_first takes the original dataframe and fills any nan values with data 
        # of another identical shape dataframe
        # ex. if value df.loc[2,col1] is nan df2.loc[2,col1] would fill it if not nan
        tophour_df = tophour_df.combine_first(df[(df['MINUTE']==00)&(df['REPTYPE']==reptype)].sort_values(['OBSERVATIONTIME'],ascending=True).drop_duplicates(subset=['ROLLED_OBSERVATIONTIME'],keep='first'))

tophour_df = tophour_df.reset_index()

return tophour_df

выделенный текст

0 голосов
/ 20 июня 2019

Вы можете избежать использования groupby.Одним из способов может быть классификация столбца REPTYPE с помощью pd.Categorical, а затем sort_values и drop_duplicates, например:

def select_the_one_ob(df):
    preferred_order = ['FM-15', 'AUTO', 'SAO', 'FM-16', 'SAOSP', 'FM-12', 'SY-MT', 'SY-SA']
    df.REPTYPE = pd.Categorical(df.REPTYPE, categories=preferred_order, ordered=True)
    return (df.sort_values(by=['OBSERVATIONTIME','REPTYPE'])
              .drop_duplicates(subset='OBSERVATIONTIME', keep='first'))

и вы получите с вашим примером:

       OBSERVATIONTIME REPTYPE  CIGFT
1  2000-01-01 00:00:00   FM-15  25000
5  2000-01-01 01:00:00   FM-15   5000
8  2000-01-01 02:00:00   FM-15  15000
10 2000-01-01 03:00:00     SAO    700
11 2000-01-01 04:00:00     SAO   3000
12 2000-01-01 05:00:00   FM-16   5000
13 2000-01-01 06:00:00    AUTO  15000
16 2000-01-01 07:00:00   FM-15  20000
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...