Нахождение наименьшей возможной разницы между списками неодинаковой длины - PullRequest
0 голосов
/ 09 января 2019

У меня есть фрейм данных с двумя столбцами 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]

Ответы [ 5 ]

0 голосов
/ 09 января 2019

Я просто хочу ввести 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')
0 голосов
/ 09 января 2019
df['C'] = df.apply(lambda row: min([abs(x - y) for x in row['A'] for y in row['B']], default=0), axis=1)
0 голосов
/ 09 января 2019

Это нелегко векторизовать, поскольку у вас есть 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
0 голосов
/ 09 января 2019

Вы можете использовать следующее понимание списка, проверяя разницу 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]
0 голосов
/ 09 января 2019

Я думаю, что это работает

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...