Расширение ранжирования столбца в Pandas - PullRequest
1 голос
/ 11 июля 2020

Рассмотрим пример DF:

df = pd.DataFrame(np.random.randint(0,60,size=(10,3)),columns=["a","b","c"])
df["d1"]=["Apple","Mango","Apple","Apple","Mango","Mango","Apple","Mango","Apple","Apple"]
df["d2"]=["Orange","lemon","lemon","Orange","lemon","Orange","lemon","Orange","lemon","Orange"]
df["date"] = ["2002-01-01","2002-01-01","2002-01-01","2002-01-01","2002-02-01","2002-02-01","2002-02-01"]
df["date"] = pd.to_datetime(df["date"])
df

    a   b   c     d1       d2    date
0   7   1   19  Apple   Orange  2002-01-01
1   3   7   17  Mango   lemon   2002-01-01
2   9   6   4   Apple   lemon   2002-01-01
3   0   5   51  Pine    Orange  2002-01-01
4   4   6   8   Apple   lemon   2002-02-01
5   4   3   1   Mango   Orange  2002-02-01
6   2   2   14  Apple   lemon   2002-02-01
7   5   15  10  Mango   Orange  2002-01-01
8   1   2   10  Pine    lemon   2002-02-01
9   2   1   12  Apple   Orange  2002-02-01

Попытка заменить столбец d1 рангом на основе Группировать по столбцу d1 и mean столбца c в расширяющемся порядке. Например, рассмотрим следующие первые 5 строк:

  1. Первая строка по умолчанию значение индекса 0, т.е. Apple будет заменено на 0

  2. Вторая строка, индекс 1, значение Mango следует заменить на 0, потому что с учетом только первых 2 строк DF GROUPED_MEAN для Apple будет 19 и Mango будет 17, поэтому значение Man go в индексе 1 следует заменить на ранг 0, так как оно имеет более низкое сгруппированное среднее.

  3. Третья строка, индекс 2, значение Apple следует заменить на 0, потому что с учетом только первых 3 строк DF GROUPED_MEAN для Apple будет (19+4)/2, а Mango будет 17, поэтому значение Apple с индексом 2 следует заменить на rank 0, поскольку оно имеет более низкое сгруппированное среднее

  4. Четвертая строка, индекс 3, значение Pine следует заменить на 2, потому что с учетом только первых 4 строк DF GROUPED_MEAN для Apple будет (19+4)/2, а Mango будет 17, Pine w будет 51, так как сосна имеет наивысшее сгруппированное среднее из всех 3 категорий - [Apple, Mango, Pine], сосне будет присвоен ранг 2.

  5. Пятая строка, индекс 4, значение Apple следует заменить на 0, потому что с учетом только первых 5 строк DF GROUPED_MEAN для Apple будет (19+4+8)/3, а Mango будет 17, Pine будет 51, поскольку Apple имеет самое низкое сгруппированное среднее из всех 3 - Apple, Mango, Pine, Apple будет присвоен ранг 0.

Ожидаемое значение столбца d1:

0
0
0
2
0
0
1
0
2
1

Итерационный подход:

def expanding(data,cols):

    copy_df = data.copy(deep=True)
    for i in range(len(copy_df)):
       if i==0:
          copy_df.loc[i,cols]=0
       else:
          op = group_processor(data[:i+1],cols,i)
          copy_df.loc[i,cols]=op
    return copy_df

def group_processor(cut_df,cols,i):

    op=[]
    for each_col in cols:
       temp = cut_df.pivot_table("c",[each_col]).rank(method="dense")-1
       value = cut_df.loc[i,each_col]
       temp = temp.reset_index()
       final_value = temp.loc[temp[each_col]==value,"c"]
       op.append(final_value.values[0])

    return op

expanding(df,["d1"])

Я могу делать это итеративно через каждую строку DF, но производительность плохая для больших DF, поэтому любые предложения по подходу, основанному на более pandas, будут отличными. *

1 Ответ

1 голос
/ 11 июля 2020

Используйте Series.expanding с минимальным размером окна 1 в столбце c и используйте настраиваемую лямбда-функцию exp. В этой лямбда-функции мы используем Series.groupby, чтобы сгруппировать расширяющееся окно w по столбцу d1 в исходном фрейме данных и transform используя mean, наконец используя Series.rank с method='dense' вычисляем ранг:

exp = lambda w: w.groupby(df['d1']).transform('mean').rank(method='dense').iat[-1]
df['d1_new'] = df['c'].expanding(1).apply(exp).sub(1).astype(int)

Результат:

# print(df)

   a   b   c     d1      d2        date  d1_new
0  7   1  19  Apple  Orange  2002-01-01       0
1  3   7  17  Mango   lemon  2002-01-01       0
2  9   6   4  Apple   lemon  2002-01-01       0
3  0   5  51   Pine  Orange  2002-01-01       2
4  4   6   8  Apple   lemon  2002-02-01       0
5  4   3   1  Mango  Orange  2002-02-01       0
6  2   2  14  Apple   lemon  2002-02-01       1
7  5  15  10  Mango  Orange  2002-01-01       0
8  1   2  10   Pine   lemon  2002-02-01       2
9  2   1  12  Apple  Orange  2002-02-01       1

Производительность:

df.shape
(1000, 7)

%%timeit
exp = lambda w: w.groupby(df['d1']).transform('mean').rank(method='dense').iat[-1]
df['d1_new'] = df['c'].expanding(1).apply(exp).sub(1).astype(int)
3.15 s ± 305 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%%timeit
expanding(df,["d1"]) # your method
11.9 s ± 449 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...