基于熊猫另一列的增量

时间:2018-06-29 13:43:52

标签: python pandas dataframe

我有2列:组和级别范围。每个“组”都有一个水果列表,每个“级别范围”都有一个级别范围,例如“ L1-L4”。

所需的结果是下图中的“水果”和“等级”列。

因此,如果范围为“ L2-L3”,则级别列将对第一行说“ 2”,然后对下一行说“ 3”。我还想将“组”列表中的每个项目添加到“水果”列中。

任何帮助将不胜感激!谢谢!

enter image description here

这是我已经完成的工作:

我创建了2个帮助器列:“ level_repeat”和“ grouping_repeat”,以帮助我复制必要的行。

df['level_repeat'] = df['Level'].replace(['L1-L6', 'L1-L2', 'L1-L3', 'L4-L6', 'L3-L6', 'L2-L6'], [6, 2, 3, 2, 3, 4])

df['grouping_repeat'] = df['Group'].str.len()

df_new = pd.DataFrame([df.ix[idx] for idx in df.index
                        for _ in range(df.ix[idx]['level_repeat'])]).reset_index(drop=True)

df_new = pd.DataFrame([df_new.ix[idx] for idx in df_new.index
                        for _ in range(df_new.ix[idx]['grouping_repeat'])]).reset_index(drop=True)           

结果是,对于上面的示例,我将有10行,其中该组有2个项目,并且级别范围跨越5个级别(2 * 5 = 10)。但是,在将数据插入“水果”和“级别”列中时,我仍然需要帮助。

3 个答案:

答案 0 :(得分:1)

我真的不确定如何在不遍历数据帧的情况下执行此操作。可能有更好的解决方案,但我没有想到。无论如何:

res = []
for _, row in df.iterrows():
    group = row['Group']
    lv_range_str = row['Level Range']

    #change this line if the format of 'Level Range' changes
    lv_range = range(lv_range_str[1], lv_range_str[4] + 1)

    res += [
        {
            'Group': group,
            'Level Range': lv_range_str,
            'Fruit': fruit,
            'Level': level
        }
        for level in lv_range
        for fruit in group
    ]

res = pd.DataFrame(res)

仅当Level Range中的所有字符串都采用L{i}-L{j}格式时,它才有效,否则您将需要更改lv_range的定义
如果您的数据集很大,则可能需要一些时间

答案 1 :(得分:0)

这是一种方法,我首先从“级别范围”中创建带有数字range的列“级别列表”,因此对于“ L2-L5”,列表将为[2,3,4 ,5]。

df['level_list'] = (df['Level Range'].str.split('-',expand=True)
                     .stack().str[-1].unstack()
                     .apply(lambda x: range(int(x[0]),int(x[1])+1),1))

现在,使用itertools中的产品以及带有列表的两列(Group和level_list),您可以创建新的数据框:

from itertools import product
df_new = pd.DataFrame([ [ind, group, level_range, g, l] 
                        for ind, group, level_range, level_list 
                             in df[['Group','Level Range', 'level_list']].itertuples() 
                                   for l, g in product(level_list, group) ], 
                      columns = ['original_ind','Group', 'Level Range', 'Fruit','Level'])

具有类似

的输入

df = pd.DataFrame({'Group':[['Apple','Banana']], 'Level Range': ['L2-L5']})

df_new的结果是:

   original_ind            Group Level Range   Fruit  Level
0             0  [Apple, Banana]       L2-L5   Apple      2
1             0  [Apple, Banana]       L2-L5  Banana      2
2             0  [Apple, Banana]       L2-L5   Apple      3
3             0  [Apple, Banana]       L2-L5  Banana      3
4             0  [Apple, Banana]       L2-L5   Apple      4
5             0  [Apple, Banana]       L2-L5  Banana      4
6             0  [Apple, Banana]       L2-L5   Apple      5
7             0  [Apple, Banana]       L2-L5  Banana      5

请注意,如果您不关心原始索引,则可以删除该列或不创建该列

答案 2 :(得分:0)

您需要从字符串#box中提取范围为L1-L5,并使用此列表和水果列表[1,2,3,4,5]的乘积创建一个数据框。

您可以使用[Apple, Banana]itertools.product进行此操作。

在这里,我正在使用后者和一个辅助函数来构建范围。

pd.MultiIndex.from_product

第一个警告是def get_level_range(x): a, b = x.replace('L', '').split('-') return range(int(a), int(b)+1) dframes = [] for _, x in df.iterrows(): dframes.append( pd.DataFrame( index=pd.MultiIndex.from_product( [get_level_range(x['Level Range']), x.Group, [tuple(x.Group)], [x['Level Range']]], names=['Level', 'Fruit', 'Group', 'Level Range'] ) ).reset_index() ) pd.concat(dframes) # produces output: Level Fruit Group Level Range 0 1 Apple (Apple, Banana) L1-L5 1 1 Banana (Apple, Banana) L1-L5 2 2 Apple (Apple, Banana) L1-L5 3 2 Banana (Apple, Banana) L1-L5 4 3 Apple (Apple, Banana) L1-L5 5 3 Banana (Apple, Banana) L1-L5 6 4 Apple (Apple, Banana) L1-L5 7 4 Banana (Apple, Banana) L1-L5 8 5 Apple (Apple, Banana) L1-L5 9 5 Banana (Apple, Banana) L1-L5 需要从Group转换为list,因为list不可散列,因此不能用作索引元素。但是,如果需要,可以稍后将其转换回tuple,如下所示:

list