Estou tentando executar várias somas na mesma trama de dados e, em seguida, concatenar os novos dataframes em uma trama de dados de final. Existe uma maneira concisa de fazer isso, ou eu preciso usar iteração?
Eu tenho um dicionário desta forma {key: [list_of_idx], ...}
e precisa groupby minha trama de dados para cada chave.
Dados de amostra
import random
random.seed(1)
df_len = 5
df = {'idx':{i: i+1 for i in range(df_len)}, 'data':{i:random.randint(1,11) for i in range(df_len)}}
df = pd.DataFrame(df).set_index('idx')
# Groups with the idx to groupby
groups = {'a': [1,2,3,4,5],
'b': [1,4],
'c': [5]}
# I'm trying to avoid/find a faster way than this
dfs = []
for grp in groups:
_df = df.loc[groups[grp]]
_df['grp'] = grp
_df = _df.groupby('grp').sum()
dfs.append(_df)
dff = pd.concat(dfs)
Input (df)
data idx
0 2 1
1 10 2
2 9 3
3 3 4
4 6 5
saída esperada (DFF)
data
grp
a 30
c 6
b 5
Nota: Eu estou preso com Python 2.7 e pandas 0.16.1
resultado tempo
Eu testei os métodos propostos e calcular o tempo de execução. I mostram o tempo médio per execução (usando 1000 execuções para cada resposta): Eu couln't testar Quang Hoang primeira resposta, por causa da minha versão pandas.
time method
0.00696 sec my method (question)
0.00328 sec piRSquared (pd.concat)
0.00024 sec piRSquared (collections and defaultdict)
0.00444 sec Quang Hoang (2nd method : concat + reindex)
Inteligente uso de pd.concat
pd.concat({k: df.loc[v] for k, v in groups.items()}).sum(level=0)
data
a 22
b 8
c 2
NOTA: Este magicamente funciona para todas as colunas.
Suponha que temosmore_data
import random
random.seed(1)
df_len = 5
df = {
'idx':{i: i+1 for i in range(df_len)},
'data':{i:random.randint(1,11) for i in range(df_len)},
'more_data':{i:random.randint(1,11) for i in range(df_len)},
}
df = pd.DataFrame(df).set_index('idx')
Então
pd.concat({k: df.loc[v] for k, v in groups.items()}).sum(level=0)
data more_data
a 22 42
b 8 19
c 2 7
Mas eu ia ficar com mais Python: collections.defaultdict
from collections import defaultdict
results = defaultdict(int)
for k, V in groups.items():
for v in V:
results[k] += df.at[v, 'data']
pd.Series(results)
a 22
b 8
c 2
dtype: int64
Para que isso funcione com várias colunas, eu tenho que configurar o defaultdict
um pouco diferente:
from collections import defaultdict
results = defaultdict(lambda: defaultdict(int))
for k, V in groups.items():
for v in V:
for c in df.columns:
results[c][k] += df.at[v, c]
pd.DataFrame(results)
data more_data
a 22 42
b 8 19
c 2 7
Isto é o que ficaria sem defaultdict
, mas usando o método setdefault
do dict
objeto em seu lugar.
results = {}
for k, V in groups.items():
for v in V:
for c in df.columns:
results.setdefault(c, {})
results[c].setdefault(k, 0)
results[c][k] += df.at[v, c]
pd.DataFrame(results)
data more_data
a 22 42
b 8 19
c 2 7