代码之家  ›  专栏  ›  技术社区  ›  N08

求不等长列表之间的最小可能差

  •  2
  • N08  · 技术社区  · 6 年前

    我有一个有两列的数据框 A B 其中包含列表:

    import pandas as pd
    
    df = pd.DataFrame({"A" : [[1,5,10],  [], [2], [1,2]],
                       "B" : [[15, 2],   [], [6], []]})
    

    我想建第三列 C 它的定义是,它等于 如果它们不是空的,则为0;如果其中一个或两个都是空的,则为0。

    对于第一行,最小的差异是1(我们取绝对值..),第二行是0,因为列表是空的,第三行是4,第四行是0,因为列表是空的,所以我们最终得出:

    df["C"] = [1, 0, 4, 0]
    
    5 回复  |  直到 6 年前
        1
  •  3
  •   jpp    6 年前

    这不容易矢量化,因为 object 数据类型列表系列。你可以用列表理解 itertools.product :

    from itertools import product
    
    zipper = zip(df['A'], df['B'])
    df['C'] = [min((abs(x - y) for x, y in product(*vals)), default=0) for vals in zipper]
    
    # alternative:
    # df['C'] = [min((abs(x - y) for x, y in product(*vals)), default=0) \
    #            for vals in df[['A', 'B']].values]
    
    print(df)
    #             A        B  C
    # 0  [1, 5, 10]  [15, 2]  1
    # 1          []       []  0
    # 2         [2]      [6]  4
    # 3      [1, 2]       []  0
    
        2
  •  2
  •   yatu Sayali Sonawane    6 年前

    您可以使用以下列表理解,检查 min 笛卡尔积之差( itertools.product )从两列

    [min(abs(i-j) for i,j in product(*a)) if all(a) else 0 for a in df.values]
    [1, 0, 4, 0]
    
        3
  •  2
  •   Filipe Aleixo    6 年前
    df['C'] = df.apply(lambda row: min([abs(x - y) for x in row['A'] for y in row['B']], default=0), axis=1)
    
        4
  •  1
  •   BENY    6 年前

    我只想介绍一下 unnesting 再一次

    df['Diff']=unnesting(df[['B']],['B']).join(unnesting(df[['A']],['A'])).eval('C=B-A').C.abs().min(level=0)
    df.Diff=df.Diff.fillna(0).astype(int)
    df
    Out[60]: 
                A        B  Diff
    0  [1, 5, 10]  [15, 2]     1
    1          []       []     0
    2         [2]      [6]     4
    3      [1, 2]       []     0
    

    供参考

    def unnesting(df, explode):
        idx=df.index.repeat(df[explode[0]].str.len())
        df1=pd.concat([pd.DataFrame({x:np.concatenate(df[x].values)} )for x in explode],axis=1)
        df1.index=idx
        return df1.join(df.drop(explode,1),how='left')
    
        5
  •  0
  •   Ananay Mital    6 年前

    我想这个行

    def diff(a,b):    
        if len(a) > 0 and len(b) > 0:
            return min([abs(i-j) for i in a for j in b])
        return 0
    
    df['C'] = df.apply(lambda x: diff(x.A, x.B), axis=1)
    df
    
               A        B   C
    0   [1, 5, 10]  [15, 2] 1
    1           []       [] 0
    2          [2]      [6] 4
    3       [1, 2]       [] 0