Подтвердить что ты не робот

Pandas: применить функцию к DataFrame, которая может возвращать несколько строк

Я пытаюсь преобразовать 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 

Это противоположность агрегации с функцией count. Есть ли простой способ достичь этого в pandas (без использования для циклов или списков)?

Одна из возможностей может заключаться в том, чтобы позволить функции DataFrame.applymap возвращать несколько строк (метод akin apply GroupBy). Тем не менее, я не думаю, что это возможно в pandas сейчас.

4b9b3361

Ответ 1

Вы можете использовать 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

Вы можете исправить индекс результата, но вам нравится

Ответ 2

Я знаю, что это старый вопрос, но у меня возникли проблемы с получением ответа Уэса на работу для нескольких столбцов в dataframe, поэтому я сделал его код более универсальным. Думал, что я поделюсь тем, что кто-то еще споткнется на этот вопрос с той же проблемой.

В основном вы указываете, в каком столбце есть счетчики, и вы получаете расширенный кадр данных в ответ.

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 секунд.

Ответ 3

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]})

Ответ 4

Этот вопрос очень старый, и ответы не отражают современных возможностей pandas. Вы можете использовать iterrows для циклического перехода по каждой строке, а затем использовать конструктор DataFrame для создания новых DataFrames с правильным количеством строк. Наконец, используйте 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.