J'essaie de convertir toutes les valeurs de mon ensemble de données en valeurs catégorielles, je veux que toutes les valeurs numériques soient catégorisées en faible, moyenne ou élevée dépend de leurs valeurs de quantile.
Donc, si la valeur est inférieure à 25% la série, elle sera convertie en "Low"
J'ai essayé d'utiliser assign puis appliqué une fonction que je fournis:
Year Month Central Equatoria Eastern Equatoria Gogrial Jonglei 0 2014 10 High Medium Low Medium 1 2014 11 Low Medium Low high
Cependant, le le code ne fonctionne pas bien. Je l'ai également essayé via iterrows mais je me demande s'il existe un moyen plus rapide de le faire?
Voici les données que je voulais convertir, tous les nombres hors année et mois doivent être classés en bas, moyen Élevé, en fonction de leur valeur quantile.
Year Month Central Equatoria Eastern Equatoria Gogrial Jonglei 0 2014 10 6.0 1.0 0.0 3.0 1 2014 11 4.0 3.0 0.0 12.0 2 2014 12 3.0 5.0 0.0 11.0 3 2015 1 7.0 2.0 0.0 4.0 4 2015 2 5.0 5.0 0.0 10.0 5 2015 3 7.0 5.0 0.0 8.0 6 2015 4 4.0 1.0 0.0 6.0 7 2015 5 5.0 0.0 0.0 7.0 8 2015 6 4.0 1.0 0.0 6.0 9 2015 7 15.0 2.0 0.0 9.0 10 2015 8 10.0 7.0 0.0 9.0 11 2015 9 12.0 0.0 0.0 8.0 12 2015 10 12.0 0.0 0.0 5.0 13 2015 11 8.0 5.0 0.0 10.0 14 2015 12 5.0 7.0 0.0 3.0
Résultat attendu: (Exemple)
def turn_into_categorical(row): quantile_level = [.25, .5, .75] for r in row: cut = refugees_T_F_V_P_full_data.r.quantile(quantile_level) if r >= cut[.75]: return "High" elif r >= cut[.25] and r < cut[0.75]: return "Average" else: return "Low" refugees_T_F_V_P_full_data.apply(turn_into_categorical, axis = 1)
4 Réponses :
Une idée utilisant pd.DataFrame.quantile
avec pd.Series.cut
:
print(df) Year Month CentralEquatoria EasternEquatoria Gogrial Jonglei 0 2014 10 Medium Low Low Low 1 2014 11 Low Medium Low High 2 2014 12 Low Medium Low High 3 2015 1 Medium Medium Low Low 4 2015 2 Medium Medium Low High 5 2015 3 Medium Medium Low Medium 6 2015 4 Low Low Low Medium 7 2015 5 Medium Low Low Medium 8 2015 6 Low Low Low Medium 9 2015 7 High Medium Low Medium 10 2015 8 High High Low Medium 11 2015 9 High Low Low Medium 12 2015 10 High Low Low Low 13 2015 11 Medium Medium Low High 14 2015 12 Medium High Low Low
Résultat:
XXX
Si l'OP est prêt à prendre des étiquettes int et non des chaînes, nous pourrions vectoriser cela, je pense. J'essaye juste de finaliser une idée
@roganjosh, pd.cut
Je crois qu'il est entièrement vectorisé, les séries "string" à la fin sont en fait des catégoriques efficaces, c'est-à-dire soutenues par des tableaux d'entiers.
Ah merde, j'ai vu la boucle for
et je l'ai mal lu! J'allais pour np.digitize
. Vous avez raison AFAIK.
J'ai essayé le code mais il renvoie la même erreur qui m'a eue lorsque j'ai essayé le code de @ yatu ValueError: Les bords du bac doivent être uniques: array ([0., 0., 5., 26.]). Vous pouvez supprimer les arêtes en double en définissant le kwarg "duplicates"
On dirait que vous voulez pd.qcut
, qui fait précisément cela. À partir de la documentation:
Fonction de discrétisation basée sur les quantiles
Vous pourriez donc appliquez
pd.qcut
le long des colonnes du dataframe à partir de Central Equatoria
, en spécifiant les quantiles que vous souhaitez utiliser la série avec q = [0, 0.25, 0.75, 1.0]
Central Equatoria Eastern Equatoria Gogrial Jonglei 0 medium low low low 1 low medium low high 2 low medium low high 3 medium medium low low 4 medium medium low high 5 medium medium low medium 6 low low low medium 7 medium low low medium 8 low low low medium 9 high medium low medium 10 high high low medium 11 high low low medium 12 high low low low 13 medium medium low high 14 medium high low low
Sortie
df.loc[:,'Central Equatoria':].apply(lambda x: pd.qcut(x, q=[0, 0.25, 0.75, 1.0], labels =['low','medium','high']) if not x.nunique() == 1 else 'low'))
Meilleure solution que la mienne :) .. en gros, cela combine les méthodes Pandas quantile
et cut
.
Oui, il se range directement en utilisant les informations quantiles. Merci :)
J'ai essayé d'implémenter le vôtre et le code de @jpp, mais il semble que la fonction pd.qcut renvoie toujours l'erreur ValueError: ("Les bords du bac doivent être uniques: array ([0., 0., 2., 7.]). \ NVous pouvez supprimer les arêtes en double en définissant le 'doublons' kwarg ", 'survenu à l'index Northern Bahr el Ghazal')
J'ai essayé de rechercher une solution pour cela à partir d'ici lien et j'ai ajouté un argument duplicates = 'drop'
, mais il renvoie toujours ValueError: ('Les étiquettes de casier doivent être un de moins que le nombre d'arêtes', 's'est produite à l'index du Bahr el Ghazal du Nord') code>
le code complet est ici réfugiés_T_F_V_P_full_data.iloc [:, 2:]. apply (lambda x: pd.qcut (x, duplicates = 'drop', q = [0, 0.25, 0.75, 1.0], labels = [' faible ',' moyen ',' élevé ']) sinon x.nunique () == 1 sinon' faible ')
L'ensemble de données pour cette question peut être trouvé ici sur GitHub: lien < / a>
Je ne peux malheureusement pas vérifier maintenant, jettera un coup d'œil plus tard
Les bords du bac doivent être uniques: array ([0., 0., 2., 7.])
est clair. Vous avez 0
deux fois. Comment pouvez-vous bin des valeurs entre 0 et 0? Il existe un hack rapide pour résoudre ce problème, mais vous comprendrez mieux comment vous avez des valeurs en double dans vos bacs.
Utilisation de pd.cut ()
et df.apply()
:
df.iloc[:,2:]=df.iloc[:,2:].apply(lambda x:pd.cut(x, 3, labels=['Low','Med','High']), axis=1) Year Month Central_Equatoria Eastern_Equatoria Gogrial Jonglei 0 2014 10 High Low Low Med 1 2014 11 Low Low Low High 2 2014 12 Low Med Low High 3 2015 1 High Low Low Med 4 2015 2 Med Med Low High 5 2015 3 High Med Low High
Finit par utiliser la mode la plus ancienne:
new_df = pd.DataFrame() name_list = list(df) for name in name_list: if name != 'Year' and name != 'Month': new_row = [] quantiles = df[name].quantile([.25, .5, .75]) row_list = df[name].tolist() for i, value in enumerate(row_list): if value < quantiles[.25]: new_row.append("Low") elif value < quantiles[.75] and value >= quantiles[.25]: new_row.append("Average") else: new_row.append("High") series = pd.Series(new_row) new_df[name] = series.values new_df.head()
En guise de commentaire, c'est une question bien écrite avec un problème intéressant - merci!