J'ai le dataframe suivant
A_key Date Distance A1 2016-05-03 145 A1 2016-09-25 145 A2 2015-02-25 0 A2 2015-02-25 0 A3 2015-10-04 163 A3 2016-03-15 26 A3 2016-04-10 26 A4 2015-09-26 0 A4 2015-09-26 0
Je veux obtenir la distance du voisin le plus proche pour chaque A_key distincte en unités de jours pour n_nequart (k) = 1 de sorte que la sortie ressemble à ce qui suit
A_key Date A1 2016-05-03 A1 2016-09-25 A2 2015-02-25 A2 2015-02-25 A3 2015-10-04 A3 2016-03-15 A3 2016-04-10 A4 2015-09-26 A4 2015-09-26
4 Réponses :
Cette base sur le groupby
pour diviser votre df d'origine en petite trame de données clé unique, puis nous utilisons la diffusion numpy
pour accélérer l'ensemble du calcul
df.Date=pd.to_datetime(df.Date) l=[] for _, x in df.groupby('A_key'): s=np.abs((x['Date'].values - x['Date'].values[:,None])).astype('timedelta64[D]').astype(int) s[[np.arange(len(s))] * 2]=9999 l.append(np.min(s,1)) df['New']=np.concatenate(l) df Out[501]: A_key Date New 0 A1 2016-05-03 145 1 A1 2016-09-25 145 2 A2 2015-02-25 0 3 A2 2015-02-25 0 4 A3 2015-10-04 163 5 A3 2016-03-15 26 6 A3 2016-04-10 26 7 A4 2015-09-26 0 8 A4 2015-09-26 0
Pourquoi le deuxième A3 26 au lieu de 163? Je veux dire que c'est la même chose que la sortie des OP, mais ne comprends pas pourquoi il en est ainsi
@yatu mélange de différents parmi toutes les dates différentes
@yatu, ce n'est pas aussi simple que groupby et diff. L'OP veut le point le plus proche de chaque point d'un groupe
Ah, prenez maintenant l'idée de plus proche
, compris. Merci
@ W-B, grande utilisation du remodelage de tableau
Juste un petit avertissement concernant ce code, prenez la première ligne de A3 et déplacez-la à la fin du DataFrame, puis exécutez la méthode, vous verrez que le résultat est faux. Afin de ne pas avoir de surprise en utilisant ce code, vous devez d'abord trier par A_key et ne vous souciez pas de votre index actuel (car l'ordre résultant sera basé en fonction du groupe pris par la méthode groupby)
@abcdaire le trie avant de faire ma méthode
Oui, mais même si vous triez, si votre index d'origine est significatif pour vous, il sera perdu, je veux juste vous en avertir :) Mais belle méthode!
@abcdaire cela peut être résolu, enregistrez l'index d'origine sous idx, puis sort_values avec A_Key, puis faites ce que je fais ci-dessus, puis réindexez avec idx pour la trame de données de sortie
Vous pouvez convertir les dates en Epoch en utilisant ce code:
import time date_time = '2016-05-03 00:00:00' pattern = '%Y-%m-`enter code here`%d %H:%M:%S' epoch = int(time.mktime(time.strptime(date_time, pattern)))
Ensuite, soustrayez simplement la valeur de sa valeur voisine. Notez que le résultat sera en millisecondes, vous devrez donc diviser par (1000 * 60 * 60 * 24) pour le convertir en jours.
Vous avez déjà trié par date dans chaque clé. Il vous suffit donc de calculer la distance entre la date suivante et la date précédente dans la même clé. J'ai essayé ceci (en Swift) pour calculer la distance entre 2 dates au format 2015-05-22
func dist(_ d1: String, _ d2: String) -> Int { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "YYYY-MM-DD" if let date1 = dateFormatter.date(from: d1), let date2 = dateFormatter.date(from: d2) { let distance = date1.timeIntervalSince(date2) / 86400 return abs(Int(distance)) } else { return 0 } } print(dist("2015-05-25", "2015-05-22"))
Vous pouvez maintenant parcourir les valeurs dans une clé pour calculer la distance minimale pour une donnée donnée clé (sauf elle-même bien sûr)
Merci, mais ce n'est pas seulement la distance entre des dates consécutives, pour une A_key donnée s'il y a trois enregistrements, pour chaque enregistrement, calculez sa distance dans le temps avec les deux autres et choisissez le minimum qui représente la distance du voisin le plus proche
À droite, sauf si le tableau est déjà commandé; alors besoin de comparer avec les dates précédentes et suivantes (si elles existent) seulement; tous les autres seront plus loin que celui-ci; et comme abcdaire recherche le plus proche…
Bonjour, voici une solution possible en utilisant uniquement Pandas
Donnons un nom à l'index actuel (pour plus de commodité et pour être sûr que nous récupérons bien tout)
result_df =sorted_df.groupby('A_key').apply(nearest_date_distance).reset_index(level=0) A_key Distance id 0 A1 145 days 1 A1 145 days 2 A2 0 days 3 A2 0 days 4 A3 163 days 5 A3 26 days 6 A3 26 days 7 A4 0 days 8 A4 0 days
Nous vont d'abord trier par date et appliquer une fonction à chaque groupe, il est important de noter que nous allons nous appuyer sur le fait que les pandas conservent l'ordre des lignes à l'intérieur d'un groupe (voir documentation)
A_key id A1 0 145 days 1 145 days A2 2 0 days 3 0 days A3 4 163 days 5 26 days 6 26 days A4 7 0 days 8 0 days
Voyons maintenant ce que nous avons à l'intérieur la fonction plus proche_date_distance
La fonction repose sur le fait que la date sera triée, donc nous calculons l'heure à la date avant et l'heure à la date après, la différence entre le jour en cours et le jour suivant est négative c'est pourquoi nous ajoutons le .abs ()
.Enfin, nous prenons le minimum entre ces deux distances (btw l'opérateur min ne prendra pas la valeur manquante (NaT) que vous avez pour la première ligne de time_to_before et la dernière ligne de time après)
def nearest_date_distance(sub): time_to_before = sub['Date'].diff() time_to_after = sub['Date'].diff(-1).abs() nearest_date_distance = pd.concat([time_to_before, time_to_after],axis=1).min(axis=1) nearest_date_distance.name = 'Distance' return nearest_date_distance
Enfin j'ai menti un peu result_df
sera une série MultiIndex (pas une dataframe) de cette forme:
sorted_df = sorted_df = df.sort_values('Date') result_df = sorted_df.groupby('A_key').apply(nearest_date_distance)
Nous pouvons facilement le convertir en DataFrame et avoir un nom approprié pour notre index d'origine permet de voir que tout est indexé de la même manière que dans le df d'origine.
df['Date'] = df['Date'].astype('datetime64[ns]') df.index.name = 'id'
mmm pourquoi le deuxième A3 n'est pas 163? Quels critères utilisez-vous pour cela?