基于不同列

时间:2015-09-26 00:04:47

标签: python pandas

我有一个交易数据框。每行代表两个项目的交易(将其视为2个事件票据或其他事务的交易)。我想根据销售数量复制每一行。

以下是示例代码:

# dictionary of transactions

d = {'1': ['20', 'NYC', '2'], '2': ['30', 'NYC', '2'], '3': ['5', 'NYC', '2'], \
     '4': ['300', 'LA', '2'], '5': ['30', 'LA', '2'],  '6': ['100', 'LA', '2']}

columns=['Price', 'City', 'Quantity']

# create dataframe and rename columns

df = pd.DataFrame.from_dict(data=d, orient='index')
df.columns = columns

这会产生一个看起来像这样的数据框

Price   City    Quantity

20       NYC         2

30       NYC         2

5        NYC         2

300      LA          2

30       LA          2

100      LA          2

因此,在上面的情况中,每行将转换为两个重复的行。如果'数量' column为3,然后该行将转换为三个重复的行。

3 个答案:

答案 0 :(得分:8)

首先,我使用整数而不是文本重新创建数据。我也改变了数量,以便人们可以更容易地理解问题。

d = {1: [20, 'NYC', 1], 2: [30, 'NYC', 2], 3: [5, 'SF', 3],      
     4: [300, 'LA', 1], 5: [30, 'LA', 2],  6: [100, 'SF', 3]}

columns=['Price', 'City', 'Quantity'] 
# create dataframe and rename columns

df = pd.DataFrame.from_dict(data=d, orient='index').sort_index()
df.columns = columns

>>> df
   Price City  Quantity
1     20  NYC         1
2     30  NYC         2
3      5   SF         3
4    300   LA         1
5     30   LA         2
6    100   SF         3

我使用嵌套列表理解结构创建了一个新的DataFrame。

df_new = pd.DataFrame([df.ix[idx] 
                       for idx in df.index 
                       for _ in range(df.ix[idx]['Quantity'])]).reset_index(drop=True)
>>> df_new
    Price City  Quantity
0      20  NYC         1
1      30  NYC         2
2      30  NYC         2
3       5   SF         3
4       5   SF         3
5       5   SF         3
6     300   LA         1
7      30   LA         2
8      30   LA         2
9     100   SF         3
10    100   SF         3
11    100   SF         3

答案 1 :(得分:3)

这种方法怎么样?我稍微改变了你的数据,以便出售4张票。

我们使用一个大小合适的帮助器np.ones()数组,然后代码的关键行是:a[np.arange(a.shape[1])[:] > a[:,0,np.newaxis]] = 0

我在这里看到了这种技巧:numpy - update values using slicing given an array value

然后只需调用.stack()并完成一些基本过滤。

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)

# make a ones array 
my_ones = np.ones(shape=(len(df),df['Quantity'].max()))

# turn my_ones into a dataframe same index as df so we can join it to the right hand side. Plenty of other ways to achieve the same outcome. 
df_my_ones = pd.DataFrame(data =my_ones,index = df.index)

df = df.join(df_my_ones)

看起来像:

  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

现在获取Quantity列,将其变为numpy数组

a = df.iloc[:,2:].values

这是聪明的一点

a[np.arange(a.shape[1])[:] > a[:,0,np.newaxis]] = 0

并重新分配给df。

df.iloc[:,2:] = a

现在df看起来如下,请注意我们如何将数量设置为零,数量为:

  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

产生:

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

答案 2 :(得分:0)

使用repeat

进行回答
df.loc[df.index.repeat(df.Quantity)]
Out[448]: 
  Price City Quantity
1    20  NYC        2
1    20  NYC        2
2    30  NYC        2
2    30  NYC        2
3     5  NYC        2
3     5  NYC        2
4   300   LA        2
4   300   LA        2
5    30   LA        2
5    30   LA        2
6   100   LA        2
6   100   LA        2