19

一部の行が指定された回数複製されるように、DataFrameを変換しようとしています。例えば:

df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count':[1,0,2]})

  class  count
0     A      1
1     B      0
2     C      2

次のように変換する必要があります:

  class 
0     A   
1     C   
2     C 

これは、カウント関数を使用した集計の逆です。パンダでそれを達成する簡単な方法はありますか(forループやリスト内包表記を使用せずに)?

1つの可能性は、関数が複数の行を返すことを許可することです(のメソッドにDataFrame.applymap似ています)。しかし、今はパンダではできないと思います。applyGroupBy

4

4 に答える 4

30

groupbyを使用できます。

def f(group):
    row = group.irow(0)
    return DataFrame({'class': [row['class']] * row['count']})
df.groupby('class', group_keys=False).apply(f)

だからあなたは

In [25]: df.groupby('class', group_keys=False).apply(f)
Out[25]: 
  class
0     A
0     C
1     C

結果のインデックスは好きなように修正できます

于 2012-10-24T15:25:40.213 に答える
5

これは古い質問ですが、Wesの回答をデータフレームの複数の列で機能させるのに問題があったため、彼のコードをもう少し一般的にしました。他の誰かが同じ問題でこの質問につまずいた場合に備えて、私は共有したいと思いました。

基本的に、カウントが含まれる列を指定するだけで、拡張されたデータフレームが返されます。

import pandas as pd
df = pd.DataFrame({'class 1': ['A','B','C','A'],
                   'class 2': [ 1,  2,  3,  1], 
                   'count':   [ 3,  3,  3,  1]})
print df,"\n"

def f(group, *args):
    row = group.irow(0)
    Dict = {}
    row_dict = row.to_dict()
    for item in row_dict: Dict[item] = [row[item]] * row[args[0]]
    return pd.DataFrame(Dict)

def ExpandRows(df,WeightsColumnName):
    df_expand = df.groupby(df.columns.tolist(), group_keys=False).apply(f,WeightsColumnName).reset_index(drop=True)
    return df_expand


df_expanded = ExpandRows(df,'count')
print df_expanded

戻り値:

  class 1  class 2  count
0       A        1      3
1       B        2      3
2       C        3      3
3       A        1      1 

  class 1  class 2  count
0       A        1      1
1       A        1      3
2       A        1      3
3       A        1      3
4       B        2      3
5       B        2      3
6       B        2      3
7       C        3      3
8       C        3      3
9       C        3      3

速度に関しては、私のベースdfは10列×6k行で、展開すると100,000行まで7秒かかります。この場合、すべての列をグループ化するため、グループ化が必要か賢明かはわかりませんが、7秒だけです。

于 2015-05-04T21:25:03.923 に答える
4

さらに単純で非常に効率的なソリューションがあります。約350万行のテーブルに対して同様の変更を行う必要があり、以前に提案されたソリューションは非常に低速でした。

より良い方法は、numpyのrepeatプロシージャを使用して、各行インデックスが指定されたカウントに従って複数回繰り返される新しいインデックスを生成し、ilocを使用してこのインデックスに従って元のテーブルの行を選択することです。

import pandas as pd
import numpy as np

df = pd.DataFrame({'class': ['A', 'B', 'C'], 'count': [1, 0, 2]})
spread_ixs = np.repeat(range(len(df)), df['count'])
spread_ixs 

array([0, 2, 2])

df.iloc[spread_ixs, :].drop(columns='count').reset_index(drop=True)

  class
0     A
1     C
2     C
于 2020-01-01T12:55:13.990 に答える
1

この質問は非常に古く、答えはパンダの最新の機能を反映していません。を使用iterrowsしてすべての行をループし、DataFrameコンストラクターを使用して正しい行数で新しいDataFrameを作成できます。最後に、を使用pd.concatしてすべての行を連結します。

pd.concat([pd.DataFrame(data=[row], index=range(row['count'])) 
           for _, row in df.iterrows()], ignore_index=True)

  class  count
0     A      1
1     C      2
2     C      2

これには、任意のサイズのDataFrameを操作できるという利点があります。

于 2017-08-29T19:16:40.563 に答える