6

すべてのセルが辞書のリストで構成され、辞書の各リストがさまざまな長さ (0 を含む) である列を含む DataFrame があります。

例:

df = pd.DataFrame({'ID' : [13423,294847,322844,429847], 'RANKS': [[{u'name': u'A', u'price': u'$1.00', u'rank': u'1'},
{u'name': u'B', u'price': u'$4.00', u'rank': u'2'},
{u'name': u'C', u'price': u'$3.99', u'rank': u'3'},
{u'name': u'D', u'price': u'$2.00', u'rank': u'4'},
{u'name': u'E', u'price': u'$2.50', u'rank': u'5'}],

[{u'name': u'AA', u'price': u'$1.99', u'rank': u'1'},
{u'name': u'BB', u'price': u'$6.99', u'rank': u'2'}],

[{u'name': u'Z', u'price': u'$0.99', u'rank': u'1'},
{u'name': u'Y', u'price': u'$10.00', u'rank': u'2'},
{u'name': u'X', u'price': u'$1.99', u'rank': u'3'}],[]], 'count' : [5,2,3,0]})

「count」は「RANKS」内の辞書の数であることに注意してください。私が念頭に置いていた目標は、一連の追加のデータフレーム/テーブル (「ランク」ごとに 1 つ) を作成し、これらを HDFStore のメイン テーブルにリンクすることでした。何かのようなもの:

Rank_2
ID       Price   Name
13423    $4.00    B  
294847   $6.99    BB 
322844   $10.99   Y 
429847   NaN      NaN   


Rank_3
ID       Price   Name
13423    $3.99    C  
294847   NaN      NaN 
322844   $1.99    X 
429847   NaN      NaN   

このようにして、必要に応じて ID とランクを簡単に照会できますが、この階層データの巻き戻しによってメイン テーブルが乱雑になることはありません。

ただし、問題は、この列からデータフレームを作成する方法がわからないことです。私は多くのことを試しました.最初のものです(機能する場合はforループにネストされますが、もちろん機能しませんでした):

Rank_1 = pd.DataFrame(df.loc[df['count'] > 0]['RANKS'].map(lambda x: pd.DataFrame(x[0])))

そして、2 つ目は、価格が私にとって最も重要な要素であるためです。

for i in range(0,5):
    df['rank_%s' % str(i+1)] = df[df['count'] > i]['RANKS'].map(lambda x: x[i]['price'].strip('$'))

次に float に変換します。これは機能しますが、かなり大きな妥協点です。ランクごとに個別の DataFrames という私の目標を達成するための効率的な方法 (NaN にハングアップしない) はありますか?

4

3 に答える 3

6

私の直観的な反応は、おそらく DataFrame を多くの小さな DataFrame に分割すべきではないということです。多数の小さな DataFrame を処理するには、Python ループが必要です。これは通常、速度低下への道のりです。代わりに、1 つの DataFrame を使用した方がよいと思います。これにより、dict のリストが平坦化され、DataFrame 内の各内部 dict に独自の行が与えられます。内部辞書のキーは新しい列になります。この単一のフラットな DataFrame 形式は、複数の DataFrame の代替手段が実行できることは何でも実行できますが、高速であり、HDFStore への保存が簡単になると思います。

RANKS列に dict のリストを含む DataFrame があるとします。

import numpy as np
import pandas as pd

df = pd.DataFrame({'ID' : [13423,294847,322844,429847], 'RANKS': [[{u'name': u'A', u'price': u'$1.00', u'rank': u'1'},
{u'name': u'B', u'price': u'$4.00', u'rank': u'2'},
{u'name': u'C', u'price': u'$3.99', u'rank': u'3'},
{u'name': u'D', u'price': u'$2.00', u'rank': u'4'},
{u'name': u'E', u'price': u'$2.50', u'rank': u'5'}],

[{u'name': u'AA', u'price': u'$1.99', u'rank': u'1'},
{u'name': u'BB', u'price': u'$6.99', u'rank': u'2'}],

[{u'name': u'Z', u'price': u'$0.99', u'rank': u'1'},
{u'name': u'Y', u'price': u'$10.00', u'rank': u'2'},
{u'name': u'X', u'price': u'$1.99', u'rank': u'3'}],[]], 'count' : [5,2,3,0]})

次に、次のように行ごとに 1 つの dict を持つフラットな DataFrame を構築できます。

result = []
for idx, row in df.iterrows():
    for dct in row['RANKS']:
        dct['ID'] = row['ID']
        dct['count'] = row['count']
        result.append(dct)
del df
result = pd.DataFrame(result)
result['rank'] = result['rank'].astype(np.int32)
result['price'] = result['price'].str.replace('$', '')
result['price'] = result['price'].astype('float')
print(result)

利回り

       ID  count name  price  rank
0   13423      5    A   1.00     1
1   13423      5    B   4.00     2
2   13423      5    C   3.99     3
3   13423      5    D   2.00     4
4   13423      5    E   2.50     5
5  294847      2   AA   1.99     1
6  294847      2   BB   6.99     2
7  322844      3    Z   0.99     1
8  322844      3    Y  10.00     2
9  322844      3    X   1.99     3

result元のデータ ソースから直接構築する (つまり、df完全に回避する) 方が、よりクリーンで、メモリをあまり必要としないソリューションになることに注意してください。

于 2015-02-22T20:20:16.497 に答える
1

同様のシナリオに遭遇したばかりで、最終的に解決した方法は次のとおりです。

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({
   ...:     'ID' : [13423,294847,322844,429847],
   ...:     'RANKS': [[{u'name': u'A', u'price': u'$1.00', u'rank': u'1'},
   ...:                {u'name': u'B', u'price': u'$4.00', u'rank': u'2'},
   ...:                {u'name': u'C', u'price': u'$3.99', u'rank': u'3'},
   ...:                {u'name': u'D', u'price': u'$2.00', u'rank': u'4'},
   ...:                {u'name': u'E', u'price': u'$2.50', u'rank': u'5'}],
   ...: 
   ...:               [{u'name': u'AA', u'price': u'$1.99', u'rank': u'1'},
   ...:                {u'name': u'BB', u'price': u'$6.99', u'rank': u'2'}],
   ...: 
   ...:               [{u'name': u'Z', u'price': u'$0.99', u'rank': u'1'},
   ...:                {u'name': u'Y', u'price': u'$10.00', u'rank': u'2'},
   ...:                {u'name': u'X', u'price': u'$1.99', u'rank': u'3'}],[]]})

In [3]: import itertools

In [4]: temp_df = pd.DataFrame(
   ...:     list(itertools.chain(*[zip([key]*len(val), val)
   ...:                            for key, val in df.RANKS.iteritems()])),
   ...:     columns=['idx', 'explode'])                  

In [5]: exploded = pd.merge(
   ...:     df.drop('RANKS', axis=1),
   ...:     temp_df.explode.apply(pd.Series).join(temp_df.idx),
   ...:     left_index=True,
   ...:     right_on='idx',
   ...:     how='left').drop('idx', axis=1)

展開されたデータ フレームは次のようになります。

In [6]: exploded
Out[6]: 
       ID name   price rank
0   13423    A   $1.00    1
1   13423    B   $4.00    2
2   13423    C   $3.99    3
3   13423    D   $2.00    4
4   13423    E   $2.50    5
5  294847   AA   $1.99    1
6  294847   BB   $6.99    2
7  322844    Z   $0.99    1
8  322844    Y  $10.00    2
9  322844    X   $1.99    3
9  429847  NaN     NaN  NaN
于 2016-12-12T01:10:38.507 に答える