字符串作为索引在 NumPy 数组中是不可能的。
但是,如果我理解正确,您实际上并没有必要更改索引,而只是想根据索引获取相应的月份和年份。
从索引中计算正确的月份和日期非常简单。为此,您可以使用 modulus 和 floor division 函数。
由于年份每 12 个指数递增,您可以将其计算为 1749(基准年)加上指数的下限除以 12 的结果:
yr = idx // 12 + 1749
月份是索引模 12 加一(因为索引从零开始):
mnth = idx % 12 + 1
由于您不希望将月份作为数字,而是将缩写作为字符串,因此您需要将不同的可能性之一应用于get the month name from a number。我只是创建了一个数组来查找月份缩写,如this SO answer,因为以后可以有效地使用它来查找np.take()。
months = ['n/a', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
mnth_abbrev = months[idx % 12 + 1]
为了不仅将其有效地应用于单个索引值,而且同时应用于 numpy 数组的所有值,我们可以使用针对性能优化的上述操作的 矢量化 版本。它们是np.mod()(用于%)和np.floor_divide()(用于//)。此外,我们使用np.take()(对于x[y],请参阅this SO post)。作为一些小的更改,我使用np.flatnonzero() 而不是np.where() 来获取索引,因为我们想要一个数组作为结果而不是一个元组(有关更多信息,请参阅this SO post)。最后,我使用np.char.add() 连接月份和年份,还稍微更改了months 数组,在每个月份缩写后包含一个逗号和一个空格,以获得最终所需的输出。
完整示例:
import numpy as np
sunspots = np.array([58,12,4,0,58,1,548,45,0,0,2,58,58,1,12,2,0,58])
months = ['n/a', 'Jan, ', 'Feb, ', 'Mar, ', 'Apr, ', 'May, ', 'Jun, ', 'Jul, ', 'Aug, ', 'Sep, ', 'Oct, ', 'Nov, ', 'Dec, ']
def get_year_and_month(cnt, spots):
hits = np.flatnonzero(spots == cnt)
mths = np.take(months, np.mod(hits, 12) + 1)
yrs = np.floor_divide(hits, 12) + 1749
return np.char.add(mths, yrs.astype('str'))
count = int(input("Enter a number of sunspots: "))
res = get_year_and_month(count, sunspots)
if res.size != 0:
print(np.vstack(res))
输出:
Enter a number of sunspots: 58
[['Jan, 1749']
['May, 1749']
['Dec, 1749']
['Jan, 1750']
['Jun, 1750']]
对于您的数据,结果将是:
Enter a number of sunspots: 58
[['Jan, 1749']
['Jan, 1792']
['Aug, 1881']]
如果您经常/重复调用此函数,另一种方法是将完整日期范围构造为数组并通过它查找索引:
import numpy as np
sunspots = np.array([58,12,4,0,58,1,548,45,0,0,2,58,58,1,12,2,0,58])
months = ['n/a', 'Jan, ', 'Feb, ', 'Mar, ', 'Apr, ', 'May, ', 'Jun, ', 'Jul, ', 'Aug, ', 'Sep, ', 'Oct, ', 'Nov, ', 'Dec, ']
dates = np.arange(0,sunspots.shape[0])
dates = np.char.add(np.take(months, np.mod(dates, 12) + 1), (np.floor_divide(dates, 12) + 1749).astype('str'))
def get_year_and_month(cnt, spots, dts):
hits = np.flatnonzero(spots == cnt)
return np.take(dts, hits)
count = int(input("Enter a number of sunspots: "))
res = get_year_and_month(count, sunspots, dates)
if res.size != 0:
print(np.vstack(res))
输出与上面的相同。
如果你真的确实想要一个带有字符串索引的数据结构,我建议你使用Pandas DataFrame。你可以例如只需以相同的方式构建日期数组并将其作为DataFrame() 调用的index 参数传递。然后通过df.index 查找您的结果:
import numpy as np
import pandas as pd
sunspots = np.array([58,12,4,0,58,1,548,45,0,0,2,58,58,1,12,2,0,58])
months = ['n/a', 'Jan, ', 'Feb, ', 'Mar, ', 'Apr, ', 'May, ', 'Jun, ', 'Jul, ', 'Aug, ', 'Sep, ', 'Oct, ', 'Nov, ', 'Dec, ']
df = pd.DataFrame(data=sunspots, index=np.char.add(np.take(months, np.mod(np.arange(sunspots.shape[0]), 12) + 1), (np.floor_divide(np.arange(sunspots.shape[0]), 12) + 1749).astype('str')), columns=['spots'])
count = int(input("Enter a number of sunspots: "))
print(df.index[df['spots'] == count].tolist())
输出:
Enter a number of sunspots: 58
['Jan, 1749', 'May, 1749', 'Dec, 1749', 'Jan, 1750', 'Jun, 1750']
由于数据框现在确实将日期字符串作为索引,您还可以通过此字符串索引访问您的太阳黑子数据:
>>> df
spots
Jan, 1749 58
Feb, 1749 12
Mar, 1749 4
Apr, 1749 0
May, 1749 58
Jun, 1749 1
Jul, 1749 548
Aug, 1749 45
Sep, 1749 0
Oct, 1749 0
Nov, 1749 2
Dec, 1749 58
Jan, 1750 58
Feb, 1750 1
Mar, 1750 12
Apr, 1750 2
May, 1750 0
Jun, 1750 58
>>> df['spots']['Jan, 1750']
58