Mon dataframe ressemble à ceci:
df.groupby(['date','id'])['id'].unique().value_counts() df.groupby(['date','id'])['id'].count()
Je voudrais l'écrire avec les colonnes 'target', 'source', 'weights', où: «cible» et «source» sont toutes deux des «identifiants» et «pondérations» compte sur le nombre de jours pendant lesquels le prix «cible» et «source» a changé simultanément. Cela ressemblerait donc à:
target source weights 60059 60060 2 60059 60076 1 60060 60076 1
Mon objectif est d'utiliser ce dataframe pour créer un graphique networkx.
J'ai essayé d'utiliser groupby
date id pct_change 12355258 2010-07-28 60059 0.210210 12355265 2010-07-28 60060 0.592000 12355282 2010-07-29 60059 0.300273 12355307 2010-07-29 60060 0.481982 12355330 2010-07-28 60076 0.400729
et les boucles for (qui étaient terribles).
J'ai l'impression de manquer un petit pas dans le groupby, mais je ne pourrais pas dire ce qui manquait.
Merci pour votre aide.
4 Réponses :
L'idée est d'utiliser d'abord un pivto_table
pour obtenir True si l'id a un pct_change pour chaque date
# get all combinations of ids from itertools import combinations a, b = map(list, zip(*combinations(df_.index, 2))) res = (pd.DataFrame({'target':a, 'source':b}) .assign(weigths=(df_.loc[a].to_numpy() &df_.loc[b].to_numpy() ).sum(axis=1)) ) print(res) target source weigths 0 60059 60060 2 1 60059 60076 1 2 60060 60076 1
Ensuite, vous pouvez utiliser combinaison de
itertools
pour créer toutes les paires possibles, utilisez-les pour sélectionner les lignes et utilisez l'opérateur &
pour voir où les deux ont Vrai à la même date, additionnez le long de la colonnes (récupérez la colonne des poids). Attribuez cette colonne au Dataframe créé à partir des deux listes de combinaisons.
#first pivot to get True if any value of id for a date df_ = df.pivot_table(index='id', columns='date', values='pct_change', aggfunc=any, fill_value=False) print(df_) date 2010-07-28 2010-07-29 id 60059 True True 60060 True True 60076 True False
Remarque: n'oubliez pas de changer le index = 'id'
dans le pivot_table
avec le nom de votre colonne catégorielle, sinon il y a de fortes chances que votre ordinateur ne puisse pas gérer les opérations suivantes et planter
essayez ceci
import pandas as pd, numpy as np ids = df.id.unique() WeightDf = pd.DataFrame(index=ids, columns=ids) WeightDf.loc[:, :] = 0 def weigh(ID): IdDates = set(df.loc[df.id==ID].date.to_list()) for i in ids: WeightDf.at[ID, i] = len(set.intersection(set(df.loc[df.id==i].date.to_list()), IdDates)) pd.Series(ids).apply(weigh) print(WeightDf) import itertools as itt result = pd.DataFrame(columns=['Id1', 'Id2', 'Weight']) for i1, i2 in itt.combinations(ids, 2): result = pd.concat([result, pd.DataFrame(data=[{'Id1':i1, 'Id2':i2,'Weight':WeightDf.loc[i1, i2]}])]) print(result)
Cela crée une matrice, pas vraiment les colonnes cible, source, pondérations.
Merci! Je me demandais s'il serait possible de le faire avec la variable «id» qui a 24800 observations? Je ne sais pas si l'utilisation de combinaisons est possible avec un si grand nombre. Pensez-vous que ce soit le cas?
Ce sera possible parce que, vous pourriez avoir 24800 observations, mais, vous aurez moins d ' IDS uniques
Vu de nombreuses variantes de ce cas d'utilisation - génération de combinaisons
weights target source 2 60059 60060 1 60059 60076 1 60060 60076
sortie
import itertools df = pd.read_csv(io.StringIO(""" date id pct_change 12355258 2010-07-28 60059 0.210210 12355265 2010-07-28 60060 0.592000 12355282 2010-07-29 60059 0.300273 12355307 2010-07-29 60060 0.481982 12355330 2010-07-28 60076 0.400729"""), sep="\s+") # generate combinations of two... edge case when a group has only one member # tuple of itself to itself dfx = (df.groupby('date').agg({"id": lambda s: list(itertools.combinations(list(s), 2)) if len(list(s))>1 else [tuple(list(s)*2)]}) .explode("id") .groupby("id").agg({"id":"count"}) .rename(columns={"id":"weights"}) .reset_index() .assign(target=lambda dfa: dfa["id"].apply(lambda s: s[0]), source=lambda dfa: dfa["id"].apply(lambda s: s[1])) .drop(columns="id") ) print(dfx.to_string(index=False))
12177535 lignes, 24800 identifiants individuels
Le problème avec autant d'identifiants individuels si vous voulez toutes les combinaisons de 2 identifiants, vous obtenez quelque chose comme 300 millions de lignes et j'ai le sentiment que les pandas auront du mal à effectuer des opérations comme celle-ci, même en stockant le résultat avec une mémoire informatique "normale" c'est probablement trop
J'ai une variable alternative dans l'ensemble de données qui a 26 catégories au lieu de 24800. Serait-ce faisable?
Merci beaucoup!
désolé de déranger à nouveau ... sauriez-vous un moyen de le faire pour les «id»? Avec la variable «catégorie», le réseau était entièrement connecté et je ne peux pas faire une analyse plus approfondie.
cela a du sens avec seulement 26 catégories au lieu de 25K identifiants, en particulier avec autant de dates, vous obtenez un réseau entièrement connecté. honnêtement, je ne suis pas sûr que ce soit possible avec autant de données sur un ordinateur. Pardon
Merci quand même! Je pensais qu'il serait peut-être possible de faire la même chose que vous avez fait sur pyspark, mais je ne suis pas sûr.
peut être. J'en ai fait avant et je sais que le pivot existe, mais le reste je ne suis pas sûr.