【问题标题】:Finding smallest possible difference between lists of unequal length找到长度不等的列表之间的最小可能差异
【发布时间】:2023-03-05 23:14:01
【问题描述】:

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

import pandas as pd

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

我想构造第三列C,它被定义为等于A和B中的列表元素之间的最小可能差异,如果它们是非空的,如果它们是非空的,则为0,如果是或他们两个都是空的。

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

df["C"] = [1, 0, 4, 0]

【问题讨论】:

    标签: python pandas list


    【解决方案1】:

    这不容易矢量化,因为您有 object dtype 系列列表。您可以使用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
    

    【讨论】:

    • 是否可以将 dtype-series 转换为不同的格式以便对其进行矢量化?
    • @N08,由于您有可变长度列表,所以不容易,没有。当每个维度具有相同数量的值时,NumPy / Pandas 效果最好。你最终可能会得到很多空值,这也是低效的。
    • @jpp,不错,这里的拉链是什么。
    • 刚刚意识到这正是您在解决方案中所拥有的 :-),将它与三元 if 保持原样。无论如何感谢您的提示
    • @yatu,没有问题,总是乐于助人:)
    【解决方案2】:

    您可以使用以下列表推导,检查两列中笛卡尔积 (itertools.product) 的 min 差异

    [min(abs(i-j) for i,j in product(*a)) if all(a) else 0 for a in df.values]
    [1, 0, 4, 0]
    

    【讨论】:

    • min 可以采用可迭代对象(因此您可以使用生成器表达式,无需额外创建列表)。此外,在迭代df.values 时不需要tolist()。最后,min 有一个默认值,不需要三元语句。
    【解决方案3】:
    df['C'] = df.apply(lambda row: min([abs(x - y) for x in row['A'] for y in row['B']], default=0), axis=1)
    

    【讨论】:

    • 真棒@Filipe +1。
    • @pygo 注意这会比 jpp 和 yatu 的解决方案慢。 :-)
    【解决方案4】:

    我只想再次介绍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】:

      我认为这可行

      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
      

      【讨论】:

        猜你喜欢
        • 2021-03-22
        • 2015-11-12
        • 1970-01-01
        • 2016-06-19
        • 1970-01-01
        • 1970-01-01
        • 2020-11-09
        • 2017-04-18
        • 1970-01-01
        相关资源
        最近更新 更多