8
$\begingroup$

I need to find how well several different lists match a reference list. I'm looking for a percentage or some kind of similarity score.

For example,

a = {"A278", "G279", "S280", "G281", "I282", "I283", "I284", "S285", 
"D286", "T287", "P288", "V289", "H290", "D291", "C292"}
b = {"S280", "G281", "I282", "I284"}
c = {"C275", "S276", "T277", "A278", "G279"}

How can I determine that b is a better match against a than c? a is the reference list.

Order matters.

After looking through the documentation, the only way I can think of doing this is to iterate through b and c and test if each element is MemberQ of a, tallying up the total and comparing the totals at the end. Is there a better approach?

$\endgroup$
  • 2
    $\begingroup$ You might consider looking through the whole bunch of *Distance[]/*Dissimilarity[] functions available. SequenceAlignment[] might also be of use. $\endgroup$ – J. M. is away Oct 8 '18 at 4:24
  • 1
    $\begingroup$ Testing as described in the last paragraph of the question does not take account of order. If order actually does not matter, consider Complement. $\endgroup$ – bbgodfrey Oct 8 '18 at 4:33
  • $\begingroup$ Working on Complement now, it seems promising @bbgodfrey $\endgroup$ – briennakh Oct 8 '18 at 4:37
6
$\begingroup$

Maybe:

LongestCommonSequence[a, b]

{"S280", "G281", "I282", "I284"}

LongestCommonSequence[a, c]

{"A278", "G279"}

Length@LongestCommonSequence[a, #] & /@ {b, c}

{4, 2}

$\endgroup$
6
$\begingroup$
MaximalBy[Length[a⋂#]&]@{b,c} 

{{"S280", "G281", "I282", "I284"}}

MinimalBy[Length@Complement[a,#]&]@{b,c} 

{{"S280", "G281", "I282", "I284"}}

$\endgroup$
  • $\begingroup$ +1 for conciseness, this is better than my answer $\endgroup$ – briennakh Oct 8 '18 at 5:21
  • $\begingroup$ @briennakh, yours is probably faster. $\endgroup$ – kglr Oct 8 '18 at 5:22
4
$\begingroup$

Going off your percent similarity idea, maybe something like

listsim[ref_, test_] := {#, 100. (1 - Length@Complement[ref, #]/Length@ref)} & /@ test

listsim[a, {a, b, c}]

{{{A278,G279,S280,G281,I282,I283,I284,S285,D286,T287,P288,V289,H290,D291,C292},100.} {{S280,G281,I282,I284},26.6667}
{{C275,S276,T277,A278,G279},13.3333}}

which ended up being in a similar vein to your answer.

$\endgroup$
  • $\begingroup$ I like this!! Thanks! $\endgroup$ – briennakh Oct 8 '18 at 5:18
4
$\begingroup$

Suppose I have the reference list a and a matrix otherLists of all other lists I want to compare against a:

otherLists[[Ordering[Length[#] & /@ (Complement[a, #] & /@ otherLists), 1]]]

This will return the list that best matches a.

$\endgroup$
  • 1
    $\begingroup$ you can use just Length instead of Length[#] &. $\endgroup$ – kglr Oct 8 '18 at 5:28
  • $\begingroup$ Please don't edit my answer @MarcoB — Write a comment. $\endgroup$ – briennakh Feb 20 at 18:18
  • $\begingroup$ I rolled back my changes. @kglr 's comment is suggesting the same change. Is there a reason you prefer to retain your version? $\endgroup$ – MarcoB Feb 20 at 18:21
  • $\begingroup$ My answer works. If you want to optimize my answer, you can add your suggestion as a comment or upvote kglr's comment. Thank you. @MarcoB $\endgroup$ – briennakh Feb 20 at 18:23
  • $\begingroup$ @briennakh It certainly works, but the usage of Length[#]& where Length would suffice is unnecessary. This site is collaboratively edited, so I made a change that, in my opinion, improved this answer for future readers. Anyway, I will leave it as it was; perhaps you might consider making a change yourself. $\endgroup$ – MarcoB Feb 20 at 18:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.