背景・実現したいこと
並列計算を行うために、偏りが少ない形で分割処理するための前処理が行えるPython3での記述方法を探しています。
下記の入出力データ例と共に、どのような処理を行いたいかの説明をさせてください。
######入出力データ例
configの中に、aaa, bbb, cccという添え字があり、aaaの中には4つ、bbbには1つ、cccには3つ要素があります。
concurrency_limit=2
ということで、単純に2つに分割すると [['aaa','bbb'],['ccc']]
となります。
これではaaaとbbbの要素数は4+1=5、もう一方のcccの要素数は3となり、偏ってしまいます。
そうではなく、中の要素数を考慮した分割を行い、要素数の多い順に[['aaa'], ['ccc','bbb']]
という結果を得られる方法が知りたく、お力添え頂けますでしょうか。
外部ライブラリを用いる方法も含めて探しております。
python
1# 入力パラメータ (この結果を用いて並列上限数として作用させるため、この名称です) 2concurrency_limit = 2 3 4# 入力データ例 (k:vの箇所はそれぞれ異なる計算したい内容が記されている想定です) 5config = { 6 'aaa': { 7 'aaa1': {'k': 'v'}, 8 'aaa2': {'k': 'v'}, 9 'aaa3': {'k': 'v'}, 10 'aaa4': {'k': 'v'}}, 11 'bbb': {'bbb1': {'k': 'v'}}, 12 'ccc': { 13 'ccc1': {'k': 'v'}, 14 'ccc2': {'k': 'v'}, 15 'ccc3': {'k': 'v'}} 16 } 17 18# 出力データ例 (できるならば要素の多い順に並んで欲しいが、[['aaa'], ['bbb','ccc']]という順番でも可です) 19[['aaa'], ['ccc','bbb']]
考えたこと
おそらく次のようなステップで行うのだろうと想像できたのですが、不勉強で記述方法が分かりませんでした。
もし、別の最適解を求められるスマートな手法があるとしたら、よりよい形での処理方法を学びたいです。
- 要素数を計算済のデータ構造を作り大きい順にソートする
'aaa':4, 'ccc':3, 'bbb':1
concurrency_limit: N
のループで、新たに作ったハッシュ配列に先頭N件を格納する[{'item':['aaa'],'sum':4},{'item':['ccc'],'sum':3}]
- 2周目のループでcountが少ない順に残った要素を追記する
[{'item':['aaa'],'sum':4},{'item':['ccc','bbb'],'sum':4}]
- itemの中身を出力する
[['aaa'], ['ccc','bbb']]
検算として、 10, 7, 5, 4, 3, 2
という数列を2つに分割するとき、上記の方法だと次の分割となります。
- 1ループ目
[10]
,[7]
- 2ループ目
[10,4]
,[7,5]
- 3ループ目
[10,4,2]
,[7,5,3]
合計値が左辺は10+4+2=16、右辺は7+5+3=15となり、おおむね均等配分出来ていると確認ができました。
しかし、 [3, 3, 2, 2, 2]
に対して同じ手法で2分割すると、3 + 2 + 2 = 7
と 3 + 2 = 5
となります。
最適解である 3 + 3 = 6
と 2 + 2 + 2 = 6
とは異なる事にppaulさんのご指摘で気づきました。
試してみたこと
1次元配列を指定の数に分割する時に numpy や pandas を使ったことがあったので、関連する関数を探しました。
しかし入力データの形式を変えたとしても要件に合う物がなさそうに思えました。
また、teratailやGoogleで 均等 配分 分割などのキーワードで探しましたが、見つけられませんでした。