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 сейчас.
Ответы
Ответ 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.