2012-10-24 62 views
11

我試圖轉換DataFrame,這樣一些行將被複制給定次數。例如:pandas:將函數應用於可以返回多行的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 

這是聚合的具有計數功能相反。有沒有一種簡單的方法在熊貓中實現它(不使用循環或列表解析)?

一種可能是允許DataFrame.applymap函數返回多行(類似apply方法GroupBy)。不過,我認爲現在熊貓是不可能的。

+0

我還記得一個通用函數,它允許根據'count'列中的值返回多個,一個或零個行。 – btel

+0

如果您在2017+中遇到此問題,請查看我的答案以獲得更有效且直接的解決方案。 –

回答

17

你可以使用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 

您可以修復結果的指標,只要你喜歡

+0

解決了我的問題!謝謝Wes。 – btel

+1

很好的答案!如果我有幾十個其他列,有沒有一種簡單的方法來保存'f'的結果中的那些列,而不是明確地輸入它們? –

1
repeated_items = [list(row[1]*row[2]) for row in df.itertuples()] 

將創建一個嵌套列表:

[['A'], [], ['C', 'C']] 

然後你就可以遍歷與列表內涵創建一個新的數據幀:

new_df = pd.DataFrame({"class":[j for i in repeated_items for j in i]}) 

當然,你可以做到這一點如果你想:

new_df = pd.DataFrame({"class":[j for i in [list(row[1]*row[2]) for row in df.itertuples()] for j in i]}) 
3

我知道這是一個老問題,但我有麻煩讓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秒即可。

0

這個問題很舊,答案也不能反映大熊貓的現代能力。您可以使用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 

這有利於處理任何大小的數據幀。

相關問題