2
votes

Python numpy - index d'affectation de liste hors limites

J'ai un fichier CSV au format suivant

import numpy as np
import pandas as pd
import csv

df = pd.read_csv("testdata.csv")
with open("testdata.csv") as f:
    reader = csv.reader(f, delimiter=",")
    for i in reader:
        print (i[0])
        diffs=np.diff(i[0])
        increased_value=np.median(diffs[diffs>0])

Pour la reproductibilité, j'ai inclus le fichier complet fichier CSV ici . À partir de la colonne 1, je voulais lire la ligne actuelle et la comparer avec la valeur de la ligne précédente. Si elle est supérieure, je voulais prendre la différence de la valeur actuelle par rapport à la précédente et stocker ( ajouter ) la différence dans une liste. Si la valeur actuelle est égale à la valeur de la ligne précédente, continuez la comparaison. Par exemple, dans l'exemple d'enregistrement ci-dessus que j'ai fourni, la troisième ligne ( 19 ) est supérieure à la valeur de la deuxième ligne ( 15 ) - donc ce sera ( 19-15 = 4 ), la quatrième ligne ( 52-19 = 33 ), etc.

Voici mon approche simple en utilisant numpy

86,1
15,2
19,3
52,4
15,5
13,6
18,7
20,8
49,9
266,10

Cependant, j'obtiens l'erreur IndexError: index d'assignation de liste hors limites . Comment puis-je corriger cette erreur afin de résoudre la tâche que j'ai mentionnée?


2 commentaires

y a-t-il des lignes vides dans votre fichier csv?


NON, il n'y a PAS de lignes vides dans le fichier CSV.


6 Réponses :


3
votes

Je pense que c'est une meilleure façon

df = pd.read_csv("testdata.csv", header=None)
df
     0     1
0   86     1
1   15     2
2   19     3
3   52     4
4   15     5
5   13     6
6   18     7
7   20     8
8   49     9
9   266   10

diffs = np.diff(df[0])
increased_value = np.median(diffs[diffs>0])
increased_value

17.0


6 commentaires

C'est génial! Cependant, si vous imprimez diffs , cela donne array ([- 71, 4, 33, -37, -2, 5, 2, 29, 217]) . Comment pouvons-nous garder les nombres négatifs hors de la liste? Parce que je veux garder allumé UNIQUEMENT, la valeur actuelle est supérieure à la valeur de la ligne précédente.


diffs = diffs [diffs> 0] si vous souhaitez supprimer les valeurs négatives ou diffs [diffs <0] = 0 si vous souhaitez les remettre à zéro.


Et si je veux le faire dans le sens inverse? Cela signifie que lorsque la valeur de la ligne actuelle est inférieure à la valeur de la ligne précédente? Je l'ai fait comme ceci: np.median (diffs [diffs> 0]) mais les valeurs de la liste de tableaux que j'obtiens sont des nombres négatifs - [-71 - 37 -2] -37,0


diffs = np.diff (df [0]) * - 1 renvoie` [71, -4, -33, 37, 2, -5, -2, -29, -217] `< code> np.median (diffs [diffs> 0]) devrait retourner 37.0 Est-ce ce que vous espériez?


@AnanayMital, NON - la partie croissante comme vous l'avez fait dans votre réponse est correcte. Mais j'essayais de faire le contraire de la question que j'ai posée - que se passe-t-il si nous voulions le faire lorsque la valeur actuelle est plus petite que la valeur précédente? Pour cela (la partie inverse), je m'attendais à obtenir [-71 -37-2] et une valeur médiane de -37.0 .


ouais donc c'est juste np.median (diffs [diffs <0]) . Droite?



0
votes

En gros, np.diff () attend une liste comme une entrée, et ce que vous passez est un entier. C'est la raison pour laquelle il échoue


0 commentaires

0
votes

Nous n'avons techniquement pas besoin de numpy

from statistics import median
from operator import itemgetter, lt, sub

first = itemgetter(0)
nums = []

with open('testdata.csv', 'r') as fin:
    reader = csv.reader(fin)
    for line in reader:
        nums.append(int(first(line)))

res = [abs(sub(*t)) for t in zip(nums, nums[1:]) if lt(*t)]

[4, 33, 5, 2, 29, 217]

median(res)

17.0


5 commentaires

Mais l'utilisation de numpy, comme le montre Ananay Mital, est dans 99% des cas préférable à l'utilisation de listes pour les données numériques.


cela dépend du cas d'utilisation mais dire que 99% des cas est une sur-portée, ces petites données sont triviales, nous pouvons être d'accord pour ne pas être d'accord


