random.choiceの加重バージョン


245

random.choiceの加重バージョンを作成する必要がありました(リストの各要素は、選択される確率が異なります)。これは私が思いついたものです:

def weightedChoice(choices):
    """Like random.choice, but each element can have a different chance of
    being selected.

    choices can be any iterable containing iterables with two items each.
    Technically, they can have more than two items, the rest will just be
    ignored.  The first item is the thing being chosen, the second item is
    its weight.  The weights can be any numeric values, what matters is the
    relative differences between them.
    """
    space = {}
    current = 0
    for choice, weight in choices:
        if weight > 0:
            space[current] = choice
            current += weight
    rand = random.uniform(0, current)
    for key in sorted(space.keys() + [current]):
        if rand < key:
            return choice
        choice = space[key]
    return None

この機能は私には過度に複雑で醜く見えます。私はここのみんながそれを改善するか、これを行う別の方法についていくつかの提案を提供できることを望んでいます。コードの清潔さと読みやすさほど効率は重要ではありません。

回答:


297

バージョン1.7.0以降、NumPyにはchoice確率分布をサポートする関数があります。

from numpy.random import choice
draw = choice(list_of_candidates, number_of_items_to_pick,
              p=probability_distribution)

はとprobability_distribution同じ順序のシーケンスですlist_of_candidates。キーワードreplace=Falseを使用して、描画されたアイテムが置き換えられないように動作を変更することもできます。


11
私のテストでは、これはrandom.choices個々の呼び出しよりも桁違いに遅いです。ランダムな結果がたくさん必要な場合は、を調整して一度にすべてを選択することが非常に重要number_of_items_to_pickです。そうすれば、桁違いに速くなります。
jpmc26

2
これはタプルなどでは機能しません( "ValueError:aは1次元でなければなりません")。その場合、numpyにリストにインデックスを選択するように要求できます。つまりlen(list_of_candidates)list_of_candidates[draw]
xjcl

218

Python 3.6以降choicesrandomモジュールからのメソッドがあります。

Python 3.6.1 (v3.6.1:69c0db5050, Mar 21 2017, 01:21:04)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.0.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import random

In [2]: random.choices(
...:     population=[['a','b'], ['b','a'], ['c','b']],
...:     weights=[0.2, 0.2, 0.6],
...:     k=10
...: )

