How about this approach. I changed your details a bit to cause the sale of 4 tickets.
We use the np.ones () helper array, the appropriate size, and then the key line of code: a[np.arange(a.shape[1])[:] > a[:,0,np.newaxis]] = 0
I was shown this technique here: numpy - update values ββusing slicing to reflect the value of the array
Then its just calling .stack() and some basic filtering to complete.
d = {'1': ['20', 'NYC', '2'], '2': ['30', 'NYC', '2'], '3': ['5', 'NYC', '2'], \ '4': ['300', 'LA', '2'], '5': ['30', 'LA', '4'], '6': ['100', 'LA', '2']} columns=['Price', 'City', 'Quantity'] df = pd.DataFrame.from_dict(data=d, orient='index') df.columns = columns df['Quantity'] = df['Quantity'].astype(int)
which is as follows:
Price City Quantity 0 1 2 3 1 20 NYC 2 1 1 1 1 3 5 NYC 2 1 1 1 1 2 30 NYC 2 1 1 1 1 5 30 LA 4 1 1 1 1 4 300 LA 2 1 1 1 1
now get the column Number and units in a numpy array
a = df.iloc[:,2:].values
it's a smart bit
a[np.arange(a.shape[1])[:] > a[:,0,np.newaxis]] = 0
and assign df again.
df.iloc[:,2:] = a
and now df looks like this: notice how we set a zero number in quantity:
Price City Quantity 0 1 2 3 1 20 NYC 2 1 1 0 0 3 5 NYC 2 1 1 0 0 2 30 NYC 2 1 1 0 0 5 30 LA 4 1 1 1 1 4 300 LA 2 1 1 0 0 df.set_index(['Price','City','Quantity'],inplace=True) df = df.stack().to_frame() df.columns = ['sale_flag'] df.reset_index(inplace=True) print df[['Price','City', 'Quantity']][df['sale_flag'] !=0] print df
which produces:
Price City Quantity 0 20 NYC 2 1 20 NYC 2 4 5 NYC 2 5 5 NYC 2 8 30 NYC 2 9 30 NYC 2 12 30 LA 4 13 30 LA 4 14 30 LA 4 15 30 LA 4 16 300 LA 2 17 300 LA 2