Мне дан мультииндексный DataFrame pandas, проиндексированный с помощью чисел с плавающей запятой. Рассмотрим следующий пример:

arrays = [[0.21,0.21,0.21,0.22,0.22,0.22,0.23,0.23,0.23],
          [0.81,0.8200000000000001,0.83,0.81,0.8200000000000001,0.83,0.81,0.8200000000000001,0.83]]
df = pd.DataFrame(np.random.randn(9, 2), index=arrays)

df

#               0           1
# 0.21  0.81    -2.234036   -0.145643
#       0.82    0.367248    -1.471617
#       0.83    -0.764520   0.686241
# 0.22  0.81    1.380429    1.546513
#       0.82    1.230707    1.826980
#       0.83    -1.198403   0.377323
# 0.23  0.81    -0.418367   -0.125763
#       0.82    0.682860    -0.119080
#       0.83    -1.802418   0.357573

Я получил этот DataFrame в этой форме. Теперь, если я хочу получить запись df.loc[(0.21, 0.82)], я получаю сообщение об ошибке, потому что индекс на самом деле содержит не 0.82, а 0.8200000000000001. Я не знаю заранее, где в индексе возникают эти проблемы. Как я могу решить эту проблему? Моя идея состоит в том, чтобы округлить оба уровня мультииндекса до значительного числа десятичных знаков, которое в данном случае равно 2. Но как это сделать? Есть ли лучшее решение?

1
statscorr 3 Ноя 2020 в 02:21

2 ответа

Лучший ответ

Вместо этого рассмотрите возможность использования целых чисел: умножьте числа с плавающей запятой на 100 (или 1000) и преобразуйте их в целые числа:

df.index = pd.MultiIndex.from_product([
             (df.index.levels[0] * 100).astype(int),
             (df.index.levels[1] * 100).astype(int)])

Целые числа точны, в отличие от чисел с плавающей запятой. Теперь вы можете использовать df.loc[(21, 82)] для доступа к своим данным.

1
DYZ 3 Ноя 2020 в 00:33

Вы можете использовать функцию rename, чтобы применить функцию к каждому значению вашего MultiIndex:

df = df.rename(index=lambda val: round(val, 2))

print(df.loc[(.21, .82)])
0    0.260015
1   -0.233822
Name: (0.21, 0.82), dtype: float64

Однако я не уверен, есть ли числа с плавающей запятой в качестве конкретных ключей из-за https: // docs. python.org/3/tutorial/floatingpoint.html (краткий пример)

>>> .1 + .1 + .1 == .3
False

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

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

df = df.rename(index="{:.2f}".format)

print(df.loc[("0.21", "0.82")]) # note that the leading 0 is important here now
0    0.260015
1   -0.233822
Name: (0.21, 0.82), dtype: float64
0
Cameron Riddell 3 Ноя 2020 в 00:23