2016-12-03 5 views
0

Следующий код позволяет мне найти соответствующие значения:Возврат колонок обеспечивает среднее соответствующих значений

from itertools import combinations 
df = pd.DataFrame(np.random.randn(12, 3), columns=['A', 'B', 'C']) 
thresh = .3 
df['matches'] = sum(abs(df[k1]-df[k2])<thresh for k1,k2 in combinations(df.keys(),2)) 

Информацию об этом можно найти here:

Лучшего объяснения от @Andras ДИК

«Генерирующее выражение в sum() пересекает каждую пару столбцов и строит соответствующий логический вектор. Они суммируются для каждой пары столбцов, а полученный столбец добавляется к кадру данных».

Пример выходных данных для Thresh = 0,3:

  A   B   C matches 
0 0.146360 -0.099707 0.633632  1 
1 1.462810 -0.186317 -1.411988  0 
2 0.358827 -0.758619 0.038329  0 
3 0.077122 -0.213856 -0.619768  1 
4 0.215555 1.930888 -0.488517  0 
5 -0.946557 -0.904743 -0.004738  1 
6 -0.080209 -0.850830 -0.866865  1 
7 -0.997710 -0.580679 -2.231168  0 
8 1.762313 -0.356464 -1.813028  0 
9 1.151338 0.347636 -1.323791  0 
10 0.248432 1.265484 0.048484  1 
11 0.559934 -0.401059 0.863616  0 

Как вернуть еще один столбец df['matches_mean'] обеспечивающий среднее из значений, которые соответствовали? Таким образом, для первой строки в приведенном выше примере она вернет среднее значение 0.146360 & -0.099707. Я бы хотел, чтобы это использовало ту же логику itertools combinations, что и исходный код, так как это хорошо масштабируется по моим реальным данным.

+0

Что делать, если более чем одна пара колонок близки? Что должно содержать этот столбец? –

+0

Привет Андраш. В конечном итоге я ищу большинство матчей и среднее значение этой группы матчей. Поэтому, если 3 столбца совпадают и 2 совпадают с одной и той же строкой, то среднее из 3 столбцов будет идеальным. Спасибо за любую помощь! – ade1e

+0

А как насчет строк, где нет совпадений? –

ответ

1

В настоящее время это почти идеальное решение. Проблема в том, что когда вы хотите рассчитать среднее значение для нескольких совпадений (скажем, все три числа в строке близки к порогу), вы должны принять правильное количество значений при вычислении среднего значения. Это легко, если есть только 1 или 3 матча из 3 столбцов. Но когда две пары чисел «близки», а третья - нет, код ниже будет иметь ошибку.

Идея заключается в суммировании совпадающих значений для каждой строки и каждой комбинации. Если только, скажем, строки 'A' и 'B' являются «близкими» (в пределах порога), мы получаем df.A+df.B, который необходимо разделить на 2, чтобы получить среднее значение. Когда все три «близки», мы получаем 2*df.A + 2*df.B + 2*df.C, которые можно разделить на 6, чтобы получить среднее значение. Однако в третьем случае мы получаем, например, df.A + 2*df.B + df.C (когда A и B близки, B и C близки, но A и C не являются). В этом случае мы не можем делить что-либо, чтобы получить надлежащее среднее значение. Вероятно, мы должны разделить на 4, чтобы получить ошибочное значение «примерно одного» элемента. Я хочу сказать, что код был бы намного сложнее, если бы мы правильно относились к этому делу и, в зависимости от ваших потребностей, это не стоило того. Также неясно, как именно вы хотите справиться с этим делом. Текущая версия деления выше на 4 эквивалентна усреднению A vs B, усреднению B против C, а затем усреднению этих средних значений снова.

Так вот:

import numpy as np 
import pandas as pd 
from itertools import combinations 

colnames = ['A', 'B', 'C'] 
df = pd.DataFrame(np.random.randn(12, 3), columns=colnames) 
thresh = .3 
df['matches'] = sum(abs(df[k1]-df[k2])<thresh 
        for k1,k2 in combinations(colnames,2)) 
# this is your starting point, we'll need df['matches'] too 

tmpsums = sum(np.where(abs(df[k1]-df[k2])<thresh,df[k1]+df[k2],0) 
       for k1,k2 in combinations(colnames,2)) 
# divide by 2/4/6: 
df['matches_mean'] = np.where(df['matches'],tmpsums/df['matches']/2,0) 

Возникающая сумма по выражению генератора достигает границы хорошего вкуса, я признаю. Возможно, вы захотите записать его в правильном цикле, но тогда вам придется постепенно суммировать значения в tmpsums. Я признаю, что это может быть красивее.

В любом случае, это второе выражение генератора работает аналогично первому. Дали значение, конечно, разные,

np.where(abs(df[k1]-df[k2])<thresh,df[k1]+df[k2],0) 

То есть, это даст нам сумму элементов для данной пары столбца, если эти значения находятся ближе, чем молоти, иначе мы получим 0. Для всех 3 мы получаем массив с такими значениями нуля или суммы двух элементов, и суммируем их снова. Там, где было 0 совпадений, мы получаем 0. Если было 1 совпадение, мы суммируем два совпадающих элемента.В течение двух матчей мы получаем смешанную сумму, о которой я упоминал ранее, и у нас есть все условия дважды в случае 3 матчей.

Осталось разделить ненулевые случаи на число совпадений, что является просто делением с удвоенным количеством совпадений, которое мы уже знаем (но мы должны следить за делением на ноль).

Пример вывода с thresh = 0.3:

  A   B   C matches matches_mean 
0 0.716278 0.681279 0.861410  3  0.752989 
1 -0.109029 -0.646952 0.268038  0  0.000000 
2 -1.095221 -1.088397 1.100645  1  -1.091809 
3 -1.970372 -0.367096 -0.337098  1  -0.352097 
4 -1.030003 0.082001 -0.807431  1  -0.918717 
5 1.660611 -0.046429 0.557107  0  0.000000 
6 -0.508715 -0.588217 0.014917  1  -0.548466 
7 0.578028 -0.187097 -0.420243  1  -0.303670 
8 0.233687 1.311917 1.888947  0  0.000000 
9 0.478863 1.087957 -0.897025  0  0.000000 
10 -0.001462 0.866320 -1.198642  0  0.000000 
11 0.297946 0.564325 -1.098887  1  0.431135 
+0

Спасибо @ Andras Deak, это здорово. Я отмечен как полный, но задам еще один вопрос. В любом случае добавить еще один столбец, показывающий, что шаблон совпадений - это строка, показывающая «df.A/df.B/df.C», если все были в пределах thresh. Или для большего набора данных, если разные совпадения в той же строке будут отображаться, например, «df.A/df.B/df.C» - «df.D/df.L/df.Z», если были видны две отдельные группы соответствия , Я понятия не имею, можно ли это сделать, если честно. – ade1e

+0

@adele спасибо. Это определенно выполнимо, оно просто требует больше работы :) И если вы хотите построить такие строки, я не думаю, что это будет работать в векторном виде. Это означает, что вам, вероятно, придется перебирать строки, которые недостаточно масштабируются. Итак, предполагая, что вы имели в виду, если это можно сделать так эффективно: я так не думаю :( –

Смежные вопросы