Étant donné le dataframe suivant
imgRaw["Category"] = ""
for index, row in df.iterrows():
catA = row["OrderCategoryA"]
catB = row["OrderCategoryB"]
catC = row["OrderCategoryC"]
catD = row["OrderCategoryD"]
if catA == "Yes":
row["Category"] = "OrderCategoryA"
elif catB == "Yes":
row["Category"] = "OrderCategoryB"
elif catC == "Yes":
row["Category"] = "OrderCategoryC"
elif catD == "Yes":
row["Category"] = "OrderCategoryD"
Comment puis-je transformer cela pour créer des lignes basées sur la OrderCategory?
OrderCategoryA No Yes Cust_ID 1 0 1 0 2 0 1 0 3 0 1 0 4 1 0 0 5 1 0 0 6 0 1 0 7 0 1 0 8 0 1 0 9 1 0 0 10 0 0 1
J'ai essayé d'utiliser tableau croisé pour commencer avec une OrderCategory , et j'ai prévu de dupliquer pour chaque catégorie, mais cela semble inefficace et je ne savais pas trop comment procéder obtenir le résultat souhaité ...
imgCROSS = pd.crosstab(df["Cust_ID"], df["OrderCategoryA"])
Renvoie ...
+--------+-----------+----------+----------------+ |Cust_ID | OrderMade |OrderType | OrderCategory | |--------+-----------+----------+----------------| |1 | Yes | A | OrderCategoryB | |2 | Yes | A | OrderCategoryC | |3 | Yes | B | OrderCategoryC | |4 | No | | | |5 | No | | | |6 | Yes | C | OrderCategoryC | |6 | Yes | C | OrderCategoryD | |7 | Yes | A | OrderCategoryB | |8 | Yes | A | OrderCategoryC | |9 | No | | | |10 | Yes | B | OrderCategoryA | |10 | Yes | B | OrderCategoryB | +--------+-----------+----------+----------------+
J'ai aussi pensé que je pourrais remplir un nouveau vide colonne appelée Catégorie et itérer sur chaque ligne, en remplissant la catégorie appropriée en fonction de la valeur Oui / Non , mais cela ne fonctionnerait pas pour les lignes qui ont plusieurs catégories. De plus, l'implémentation ci-dessous de cette idée a renvoyé une colonne vide.
data = [[1, 'Yes','A','No','Yes','No','No','No'],
[2, 'Yes','A','No','No','Yes','No','No'],
[3, 'Yes','B','No','No','Yes','No','No'],
[4, 'No','','','','','',''],
[5, 'No','','','','','',''],
[6, 'Yes','C','No','No','Yes','Yes','No'],
[7, 'Yes','A','No','Yes','No','No','No'],
[8, 'Yes','A','No','No','Yes','No','No'],
[9, 'No','','','','','',''],
[10, 'Yes','B','Yes','Yes','No','No','No']]
df = pd.DataFrame(data,columns=['Cust_ID','OrderMade','OrderType','OrderCategoryA','OrderCategoryB','OrderCategoryC','OrderCategoryD'])
+----+-----------+-------------+-------------+------------------+------------------+------------------+------------------+
| | Cust_ID | OrderMade | OrderType | OrderCategoryA | OrderCategoryB | OrderCategoryC | OrderCategoryD |
|----+-----------+-------------+-------------+------------------+------------------+------------------+------------------|
| 0 | 1 | Yes | A | No | Yes | No | No |
| 1 | 2 | Yes | A | No | No | Yes | No |
| 2 | 3 | Yes | B | No | No | Yes | No |
| 3 | 4 | No | | | | | |
| 4 | 5 | No | | | | | |
| 5 | 6 | Yes | C | No | No | Yes | Yes |
| 6 | 7 | Yes | A | No | Yes | No | No |
| 7 | 8 | Yes | A | No | No | Yes | No |
| 8 | 9 | No | | | | | |
| 9 | 10 | Yes | B | Yes | Yes | No | No |
+----+-----------+-------------+-------------+------------------+------------------+------------------+------------------+
Je sais que je dois transformer le dataframe, probablement plusieurs fois avant de pouvoir obtenir le résultat souhaité. Je ne sais pas comment procéder.
4 Réponses :
Comme suggéré dans l'autre réponse, vous voulez fondre avec un nettoyage supplémentaire, et fusionner:
Cust_ID OrderMade OrderType OrderCategory 0 10 Yes B OrderCategoryA 1 10 Yes B OrderCategoryB 2 1 Yes A OrderCategoryB 3 7 Yes A OrderCategoryB 4 2 Yes A OrderCategoryC 5 3 Yes B OrderCategoryC 6 6 Yes C OrderCategoryC 7 6 Yes C OrderCategoryD 8 8 Yes A OrderCategoryC 9 4 No NaN 10 5 No NaN 11 9 No NaN
Sortie:
id_cols = ['Cust_ID','OrderMade','OrderType']
new_df = df[df.OrderMade.eq('Yes')].melt(id_vars=id_cols, var_name='OrderCategory')
new_df[new_df['value'].ne('No')]
.merge(df.loc[df.OrderMade.eq('No'),
['Cust_ID','OrderMade','OrderType']],
how='outer')
.drop('value',axis=1)
Voici une façon de le faire (j'ai dû modifier votre dataframe d'origine pour qu'il n'ait qu'une seule OrderCategoryD au lieu de deux ... j'espère que c'était une faute de frappe):
keep_cols = ['Cust_ID','OrderMade','OrderType']
build = pd.DataFrame()
for col in df.columns:
if 'OrderCategory' in col:
cat = col[-1:] # Get the category letter
temp = df.loc[df[col] == 'Yes', keep_cols] # Get all the rows with a yes in this column
temp['OrderCategory'] = cat # Append a column with the correct letter
build = build.append(temp) # Append that df to our new df
# Once that's done, get all the rows that have a 'No' in the OrderMade column
final = pd.merge(build, df[keep_cols], how='right').sort_values('Cust_ID')
final = final.reset_index().drop(columns=['index'])
p >
'Non' dans 'OrderMade' Cela généralise le problème et nous permet d'utiliser une méthode plus uniforme. p>
d = df.assign(**{'': df.OrderMade.map({'Yes': 'No', 'No': 'Yes'})})
d.melt(['Cust_ID', 'OrderMade', 'OrderType'], var_name='OrderCategory') \
.query('value == "Yes"').drop('value', 1).sort_values('Cust_ID')
Cust_ID OrderMade OrderType OrderCategory
10 1 Yes A OrderCategoryB
21 2 Yes A OrderCategoryC
22 3 Yes B OrderCategoryC
53 4 No
54 5 No
25 6 Yes C OrderCategoryC
35 6 Yes C OrderCategoryD
16 7 Yes A OrderCategoryB
27 8 Yes A OrderCategoryC
58 9 No
9 10 Yes B OrderCategoryA
19 10 Yes B OrderCategoryB
melt L'ajout de la colonne simplifie également la fusion
d = df.assign(**{'': df.OrderMade.map({'Yes': 'No', 'No': 'Yes'})})
ids, cat = np.split(d, [3], 1) # split between 3rd and 4th columns
i, j = np.where(cat.eq('Yes'))
ids.iloc[i].assign(OrderCategory=cat.columns[j])
Cust_ID OrderMade OrderType OrderCategory
0 1 Yes A OrderCategoryB
1 2 Yes A OrderCategoryC
2 3 Yes B OrderCategoryC
3 4 No
4 5 No
5 6 Yes C OrderCategoryC
5 6 Yes C OrderCategoryD
6 7 Yes A OrderCategoryB
7 8 Yes A OrderCategoryC
8 9 No
9 10 Yes B OrderCategoryA
9 10 Yes B OrderCategoryB
h3>
Utilisons les pandas en quatre étapes:
Cust_ID OrderMade OrderType OrderCategory 0 1 Yes A OrderCategoryB 1 2 Yes A OrderCategoryC 2 3 Yes B OrderCategoryC 3 4 No 8 5 No 13 6 Yes C OrderCategoryC 14 6 Yes C OrderCategoryD 15 7 Yes A OrderCategoryB 16 8 Yes A OrderCategoryC 17 9 No 22 10 Yes B OrderCategoryA 23 10 Yes B OrderCategoryB
Sortie:
df_1 = df.set_index(['Cust_ID', 'OrderMade', 'OrderType'])
df_2 = df_1.where((df_1 == "Yes") | (df_1 == "")).rename_axis('OrderCategory', axis=1).stack().reset_index()
df_2['OrderCategory'] = df_2['OrderCategory'].mask(df_2['OrderMade'] == 'No','')
df_2.drop_duplicates().drop(0, axis=1)