web-dev-qa-db-fra.com

remodeler un cadre de données pandas

supposons un dataframe comme celui-ci:

df = pd.DataFrame([[1,2,3,4],[5,6,7,8],[9,10,11,12]], columns = ['A', 'B', 'A1', 'B1'])

 enter image description here

Je voudrais avoir un cadre de données qui ressemble à:

 enter image description here

ce qui ne marche pas:

new_rows = int(df.shape[1]/2) * df.shape[0]
new_cols = 2
df.values.reshape(new_rows, new_cols, order='F')

bien sûr, je pourrais parcourir les données et faire une nouvelle liste, mais il doit y avoir un meilleur moyen. Des idées ?

7
Moritz

La fonction pd.wide_to_long est construite presque exactement pour cette situation, où vous avez plusieurs préfixes de variable identiques se terminant par un suffixe numérique différent. La seule différence est que votre premier ensemble de variables n'a pas de suffixe, vous devez donc renommer vos colonnes en premier.

Le seul problème avec pd.wide_to_long est qu'il doit avoir une variable d'identification, i, contrairement à melt. reset_index est utilisé pour créer une colonne d'identification unique, qui sera supprimée ultérieurement. Je pense que cela pourrait être corrigé à l'avenir.

df1 = df.rename(columns={'A':'A1', 'B':'B1', 'A1':'A2', 'B1':'B2'}).reset_index()
pd.wide_to_long(df1, stubnames=['A', 'B'], i='index', j='id')\
  .reset_index()[['A', 'B', 'id']]

    A   B id
0   1   2  1
1   5   6  1
2   9  10  1
3   3   4  2
4   7   8  2
5  11  12  2
3
Ted Petrou

Vous pouvez utiliser lreshape , pour la colonne idnumpy.repeat :

a = [col for col in df.columns if 'A' in col]
b = [col for col in df.columns if 'B' in col]
df1 = pd.lreshape(df, {'A' : a, 'B' : b})

df1['id'] = np.repeat(np.arange(len(df.columns) // 2), len (df.index))  + 1
print (df1)
    A   B  id
0   1   2   1
1   5   6   1
2   9  10   1
3   3   4   2
4   7   8   2
5  11  12   2

MODIFIER:

lreshape est actuellement non documenté, mais il est possible de le supprimer ( avec pd.wide_to_long aussi ). 

La solution possible est de fusionner les 3 fonctions en une seule - peut-être melt, mais maintenant, elle n'est pas implémentée. Peut-être dans une nouvelle version des pandas. Ensuite, ma réponse sera mise à jour.

8
jezrael

Utilisez pd.concat() comme suit:

#Split into separate tables
df_1 = df[['A', 'B']]
df_2 = df[['A1', 'B1']]
df_2.columns = ['A', 'B'] # Make column names line up

# Add the ID column
df_1 = df_1.assign(id=1)
df_2 = df_2.assign(id=2)

# Concatenate
pd.concat([df_1, df_2])
1
Matthew

J'ai résolu ceci en 3 étapes:

  1. Créez un nouveau cadre de données df2 contenant uniquement les données que vous souhaitez ajouter au cadre de données initial df.
  2. Supprimez les données de df qui seront ajoutées ci-dessous (et qui ont été utilisées pour créer df2.
  3. Ajoutez df2 à df.

Ainsi:

# step 1: create new dataframe
df2 = df[['A1', 'B1']]
df2.columns = ['A', 'B']

# step 2: delete that data from original
df = df.drop(["A1", "B1"], 1)

# step 3: append
df = df.append(df2, ignore_index=True)

Notez que lorsque vous faites df.append() vous devez spécifier ignore_index=True pour que les nouvelles colonnes soient ajoutées à l'index plutôt que de conserver leur ancien index.

Votre résultat final doit être votre image d'origine avec les données réorganisées comme vous le souhaitez:

In [16]: df
Out[16]:
    A   B
0   1   2
1   5   6
2   9  10
3   3   4
4   7   8
5  11  12
1
mprat