C'est super mais la ligne res = [abs (sub (* t)) pour t dans zip (nums, nums [1:]) si lt (* t)] dit Syntaxe invalide sur Python3


@aws_apprentice, d'où vient le 5 dans la liste [4, 33, 5, 2, 29, 217] ? Je suis confus. Si je le fais manuellement, j'obtiens 5 valeurs à la place.


@Brown, les exemples de données que vous avez fournis ont 13, puis 18, d'où le 5



0
votes

La raison pour laquelle vous obtenez

IndexError: index d'affectation de liste hors de portée

est np. diff () prenant l'entrée comme un tableau ou une liste.

Comme

arr = []
df = pd.read_csv("testdata3.csv")
df
with open("testdata3.csv", mode='r', encoding='utf-8-sig') as f:
    reader = csv.reader(f, delimiter=",")
    for i in reader:
#         print(i[0])
        arr.append(int(i[0]))

diffs=abs(np.diff(arr))
increased_value=np.median(diffs[diffs>0])


1 commentaires

Et si je veux le faire dans le sens inverse? Cela signifie que lorsque la valeur de la ligne actuelle est inférieure à la valeur de la ligne précédente? Je l'ai fait comme ceci: np.median (diffs [diffs> 0]) mais les valeurs de la liste de tableaux que j'obtiens sont des nombres négatifs - [-71 - 37 -2] -37,0



1
votes

Utilisation de pandas s.diff ( ) :

data = StringIO("""86,1
15,2
19,3
52,4
15,5
13,6
18,7
20,8
49,9
266,10""")

df=pd.read_csv(data,header=None)

m1=df[0].diff().fillna(0)
#m1[m1>0].tolist()
#[4.0, 33.0, 5.0, 2.0, 29.0, 217.0]
m1[m1>0].median()
#17.0


0 commentaires

0
votes

Le problème que vous rencontrez est que lorsque vous essayez d'exécuter np.diff, le dtype par défaut de votre tableau est dtype U3, ce qui signifie que les valeurs de votre tableau ne sont pas des nombres, ce qui signifie qu'une conversion est nécessaire. Essayez ce qui suit:

with open("test_data.csv", "r") as f:
    reader = csv.reader(f) ## no need for delimiter if your delimiter is ','
    data = []
    for row in reader:
        data.append(row[0])

## ensure that you convert your data into numpy array with appropriate data type 
## before carrying out any mathematical operations 

np_array = np.array(data, dtype=np.uint8) 
np_diff = np.diff(np_array)
np_median = abs(np.median(np_diff[np_diff > 0]))

print(np_median)

Si vous devez le faire régulièrement, vous pouvez toujours encapsuler une méthode. Essayez ceci.


7 commentaires

Et si je veux le faire dans le sens inverse? Cela signifie que lorsque la valeur de la ligne actuelle est inférieure à la valeur de la ligne précédente? Je l'ai fait comme ceci: np.median (diffs [diffs> 0]) mais les valeurs de la liste de tableaux que j'obtiens sont des nombres négatifs - [-71 - 37 -2] -37,0


Vous attendez-vous à ce que votre résultat soit positif à tout moment?


Oui, je m'attends à ce que tous mes résultats soient positifs.


Je viens de faire une mise à jour pour inclure abs dans la variable np_median qui rendra tous les résultats positifs.


il imprime la liste entière array ([185, 4, 33, 219, 254, 5, 2, 29, 217], dtype = uint8) ce que je ne pense pas être juste. Pour la partie croissante, il ne doit imprimer que [4, 33, 5, 2, 29, 219] à la place. La question que j'ai posée dans mon premier commentaire à votre réponse doit également être imprimée [-71 -37-2]


Désolé pour la réponse tardive. J'ai juste essayé d'utiliser une liste ordinaire contenant vos nombres, c'est-à-dire data = [(86,1), (15,2), (19,3), (52,4), (15,5), (13,6), (18,7), (20,8), (49,9), (266,10)] puis en boucle pour obtenir la liste a = [86, 15, 19, 52, 15, 13, 18, 20 , 49, 266]. J'ai ensuite converti cela en tableau numpy puis appliquer diff pour obtenir un tableau ([185, 4, 33, 219, 254, 5, 2, 29, 217], dtype = uint8). À partir de là, j'ai utilisé abs (np.median (np_diff [np_diff> 0])) ce qui me donne 33,0. Pour que votre commentaire sur la valeur actuelle soit inférieure à la valeur précédente, vous devrez trier vos données, c'est-à-dire triées (données).


le diffs [diffs> 0] n'est qu'un filtre et ne vous indique pas réellement si la valeur de la ligne actuelle est inférieure à la valeur de la ligne précédente. Vous devrez faire une boucle pour cela.