Out[2]:
[['c', 'b'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['b', 'a'],
 ['c', 'b'],
 ['c', 'b']]

docsによると、置換random.choicesサンプルされることに注意してください:

k母集団から選択された要素のサイズ変更されたリストを置換して返します。

置換せずにサンプリングする必要がある場合は、@ronan-paixãoのすばらしい答えが示すようnumpy.choiceに、replace引数を使用してそのような動作を制御できます。


4
これはnumpy.random.choiceよりもはるかに高速です。8つの加重アイテムのリストから10,000回選択すると、numpy.random.choiceは0.3286秒かかりましたが、random.choicesは0.0416秒かかり、約8倍速くなりました。
アントンコード

@AntonCodesこの例はチェリーピックです。numpyには一定の時間オーバーヘッドがありrandom.choicesません。そのため、もちろん8項目の非常に小さなリストでは遅くなります。そのようなリストから1万回を選択している場合は正しいです。しかし、リストが大きい場合(テストの方法にもよりますが、100から300の要素の間にブレークポイントが見られます)は、かなり広いギャップでnp.random.choiceパフォーマンスが向上random.choicesし始めます。たとえば、numpy呼び出しと一緒に正規化ステップを含めると、1 random.choices万個の要素のリストで約4倍のスピードアップが得られます。
ggorlen

これは、@ AntonCodesが報告したパフォーマンスの向上に基づく新しい答えになるはずです。
ウェインWorkman

132
def weighted_choice(choices):
   total = sum(w for c, w in choices)
   r = random.uniform(0, total)
   upto = 0
   for c, w in choices:
      if upto + w >= r:
         return c
      upto += w
   assert False, "Shouldn't get here"

10
あなたはドロップ操作し、forループ内のステートメントを反転させることにより、時間のスライバーを保存することができます:upto +=w; if upto > r
knite

5
毎回重みをrまで削除し、rを減分して変数を保存します。次に、比較はif r < 0
JnBrymn 2014年

@JnBrymnチェックする必要がありr <= 0ます。1アイテムの入力セットと1.0のロールを考えます。その場合、アサーションは失敗します。答えの誤りを訂正しました。
moooeeeep 2015

1
あなたは部分としてループのためにマークするプラグマを使用することができ@Sardathrion:# pragma: no branch
ネッドBatchelder

1
@ mLstudent33私はUdacityを使用しません。
アントンコード

70
  1. 重みを累積分布に配置します。
  2. random.random()を使用してランダムなフロートを選択します0.0 <= x < totalます。
  3. http://docs.python.org/dev/library/bisect.html#other-examplesの例に示すように、bisect.bisectを使用してディストリビューションを検索します
from random import random
from bisect import bisect

def weighted_choice(choices):
    values, weights = zip(*choices)
    total = 0
    cum_weights = []
    for w in weights:
        total += w
        cum_weights.append(total)
    x = random() * total
    i = bisect(cum_weights, x)
    return values[i]

>>> weighted_choice([("WHITE",90), ("RED",8), ("GREEN",2)])
'WHITE'

複数の選択をする必要がある場合は、これを2つの関数に分割します。1つは累積的な重みを作成するためのもので、もう1つはランダムな点に二分するためのものです。


5
これはネッドの答えよりも効率的です。基本的に、選択肢を線形(O(n))検索する代わりに、二分検索(O(log n))を実行します。+1!
NHDaly 2014年

random()がたまたま1.0を返した場合、タプルインデックスが範囲外
Jon Vaughan

10
O(n)累積分布計算のため、これはまだ実行されます。
Lev

6
このソリューションは、同じ選択セットに対してweighted_choiceへの複数の呼び出しが必要な場合に適しています。その場合、累積合計を1回作成し、各呼び出しでバイナリ検索を実行できます。
Amosは

1
@JonVaughan random() 1.0を返すことはできません。ドキュメントごとに、ハーフオープン間隔[0.0, 1.0)で結果を返します。つまり、正確に0.0 返すことはできますが、正確に1.0を返すことはできません。返すことができる最大値は0.99999999999999988897769753748434595763683319091796875です(これはPythonが0.9999999999999999として出力し、1未満の最大の64ビット浮動小数点数です)。
Mark Amery

21

numpyを使用してもかまわない場合は、numpy.random.choiceを使用できます

例えば:

import numpy

items  = [["item1", 0.2], ["item2", 0.3], ["item3", 0.45], ["item4", 0.05]
elems = [i[0] for i in items]
probs = [i[1] for i in items]

trials = 1000
results = [0] * len(items)
for i in range(trials):
    res = numpy.random.choice(items, p=probs)  #This is where the item is selected!
    results[items.index(res)] += 1
results = [r / float(trials) for r in results]
print "item\texpected\tactual"
for i in range(len(probs)):
    print "%s\t%0.4f\t%0.4f" % (items[i], probs[i], results[i])

事前に必要な選択の数がわかっている場合は、次のようなループなしで実行できます。

numpy.random.choice(items, trials, p=probs)

15

粗野ですが、十分かもしれません:

import random
weighted_choice = lambda s : random.choice(sum(([v]*wt for v,wt in s),[]))

うまくいきますか?

# define choices and relative weights
choices = [("WHITE",90), ("RED",8), ("GREEN",2)]

# initialize tally dict
tally = dict.fromkeys(choices, 0)

# tally up 1000 weighted choices
for i in xrange(1000):
    tally[weighted_choice(choices)] += 1

print tally.items()

プリント:

[('WHITE', 904), ('GREEN', 22), ('RED', 74)]

すべての重みが整数であると仮定します。合計が100になる必要はありません。テスト結果をより簡単に解釈できるようにするためだけに計算しました。(重みが浮動小数点数の場合、すべての重みが1以上になるまで、それらすべてに10を繰り返し乗算します。)

weights = [.6, .2, .001, .199]
while any(w < 1.0 for w in weights):
    weights = [w*10 for w in weights]
weights = map(int, weights)

1
ただし、すべての重みが整数であると想定できるかどうかはわかりません。
コリン

1
この例ではオブジェクトが複製されるようです。これは非効率的です(したがって、重みを整数に変換する関数も同様です)。それにもかかわらず、整数の重みが小さい場合、このソリューションは優れたワンライナーです。
wei2912

プリミティブは複製されますが、オブジェクトには参照だけが複製され、オブジェクト自体は複製されません。(これは、使用してリストのリストを作成することができない理由である[[]]*10外側のリストポイント内のすべての要素を同じリストに- 。
PaulMcG

@PaulMcGいいえ。参照のみが複製されます。Pythonの型システムにはプリミティブの概念がありません。たとえば、たとえint同じことをしても、同じオブジェクトへの参照がまだたくさんあることを確認し、すべての呼び出しで同じメモリアドレス[id(x) for x in ([99**99] * 100)]id返すことを確認できます。
Mark Amery

14

リストの代わりに加重辞書がある場合は、これを書くことができます

items = { "a": 10, "b": 5, "c": 1 } 
random.choice([k for k in items for dummy in range(items[k])])

[k for k in items for dummy in range(items[k])]このリストを生成することに注意してください['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'b', 'b', 'b', 'b', 'b']


10
これは、小さい総人口値に対しては機能しますが、大きなデータセットに対しては機能しません(たとえば、米国の州ごとの人口は、最終的に3億のアイテムを含む作業リストを作成することになります)。
ライアン

@ライアン確かに。別の現実的なシナリオである非整数の重みに対しても機能しません(たとえば、重みが選択の確率として表されている場合)。
Mark Amery

12

Pythonではv3.6、オプションの重みを使用して、指定された母集団から指定されたサイズの要素のrandom.choicesaを返すためlistに使用できました。

random.choices(population, weights=None, *, cum_weights=None, k=1)

  • 母集団listユニークな観測を含みます。(空の場合は発生IndexError

  • 重み:より正確には、選択を行うために必要な相対重み。

  • cum_weights:選択を行うために必要な累積重み。

  • k:出力するのsize(lenlist。(デフォルトlen()=1


いくつかの警告:

1)重み付きサンプリングと置換を使用して、描画されたアイテムが後で置換されるようにします。ウェイトシーケンスの値自体は重要ではありませんが、それらの相対比率は重要です。

np.random.choice確率を重みとしてのみ取ることができ、1つの基準までの個々の確率の合計を確実にする必要があるものとは異なり、ここではそのような規制はありません。数値型(type int/float/fractionを除くDecimal)に属している限り、これらは引き続き機能します。

>>> import random
# weights being integers
>>> random.choices(["white", "green", "red"], [12, 12, 4], k=10)
['green', 'red', 'green', 'white', 'white', 'white', 'green', 'white', 'red', 'white']
# weights being floats
>>> random.choices(["white", "green", "red"], [.12, .12, .04], k=10)
['white', 'white', 'green', 'green', 'red', 'red', 'white', 'green', 'white', 'green']
# weights being fractions
>>> random.choices(["white", "green", "red"], [12/100, 12/100, 4/100], k=10)
['green', 'green', 'white', 'red', 'green', 'red', 'white', 'green', 'green', 'green']

2)weightscum_weightsも指定されていない場合、選択は等しい確率で行われます。重みシーケンスが指定されている場合、それは母集団と同じ長さでなければなりませんシーケンス。

weightscum_weightsの両方を指定すると、が発生しTypeErrorます。

>>> random.choices(["white", "green", "red"], k=10)
['white', 'white', 'green', 'red', 'red', 'red', 'white', 'white', 'white', 'green']

3)cum_weightsは通常、そのitertools.accumulateような状況で本当に便利な関数の結果です。

リンクされたドキュメントから:

内部的には、相対的な重みは選択を行う前に累積的な重みに変換されるため、累積的な重みを指定すると作業が節約されます。

したがって、私たちが考案したケースを提供するweights=[12, 12, 4]cum_weights=[12, 24, 28]、またはそのいずれかで同じ結果が得られ、後者の方がより高速で効率的です。


11

Python 3.6の標準ライブラリに含まれているバージョンは次のとおりです。

import itertools as _itertools
import bisect as _bisect

class Random36(random.Random):
    "Show the code included in the Python 3.6 version of the Random class"

    def choices(self, population, weights=None, *, cum_weights=None, k=1):
        """Return a k sized list of population elements chosen with replacement.

        If the relative weights or cumulative weights are not specified,
        the selections are made with equal probability.

        """
        random = self.random
        if cum_weights is None:
            if weights is None:
                _int = int
                total = len(population)
                return [population[_int(random() * total)] for i in range(k)]
            cum_weights = list(_itertools.accumulate(weights))
        elif weights is not None:
            raise TypeError('Cannot specify both weights and cumulative weights')
        if len(cum_weights) != len(population):
            raise ValueError('The number of weights does not match the population')
        bisect = _bisect.bisect
        total = cum_weights[-1]
        return [population[bisect(cum_weights, random() * total)] for i in range(k)]

ソース:https : //hg.python.org/cpython/file/tip/Lib/random.py#l340


2
import numpy as np
w=np.array([ 0.4,  0.8,  1.6,  0.8,  0.4])
np.random.choice(w, p=w/sum(w))

2

役に立つ情報を提供するには遅すぎるかもしれませんが、以下はシンプルで短く、非常に効率的なスニペットです。

def choose_index(probabilies):
    cmf = probabilies[0]
    choice = random.random()
    for k in xrange(len(probabilies)):
        if choice <= cmf:
            return k
        else:
            cmf += probabilies[k+1]

確率をソートしたり、cmfでベクトルを作成したりする必要はありません。選択が見つかると終了します。メモリ:O(1)、時間:O(N)、平均実行時間〜N / 2。

重みがある場合は、1行追加するだけです。

def choose_index(weights):
    probabilities = weights / sum(weights)
    cmf = probabilies[0]
    choice = random.random()
    for k in xrange(len(probabilies)):
        if choice <= cmf:
            return k
        else:
            cmf += probabilies[k+1]

1
これにはいくつかの問題があります。表面的には、タイプミスされた変数名がいくつかあり、これを使用するための根拠はありませんnp.random.choice。しかしさらに興味深いことに、これが例外を発生させる障害モードがあります。これを行っprobabilities = weights / sum(weights)ても、probabilities合計が1になるとは限りません。場合、例えば、weightsある[1,1,1,1,1,1,1]ついでprobabilitiesのみの最大の可能な戻り値よりも小さい、0.9999999999999998に合計するrandom.random(0.9999999999999999です)。その後choice <= cmf、満足することはありません。
Mark Amery

2

重み付けされた選択肢のリストが比較的静的であり、頻繁なサンプリングが必要な場合は、この関連する回答の関数を使用して、O(N)前処理ステップを1つ実行してから、O(1)で選択を実行できます

# run only when `choices` changes.
preprocessed_data = prep(weight for _,weight in choices)

# O(1) selection
value = choices[sample(preprocessed_data)][0]

1

私は指摘された他のスレッドを調べて、コーディングスタイルにこのバリエーションを思いつきました。これは、集計のために選択したインデックスを返しますが、文字列を返すのは簡単です(コメント付きの代替代替):

import random
import bisect

try:
    range = xrange
except:
    pass

def weighted_choice(choices):
    total, cumulative = 0, []
    for c,w in choices:
        total += w
        cumulative.append((total, c))
    r = random.uniform(0, total)
    # return index
    return bisect.bisect(cumulative, (r,))
    # return item string
    #return choices[bisect.bisect(cumulative, (r,))][0]

# define choices and relative weights
choices = [("WHITE",90), ("RED",8), ("GREEN",2)]

tally = [0 for item in choices]

n = 100000
# tally up n weighted choices
for i in range(n):
    tally[weighted_choice(choices)] += 1

print([t/sum(tally)*100 for t in tally])

1

分布をサンプリングする回数によって異なります。

分布をK回サンプリングするとします。次に、np.random.choice()各時間を使用する時間の複雑さはO(K(n + log(n)))nは、配布内のアイテム数になるかです。

私の場合、nが10 ^ 6のオーダーである10 ^ 3のオーダーの同じ分布を複数回サンプリングする必要がありました。累積分布を事前計算し、それをでサンプリングする以下のコードを使用しましたO(log(n))。全体的な時間の複雑さはO(n+K*log(n))です。

import numpy as np

n,k = 10**6,10**3

# Create dummy distribution
a = np.array([i+1 for i in range(n)])
p = np.array([1.0/n]*n)

cfd = p.cumsum()
for _ in range(k):
    x = np.random.uniform()
    idx = cfd.searchsorted(x, side='right')
    sampled_element = a[idx]

1

たまたまPython 3を使用していnumpyて、独自のループをインストールまたは作成するのが怖い場合は、次のようにすることができます。

import itertools, bisect, random

def weighted_choice(choices):
   weights = list(zip(*choices))[1]
   return choices[bisect.bisect(list(itertools.accumulate(weights)),
                                random.uniform(0, sum(weights)))][0]

配管アダプターのバッグから何でも構築できるからです!ネッドの答えは少し長いですが、理解しやすいことを認めなければなりません。


0

一般的な解決策:

import random
def weighted_choice(choices, weights):
    total = sum(weights)
    treshold = random.uniform(0, total)
    for k, weight in enumerate(weights):
        total -= weight
        if total < treshold:
            return choices[k]

0

numpyを使用するweighted_choiceの別のバージョンを次に示します。重みベクトルを渡すと、選択されたビンを示す1を含む0の配列が返されます。コードはデフォルトで単一のドローを作成するように設定されていますが、作成するドローの数を渡すことができ、描画されたビンごとのカウントが返されます。

重みベクトルの合計が1にならない場合は、合計するように正規化されます。

import numpy as np

def weighted_choice(weights, n=1):
    if np.sum(weights)!=1:
        weights = weights/np.sum(weights)

    draws = np.random.random_sample(size=n)

    weights = np.cumsum(weights)
    weights = np.insert(weights,0,0.0)

    counts = np.histogram(draws, bins=weights)
    return(counts[0])

0

これを行う別の方法として、要素配列の要素と同じインデックスに重みがあると仮定します。

import numpy as np
weights = [0.1, 0.3, 0.5] #weights for the item at index 0,1,2
# sum of weights should be <=1, you can also divide each weight by sum of all weights to standardise it to <=1 constraint.
trials = 1 #number of trials
num_item = 1 #number of items that can be picked in each trial
selected_item_arr = np.random.multinomial(num_item, weights, trials)
# gives number of times an item was selected at a particular index
# this assumes selection with replacement
# one possible output
# selected_item_arr
# array([[0, 0, 1]])
# say if trials = 5, the the possible output could be 
# selected_item_arr
# array([[1, 0, 0],
#   [0, 0, 1],
#   [0, 0, 1],
#   [0, 1, 0],
#   [0, 0, 1]])

ここで、1回の試行で3つのアイテムをサンプリングする必要があると仮定します。重量配列によって与えられた重量の比率で大量に存在する3つのボールR、G、Bがあると想定できます。以下の結果が考えられます。

num_item = 3
trials = 1
selected_item_arr = np.random.multinomial(num_item, weights, trials)
# selected_item_arr can give output like :
# array([[1, 0, 2]])

選択するアイテムの数を、セット内の二項/多項式試行の数として考えることもできます。したがって、上記の例はまだ動作する可能性があります

num_binomial_trial = 5
weights = [0.1,0.9] #say an unfair coin weights for H/T
num_experiment_set = 1
selected_item_arr = np.random.multinomial(num_binomial_trial, weights, num_experiment_set)
# possible output
# selected_item_arr
# array([[1, 4]])
# i.e H came 1 time and T came 4 times in 5 binomial trials. And one set contains 5 binomial trails.

0

これについての無料のUdacityコースAI for RoboticsでSebastien Thurnによる講義があります。基本的に彼はmod演算子を使用してインデックス付きの重みの循環配列を作成します%、変数ベータを0に設定し、ランダムにインデックスを選択します。Nを通るループの場合、Nはインデックスの数であり、forループでは最初に次の式でベータをインクリメントします。

beta = beta + {0 ... 2 * Weight_max}からの均一サンプル

次にforループにネストされ、以下のwhileループ:

while w[index] < beta:
    beta = beta - w[index]
    index = index + 1

select p[index]

次に、確率(またはコースで提示されたケースでは正規化された確率)に基づいてリサンプリングする次のインデックスに進みます。

講義リンク:https : //classroom.udacity.com/courses/cs373/lessons/48704330/concepts/487480820923

私は自分の学校のアカウントでUdacityにログインしています。リンクが機能しない場合は、人工知能ロボット工学のレッスン8、ビデオ番号21で、粒子フィルターについて講義しています。


-1

1つの方法は、すべての重みの合計をランダム化し、その値を各変数の限界点として使用することです。これがジェネレーターとしての大まかな実装です。

def rand_weighted(weights):
    """
    Generator which uses the weights to generate a
    weighted random values
    """
    sum_weights = sum(weights.values())
    cum_weights = {}
    current_weight = 0
    for key, value in sorted(weights.iteritems()):
        current_weight += value
        cum_weights[key] = current_weight
    while True:
        sel = int(random.uniform(0, 1) * sum_weights)
        for key, value in sorted(cum_weights.iteritems()):
            if sel < value:
                break
        yield key

-1

numpyの使用

def choice(items, weights):
    return items[np.argmin((np.cumsum(weights) / sum(weights)) < np.random.rand())]

NumPyはすでにnp.random.choice2014年からここにある受け入れられた回答で述べられているようにを持っています。
Mark Amery

-1

私は、このテンプレートを作成したアイデアを検索することから、このような非常に高速で本当に簡単なことをする必要がありました。このアイデアは、apiからjsonの形式で加重値を受け取ります。これは、dictによってシミュレートされます。

次に、各値が重みに比例して繰り返されるリストに変換し、random.choiceを使用してリストから値を選択します。

私はそれを10、100、1000回の反復で実行してみました。分布はかなりしっかりしているようです。

def weighted_choice(weighted_dict):
    """Input example: dict(apples=60, oranges=30, pineapples=10)"""
    weight_list = []
    for key in weighted_dict.keys():
        weight_list += [key] * weighted_dict[key]
    return random.choice(weight_list)

-1

それらの構文は好きではありませんでした。私は本当に、アイテムが何であるか、そしてそれぞれの重みが何であるかを指定したかっただけです。私は使用できたと思いますrandom.choicesが、代わりにすぐに以下のクラスを書きました。

import random, string
from numpy import cumsum

class randomChoiceWithProportions:
    '''
    Accepts a dictionary of choices as keys and weights as values. Example if you want a unfair dice:


    choiceWeightDic = {"1":0.16666666666666666, "2": 0.16666666666666666, "3": 0.16666666666666666
    , "4": 0.16666666666666666, "5": .06666666666666666, "6": 0.26666666666666666}
    dice = randomChoiceWithProportions(choiceWeightDic)

    samples = []
    for i in range(100000):
        samples.append(dice.sample())

    # Should be close to .26666
    samples.count("6")/len(samples)

    # Should be close to .16666
    samples.count("1")/len(samples)
    '''
    def __init__(self, choiceWeightDic):
        self.choiceWeightDic = choiceWeightDic
        weightSum = sum(self.choiceWeightDic.values())
        assert weightSum == 1, 'Weights sum to ' + str(weightSum) + ', not 1.'
        self.valWeightDict = self._compute_valWeights()

    def _compute_valWeights(self):
        valWeights = list(cumsum(list(self.choiceWeightDic.values())))
        valWeightDict = dict(zip(list(self.choiceWeightDic.keys()), valWeights))
        return valWeightDict

    def sample(self):
        num = random.uniform(0,1)
        for key, val in self.valWeightDict.items():
            if val >= num:
                return key

-1

random.choice()に事前に重み付けされたリストを提供します:

ソリューションとテスト:

import random

options = ['a', 'b', 'c', 'd']
weights = [1, 2, 5, 2]

weighted_options = [[opt]*wgt for opt, wgt in zip(options, weights)]
weighted_options = [opt for sublist in weighted_options for opt in sublist]
print(weighted_options)

# test

counts = {c: 0 for c in options}
for x in range(10000):
    counts[random.choice(weighted_options)] += 1

for opt, wgt in zip(options, weights):
    wgt_r = counts[opt] / 10000 * sum(weights)
    print(opt, counts[opt], wgt, wgt_r)

出力:

['a', 'b', 'b', 'c', 'c', 'c', 'c', 'c', 'd', 'd']
a 1025 1 1.025
b 1948 2 1.948
c 5019 5 5.019
d 2008 2 2.008
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.