質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

list()を外すと'enumerate' object is not subscriptableのエラーが出る

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 620

magi201903

score 13

前提・実現したいこと

pythonで深層学習の勉強をしています。書籍『PythonとKerasによるディープラーニング』で、単語のone-hotエンコーディングを行うコードを実際に動かしていて、疑問に感じたコードがありました。しかし自分なりに修正して実行すると、エラーメッセージが出ました。

発生している問題・エラーメッセージ

for j, word in list(enumerate(sample.split()))[:max_length]:
という1行があります。

list()のある必然性が分からず、list()を削除し、以下のように書き直しました。
for j, word in enumerate(sample.split())[:max_length]:

すると、以下のようなエラーメッセージが出ます。
TypeError: 'enumerate' object is not subscriptable

 知りたいこと

1.エラーの意味は「添え字にアクセスできないオブジェクトです」ですか?
2.list()があるとエラーが出ないようになる理屈を教えてください
3.そもそも[:max_length]は不要な気がするのですが、なぜあるのでしょうか

該当のソースコード

import numpy as np

# This is our initial data; one entry per "sample"
# (in this toy example, a "sample" is just a sentence, but
# it could be an entire document).
samples = ['The cat sat on the mat.', 'The dog ate my homework.']

# First, build an index of all tokens in the data.
token_index = {}
for sample in samples:
    # We simply tokenize the samples via the `split` method.
    # in real life, we would also strip punctuation and special characters
    # from the samples.
    for word in sample.split():
        if word not in token_index:
            # Assign a unique index to each unique word
            token_index[word] = len(token_index) + 1
            # Note that we don't attribute index 0 to anything.

# Next, we vectorize our samples.
# We will only consider the first `max_length` words in each sample.
max_length = 10

# This is where we store our results:
results = np.zeros((len(samples), max_length, max(token_index.values()) + 1))
for i, sample in enumerate(samples):
    for j, word in list(enumerate(sample.split()))[:max_length]:
        index = token_index.get(word)
        results[i, j, index] = 1.

試したこと

ちなみに、[:max_length]を削除して以下のように書き直すと、エラーは出ません。
for j, word in enumerate(sample.split()):
enumerateはタプルを返す。これが謎を解くカギになっている気がしますが、よくわかりません。

以下のコードに直すとエラーが出ませんでした。
for j, word in enumerate(sample.split()[:max_length]):

補足情報(FW/ツールのバージョンなど)

google Colaboratoryを使っています。
https://github.com/fchollet/deep-learning-with-python-notebooks/blob/master/6.1-one-hot-encoding-of-words-or-characters.ipynb
ここにコードが載っています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

1.エラーの意味は「添え字にアクセスできないオブジェクトです」ですか?
その認識であっています。

2.list()があるとエラーが出ないようになる理屈を教えてください
添字でアクセスできるオブジェクトに変換したため。


組み込み関数 — Python 3.7.3rc1 ドキュメント

enumerate オブジェクトを返します。 iterable は、シーケンスか iterator か、あるいはイテレーションをサポートするその他のオブジェクトでなければなりません。 enumerate() によって返されたイテレータの next() メソッドは、 (デフォルトでは 0 となる start からの) カウントと、 iterable 上のイテレーションによって得られた値を含むタプルを返します。

enumerate() の返り値は enumerate オブジェクトであって、添字操作はサポートされていません。(subscribtableでない)

以下の例では、enumerate() の返り値 enum は [(0, 1), (1, 2), (2, 3), (3, 4)] のようなリストであると思って添字操作を行ったのだと思いますが、enum[:2] のように添字操作は行なえません。

enum = enumerate([1, 2, 3, 4])

enumerate オブジェクトは iterator であり、__next__() が呼ばれると、インスタンス化したときに渡した iterable なオブジェクトの要素を添え字付きで1つずつ返すようになっています。
添字操作をする場合は「list() でリストにする」など添字操作が行えるオブジェクトに変換する必要があります。

from collections.abc import Iterable

array = [1, 2, 3, 4]

# (1) enumerate はクラス
print(enumerate)  # <class 'enumerate'>

enum = enumerate(array)
print(enum)  # <enumerate object at 0x7f76684a2900>

# (2) enumerate クラスは iterable (__iter__ または __getitem__ 関数が定義されている。)
print(isinstance(enum, Iterable))  # True

# (3) enumerate オブジェクトからリストを作成する。
print(list(enum)) # [(0, 1), (1, 2), (2, 3), (3, 4)]

3.そもそも[:max_length]は不要な気がするのですが、なぜあるのでしょうか

コメントの We will only consider the first max_length words in each sample. とあるように文章は長さがまちまちなので、各要素が単語である文章を表すリストから最大で max_length 要素だけ取り出すということですね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/18 07:00

    >enumerate オブジェクトは iterable であり、__iter__() が呼ばれると、インスタンス化したときに渡した iterable なオブジェクトを添え字付きで1つずつ返すようになっています。
    ここの説明は怪しいかもしれません。
    正:enumerate オブジェクトは iterator であり、__next__() が呼ばれると、インスタンス化したときに渡した iterable なオブジェクトの要素を添え字付きで1つずつ返すようになっています。

    キャンセル

  • 2019/03/18 11:42

    コメントありがとうございます。
    ご指摘いただいた点を修正しました。

    キャンセル

  • 2019/03/21 03:08 編集

    tiitoiさま

    大変丁寧な説明、ありがとうございました。完全に理解はできていないので、pythonを学びながら、書いていただいた解説を折に触れ、見返します。
    今回の回答を読み、コードを書くとき、添字でアクセスできるオブジェクトか否かを意識する必要があることを学びました。

    3の[:max_length]の必要性についても理解できました。1文だけ1000単語とかある場合も、一律10単語までしか操作対象にしない、とした方が何かと便利ですよね。

    キャンセル

  • 2019/03/21 03:10

    hayataka2049さま
    ご助言、ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る