Changer les valeurs dans les pandas DataFrame
j'ai un problème à changer les valeurs d'une base de données. Je veux également consulter au sujet d'un problème que je dois résoudre et la bonne façon d'utiliser les pandas pour le résoudre. Je vais apprécier aide sur les deux. J'ai un fichier contenant des informations sur le degré de correspondance des fichiers audio avec les haut-parleurs. Le fichier ressemble à quelque chose comme ça:
wave_path spk_name spk_example# score mark comments isUsed
190 122_65_02.04.51.800.wav idoD idoD 88 NaN NaN False
191 121_110_20.17.27.400.wav idoD idoD 87 NaN NaN False
192 121_111_00.34.57.300.wav idoD idoD 87 NaN NaN False
193 103_31_18.59.12.800.wav idoD idoD_0 99 HIT VP False
194 131_101_02.08.06.500.wav idoD idoD_0 96 HIT VP False
ce que je dois faire, c'est une sorte de comptage sophistiqué. J'ai besoin de grouper les résultats par orateur, et de calculer pour chaque orateur un certain calcul. Je passe ensuite à l'orateur qui a fait le meilleur calcul pour moi, mais avant de procéder je dois marquer tous les fichiers que j'ai utilisés pour le calcul comme étant utilisés, c.-à-d. changer la valeur isUsed pour chaque ligne dans laquelle ils apparaissent (les fichiers peuvent apparaître plus d'une fois) à TRUE. Puis je fais une autre itération. Calculer pour chaque haut-parleur, marquer les fichiers utilisés et ainsi de suite jusqu'à ce qu'il ne reste plus de haut-parleurs à calculer.
j'ai beaucoup réfléchi à la façon de mettre en œuvre ce processus en utilisant pandas (c'est assez facile à implémenter en python régulier mais cela va prendre beaucoup de bouclage et de structuration de données qui, à mon avis, va ralentir le processus de manière significative, et aussi j'utilise ce processus pour apprendre plus profondément les capacités des pandas)
je suis venu avec la solution suivante. Comme préparation, je vais Grouper par nom de haut-parleur et définir le nom du fichier comme index par la méthode set_index. Je vais ensuite itérer sur le groupbyObj et appliquer la fonction de calcul, qui retournera le haut-parleur sélectionné et les fichiers à être marqué comme utilisé.
puis je vais itérer les fichiers et les marquer comme utilisés (ce serait rapide et simple puisque je les ai mis en index à l'avance), et ainsi de suite jusqu'à ce que je finisse de calculer.
tout d'abord, je ne suis pas sûr de cette solution, alors n'hésitez pas à me dire ce que vous en pensez. Maintenant, j'ai essayé d'implémenter ceci, et j'ai eu des problèmes:
j'ai d'Abord indexé par le nom de fichier, pas de problème ici:
In [53]:
marked_results['isUsed'] = False
ind_res = marked_results.set_index('wave_path')
ind_res.head()
Out[53]:
spk_name spk_example# score mark comments isUsed
wave_path
103_31_18.59.12.800.wav idoD idoD 99 HIT VP False
131_101_02.08.06.500.wav idoD idoD 99 HIT VP False
144_35_22.46.38.700.wav idoD idoD 96 HIT VP False
41_09_17.10.11.700.wav idoD idoD 93 HIT TEST False
122_188_03.19.20.400.wav idoD idoD 93 NaN NaN False
Alors I choisissez un fichier et vérifié que je reçois les entrées pertinentes à ce fichier:
In [54]:
example_file = ind_res.index[0];
ind_res.ix[example_file]
Out[54]:
spk_name spk_example# score mark comments isUsed
wave_path
103_31_18.59.12.800.wav idoD idoD 99 HIT VP False
103_31_18.59.12.800.wav idoD idoD_0 99 HIT VP False
103_31_18.59.12.800.wav idoD idoD_1 97 HIT VP False
103_31_18.59.12.800.wav idoD idoD_2 95 HIT VP False
maintenant des problèmes ici aussi. Puis j'ai essayé de changer la valeur isUsed pour ce fichier en True, et là où j'ai eu le problème:
In [56]:
ind_res.ix[example_file]['isUsed'] = True
ind_res.ix[example_file].isUsed = True
ind_res.ix[example_file]
Out[56]:
spk_name spk_example# score mark comments isUsed
wave_path
103_31_18.59.12.800.wav idoD idoD 99 HIT VP False
103_31_18.59.12.800.wav idoD idoD_0 99 HIT VP False
103_31_18.59.12.800.wav idoD idoD_1 97 HIT VP False
103_31_18.59.12.800.wav idoD idoD_2 95 HIT VP False
Donc, vous voyez le problème. Rien n'a changé. Ce que je fais mal? Le problème décrit ci-dessus devrait-il être résolu en utilisant pandas?
Et aussi: 1. Comment puis-je approcher un groupe spécifique par un objet groupby? bcz j'ai pensé que peut-être au lieu de définir les dossiers comme indexés, groupant par un dossier, et l'utilisation de ce groupby obj pour appliquer une fonction changeante à tous ses événements. Mais je n'ai pas trouvé un moyen d'approcher un groupe spécifique et de passer le nom du groupe comme paramètre et appel s'appliquent sur tous les groupes et puis agir seulement sur l'un d'eux ne me semble pas "juste".
j'espère que c'est pas pour longtemps... :)
1 réponses
indexation les objets Panda peuvent retourner deux objets fondamentalement différents: une vue ou une copie.
Si mask
est une tranche de base, puis df.ix[mask]
retourne un viewdf
. Les vues partagent les mêmes données sous-jacentes que l'objet original (df
). Donc modifier la vue, modifie aussi l'objet original.
Si mask
est quelque chose de plus compliqué, comme une séquence arbitraire d'indices, puis df.ix[mask]
retourne un copier de certains lignes df
. Modifier la copie n'a aucun effet sur l'original.
Dans votre cas, puisque les lignes qui partagent le même wave_path
se produisent à des endroits arbitraires,ind_res.ix[example_file]
renvoie une copie. Donc
ind_res.ix[example_file]['isUsed'] = True
n'a aucun effet sur ind_res
.
a la place, vous pouvez utiliser
ind_res.ix[example_file, 'isUsed'] = True
modifier ind_res
. Cependant, voir ci-dessous pour un groupby
suggestion qui je pense pourrait être plus proche de ce que vous voulez vraiment.
Jeff a déjà à condition a lien vers les Pandas docs état
Les règles sur le moment où une vue sur les données retournées sont entièrement ça dépend de NumPy.
Voici le (compliqué) règles qui décrivent lorsqu'une vue ou une copie est renvoyée. Fondamentalement, cependant, la règle est si l'index demande une tranche régulièrement espacée du tableau sous-jacent puis une vue est retournée, sinon une copie (par nécessité) est retourner.
voici un exemple simple qui utilise la tranche de base. Une vue est retournée par df.ix
, et modifier subdf
modifie df
ainsi:
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(4,3),
columns=list('ABC'), index=[0,1,2,3])
subdf = df.ix[0]
print(subdf.values)
# [0 1 2]
subdf.values[0] = 100
print(subdf)
# A 100
# B 1
# C 2
# Name: 0, dtype: int32
print(df) # df is modified
# A B C
# 0 100 1 2
# 1 3 4 5
# 2 6 7 8
# 3 9 10 11
voici un exemple simple qui utilise "l'indexation de fantaisie" (lignes arbitraires sélectionnées). Une copie est renvoyée par df.ix
. C'est pourquoi modifier subdf
n'affecte pas df
.
df = pd.DataFrame(np.arange(12).reshape(4,3),
columns=list('ABC'), index=[0,1,0,3])
subdf = df.ix[0]
print(subdf.values)
# [[0 1 2]
# [6 7 8]]
subdf.values[0] = 100
print(subdf)
# A B C
# 0 100 100 100
# 0 6 7 8
print(df) # df is NOT modified
# A B C
# 0 0 1 2
# 1 3 4 5
# 0 6 7 8
# 3 9 10 11
Avis la seule différence entre les deux exemples est que dans le premier, où un la vue est retourné, l'indice a été [0,1,2,3], tandis que dans le second, dont une copie est retourné, l'indice a été [0,1,0,3].
puisque nous sommes des lignes sélectionnées où l'index est 0, dans le premier exemple, nous pouvons le faire avec une tranche de base. Dans le deuxième exemple, les lignes où index égale 0 peuvent apparaître à des endroits arbitraires, donc une copie doit être retournée.
en dépit d'avoir crié sur la subtilité des Pandas / découpage de pépins, Je ne pense vraiment pas que
ind_res.ix[example_file, 'isUsed'] = True
est ce que vous cherchez en fin de compte. Vous voulez probablement faire quelque chose de plus comme
import pandas as pd
import numpy as np
df = pd.DataFrame(np.arange(12).reshape(4,3),
columns=list('ABC'))
df['A'] = df['A']%2
print(df)
# A B C
# 0 0 1 2
# 1 1 4 5
# 2 0 7 8
# 3 1 10 11
def calculation(grp):
grp['C'] = True
return grp
newdf = df.groupby('A').apply(calculation)
print(newdf)
ce qui donne
A B C
0 0 1 True
1 1 4 True
2 0 7 True
3 1 10 True