Nano Hash - криптовалюты, майнинг, программирование

Pandas - сгруппируйте по мультииндексному уровню, получите возможные комбинации, а затем преобразуйте данные

Я боролся с проблемой группировки, комбинаций и преобразования. Мое текущее решение:

df = df.groupby(level='lvl_2').transform(lambda x: x[0]/x[1])

Но это не решает некоторые части моих проблем.

Предполагая код ниже:

import pandas as pd
import numpy as np
import datetime
today = datetime.date.today()
today_1 = datetime.date.today() - datetime.timedelta(1)
today_2 = datetime.date.today() - datetime.timedelta(2)
ticker_date = [('first', 'a',today), ('first', 'a',today_1), ('first', 'a',today_2),
               ('first', 'c',today), ('first', 'c',today_1), ('first', 'c',today_2),
               ('first', 'b',today), ('first', 'b',today_1), ('first', 'b',today_2),
               ('first', 'd',today), ('first', 'd',today_1), ('first', 'd',today_2)]
index_df = pd.MultiIndex.from_tuples(ticker_date,names=['lvl_1','lvl_2','lvl_3'])
df = pd.DataFrame(np.random.rand(12), index_df, ['idx'])

Результат:

                          idx
lvl_1 lvl_2 lvl_3               
first a     2018-02-14  0.421075
            2018-02-13  0.278418
            2018-02-12  0.117888
      c     2018-02-14  0.716823
            2018-02-13  0.241261
            2018-02-12  0.772491
      b     2018-02-14  0.681738
            2018-02-13  0.636927
            2018-02-12  0.668964
      d     2018-02-14  0.770797
            2018-02-13  0.11469
            2018-02-12  0.877965

Мне нужно следующее:

  1. Получите новый мультииндексный фрейм данных с возможными комбинациями элементов lvl_2.
  2. Преобразуйте мои данные, чтобы получить соотношение каждого элемента

Вот иллюстрация:

Здесь я создал «новый» столбец.

                                new
lvl_1   lvl_2       lvl_3   
first   a/c     2018-02-14  0.587418372
                2018-02-13  1.154011631
                2018-02-12  0.152607603
        a/b     2018-02-14  0.617649302
                2018-02-13  0.437127018
                2018-02-12  0.17622473
        a/d     2018-02-14  0.546285209
                2018-02-13  2.427569971
                2018-02-12  0.134274145
        c/b     2018-02-14  1.051464052
                2018-02-13  0.378789092
                2018-02-12  1.154757207
        c/d     2018-02-14  0.929976375
                2018-02-13  2.103592292
                2018-02-12  0.87986537
        b/d     2018-02-14  0.884458554
                2018-02-13  5.553465865
                2018-02-12  0.761948369

Чтобы дополнительно объяснить:

                                    new
    lvl_1   lvl_2       lvl_3   
    first   a/c     2018-02-14  0.587418372
                    2018-02-13  1.154011631
                    2018-02-12  0.152607603

Здесь я делаю соотношение элементов a с c:

0.587418 = 0.421075/0.716823
1.154012 = 0.278418/0.241261
0.152608 = 0.117888/0.772491

Я пробовал метод группировки и преобразования, например:

df = df.groupby(level='lvl_2').transform(lambda x: x[0]/x[1])

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

Я чувствую, что нахожусь на правильном пути, но чувствую, что застрял.


  • PS. в следующий раз укажите случайное начальное число (np.random.seed = x), чтобы мы все могли работать с одними и теми же данными и сравнивать результаты. 14.02.2018
  • спасибо @jezrael за указание, что это должно быть np.randome.seed(x) 14.02.2018
  • Верно! Не думал об этом. Спасибо за указание 14.02.2018

Ответы:


1

Если для первого уровня используются такие же комбинации других уровней, как в примере, можно использовать reindex на MultiIndex в столбцах с div:

#same as Maarten Fabré answer
np.random.seed(42)

from  itertools import combinations

#get combination of second level values
c = pd.MultiIndex.from_tuples(list(combinations(df.index.levels[1], 2)))

#reshape to unique columns of second level
print (df['idx'].unstack(1))
lvl_2                    a         b         c         d
lvl_1 lvl_3                                             
first 2018-02-12  0.731994  0.601115  0.155995  0.969910
      2018-02-13  0.950714  0.866176  0.156019  0.020584
      2018-02-14  0.374540  0.058084  0.598658  0.708073

