2017-09-28 3 views
0

J'ai une base de données pandas où les cellules dans les colonnes ont plusieurs valeurs et sont séparées par ';'. J'essaie de diviser les valeurs multiples (dans une cellule) et créer de nouvelles lignes pour ceux qui se séparent. Quelque chose comme l'exemple ci-dessous:Python (Jupyter Notebook): Pandas copiant l'index de données causant la longueur de la valeur ne correspondant pas à la longueur de l'erreur d'index

> In: df 
> Out: 
| Year | State | Ingredient | Species | 
| 1998 | CA | egg; pork | sp1;sp2 | 

Le résultat que je suis en train de réaliser ressemble à ceci:

> In: df 
> Out: 
| Year | State | Ingredient | Species | 
| 1998 | CA | egg  | sp1  | 
| 1998 | CA | egg  | sp1  | 
| 1998 | CA | pork  | sp2  | 
| 1998 | CA | pork  | sp2  | 

j'ai trouvé une méthode pour diviser la trame de données comme celui-ci, mais il fonctionne qu'une seule fois. Le code j'est présenté ci-dessous:

sp = df['Species'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
i = sp.index.get_level_values(0) 
df1 = df.loc[i].copy() 
df1['Species] = sp.values 

Lorsque j'exécute ceci sur la colonne « espèces » d'abord, en utilisant la trame de données d'origine (df), cela fonctionne.

Cependant, lorsque j'exécute à nouveau ce code sur df1, en essayant de séparer tous les 'Ingrédients', cela me donne une erreur en disant que longueur ne correspond pas à la longueur de l'index. Comme indiqué ci-dessous:

fd = df1['Ingredient'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
j = fd.index.get_level_values(0) 
df2 = df1.loc[j].copy() 
df2['Ingredient'] = fd.values 

Je l'ai fait beaucoup d'essais pour trouver pourquoi il renvoie ce message d'erreur pour moi, et j'ai réalisé que quand j'exécute cette appelé à nouveau sur DF1 pour créer DF2, il double le nombre de lignes/index lorsque j'exécute df2 = df1.loc [j] .copy(). Par conséquent, en me donnant plus de lignes que j'ai besoin. Cependant, si je substitue 'df1' avec 'df' (l'image originale) alors cette erreur n'apparaît pas et cela fonctionne.

Existe-t-il une solution pour résoudre ce problème? Ou y a-t-il un autre moyen de le diviser?

Merci.

ps. C'est ma première fois sur Stack Overflow, et je suis aussi nouveau sur Python. Désolé si le formatage est mauvais.

Répondre

1

J'ai essayé votre problème. Je n'ai pas été capable de résoudre le problème dans votre approche. J'ai été capable de trouver une autre approche puisque vous avez fourni le résultat attendu. J'espère que c'est concis et résout votre problème.

df = pd.DataFrame(columns=['Year', 'State', 'Ingredient', 'Species']) 
df.loc[0] = [1998, 'CA', 'egg; pork', 'sp1;sp2'] # Same input df as problem 
print df 
sp = df['Species'][0].split(';') # Separating by species 
df = pd.concat([df]*len(sp), ignore_index=True) # Add len(sp) more rows 
df['Species'] = sp 
ing = df['Ingredient'][0].split(';') 
df = pd.concat([df]*len(ing), ignore_index=True) 
df['Ingredient'] = ing*len(sp) # Replicate ingredient len(sp) number of times 
print df 
    Year State Ingredient Species 
0 1998 CA egg; pork sp1;sp2 
    Year State Ingredient Species 
0 1998 CA  egg  sp1 
1 1998 CA  pork  sp2 
2 1998 CA  egg  sp1 
3 1998 CA  pork  sp2 

PS: Ceci est la première fois que répondre ... s'il vous plaît laissez-moi savoir si je devais apporter des modifications à cette réponse pour ajouter plus de détails ou format. Merci! Editer: J'ai été capable de trouver ce qui n'allait pas dans votre approche. Vous devez réinitialiser l'index lorsque vous créez la copie des données, sinon, lorsque vous obtenez le nombre d'index avec la valeur 0, vous obtenez plusieurs valeurs puisqu'elles sont toutes actuellement 0. Voir ci-dessous.

sp = df['Species'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
i = sp.index.get_level_values(0) 
df1 = df.loc[i].copy() 
print df1 
fd = df1['Ingredient'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
j = fd.index.get_level_values(0) 
print j 

df1 = df.loc[i].copy().reset_index(drop=True) 
print df1 
fd = df1['Ingredient'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
j = fd.index.get_level_values(0) 
print j 

Sortie:

Year State Ingredient Species 
0 1998 CA egg; pork sp1;sp2 
0 1998 CA egg; pork sp1;sp2 
Int64Index([0, 0, 0, 0], dtype='int64') 
    Year State Ingredient Species 
0 1998 CA egg; pork sp1;sp2 
1 1998 CA egg; pork sp1;sp2 
Int64Index([0, 0, 1, 1], dtype='int64') 

Code d'origine avec fix:

df = pd.DataFrame(columns=['Year', 'State', 'Ingredient', 'Species']) 
df.loc[0] = [1998, 'CA', 'egg; pork', 'sp1;sp2'] 
#print df 

sp = df['Species'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
i = sp.index.get_level_values(0) 
df1 = df.loc[i].copy().reset_index(drop=True, inplace=False) 
df1['Species'] = sp.values 


fd = df1['Ingredient'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
j = fd.index.get_level_values(0) 
df2 = df1.loc[j].copy().reset_index(drop=True, inplace=False) 
df2['Ingredient'] = fd.values 
print df2 

Hope that helps! A l'aide du "Code original avec fix" de vk montré ci-dessus.

+0

Merci de votre réponse! J'ai essayé votre code, et ça n'a pas très bien marché. Je pense que votre méthode a fonctionné pour vous parce que l'ensemble de données était petit. J'ai un ensemble de données volumineux et complexe, c'est pourquoi cela n'a pas fonctionné pour moi. Merci pour le conseil 'Edit', qui m'a vraiment aidé dans ma réflexion, et j'ai beaucoup appris de votre méthode. Si je trouve la solution, je vous le ferai savoir! – Dahlia

+0

Est-ce que le correctif de votre code d'origine fonctionne? Je comprends plus tôt que c'était une question de fonctionnalité incorrecte, est-ce que le problème est maintenant au sujet de la performance? –

+0

Super, bonne chance! –

0

Cela m'a aidé à résoudre l'erreur "la longueur des valeurs ne correspond pas à la longueur de l'index". La solution est: Je devais placer reset_index() aux emplacements appropriés dans le code.

Code d'origine:

## Separate multiple entries in cells in 'Species' column to new rows: 
sp = df['Species'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
i = sp.index.get_level_values(0) 
df1 = df.loc[i].copy() 
df1['Species] = sp.values 

## Separate multiple entries in cells in 'Ingredient' column to new rows: 
ing = df1['Ingredient'].str.split(';', expand=True).stack().reset_index(level=1, drop=True) 
df2 = df1.loc[j].copy() 
df2['Ingredient'] = ing.values 

Code fixe:

## Separate multiple entries in 'Species' column cell into rows 
sp = df['Species'].str.split(';', expand=True).stack() 
i = sp.index.get_level_values(0) 
df1 = df.loc[i].copy().reset_index() 
df1['Species'] = sp.values 

del df1['index'] ## a column called "index" is generated when you execute reset_index() 

## Separate multiple entries in 'Ingredient' column cell into rows: 
ing = df1['Ingredient'].str.split(';', expand=True).stack() 
j = ing.index.get_level_values(0) 
df2 = df1.loc[j].copy() 
df2['Ingredient'] = ing.values 

Et je suis la sortie que je voulais avec le «code fixe.