#reindex by both levels
df1 = df['idx'].unstack(1).reindex(columns=c, level=0)
print (df1)
                         a                             b                   c
                         b         c         d         c         d         d
lvl_1 lvl_3                                                                 
first 2018-02-12  0.731994  0.731994  0.731994  0.601115  0.601115  0.155995
      2018-02-13  0.950714  0.950714  0.950714  0.866176  0.866176  0.156019
      2018-02-14  0.374540  0.374540  0.374540  0.058084  0.058084  0.598658


df2 = df['idx'].unstack(1).reindex(columns=c, level=1)
print (df2)
                         a                             b                   c
                         b         c         d         c         d         d
lvl_1 lvl_3                                                                 
first 2018-02-12  0.601115  0.155995  0.969910  0.155995  0.969910  0.969910
      2018-02-13  0.866176  0.156019  0.020584  0.156019  0.020584  0.020584
      2018-02-14  0.058084  0.598658  0.708073  0.598658  0.708073  0.708073

#divide with flatten MultiIndex    
df3 = df1.div(df2)
df3.columns = df3.columns.map('/'.join)
#reshape back and change order of levels, sorting indices
df3 = df3.stack().reorder_levels([0,2,1]).sort_index()

print (df3)
lvl_1       lvl_3     
first  a/b  2018-02-12     1.217727
            2018-02-13     1.097599
            2018-02-14     6.448292
       a/c  2018-02-12     4.692434
            2018-02-13     6.093594
            2018-02-14     0.625632
       a/d  2018-02-12     0.754703
            2018-02-13    46.185944
            2018-02-14     0.528957
       b/c  2018-02-12     3.853437
            2018-02-13     5.551748
            2018-02-14     0.097023
       b/d  2018-02-12     0.619764
            2018-02-13    42.079059
            2018-02-14     0.082031
       c/d  2018-02-12     0.160834
            2018-02-13     7.579425
            2018-02-14     0.845476
dtype: float64
14.02.2018
  • Мне нравятся оба ответа, твой и Мартин. Я буду работать над сочетанием обоих, но я понял идею. Люблю метод unstack/stack! Спасибо 14.02.2018
  • хороший трюк с reindex(level=) . Я думал о stack/unstack, 14.02.2018
  • @MaartenFabre - спасибо. а также для np.random.seed(42) 14.02.2018

  • 2
    from itertools import combinations
    def calc_ratios(data):
        comb = combinations(data.index.get_level_values('lvl_2').unique(), 2)
    
        ratios = {
            f'{i}/{j}': 
                data.xs(i, level='lvl_2') / 
                data.xs(j, level='lvl_2')
            for i, j in comb
        }
    #     print(ratios)
        if ratios:
            return pd.concat(ratios)
    result = pd.concat(calc_ratios(data) for group, data in df.groupby('lvl_1'))
    
        lvl_1 lvl_3   idx
    a/b   first   2018-02-14  6.448292467809392
    a/b   first   2018-02-13  1.0975992712883451
    a/b   first   2018-02-12  1.2177269366284045
    a/c   first   2018-02-14  0.6256323575698127
    a/c   first   2018-02-13  6.093594353302192
    a/c   first   2018-02-12  4.692433684425558
    a/d   first   2018-02-14  0.5289572433565499
    a/d   first   2018-02-13  46.185944271838835
    a/d   first   2018-02-12  0.7547030687230791
    b/d   first   2018-02-14  0.08203059119870332
    b/d   first   2018-02-13  42.07905879677424
    b/d   first   2018-02-12  0.6197637959891664
    c/b   first   2018-02-14  10.306839775450461
    c/b   first   2018-02-13  0.18012345549282302
    c/b   first   2018-02-12  0.25950860865015657
    c/d   first   2018-02-14  0.8454761601705119
    c/d   first   2018-02-13  7.579425474360648
    c/d   first   2018-02-12  0.16083404038888807
    

    (данные сгенерированы с помощью np.random.seed(42))

    14.02.2018
  • А как насчет использования np.random.seed() в вашем ответе? ;) 14.02.2018
  • Спасибо, Мартин! Очень полезно! 14.02.2018
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..