Нечеткое сопоставление между столбцами разных фреймов данных (разной длины) [дубликат]

UPDATE: Спасибо всем за все, что угодно, но я не думаю, что мой ответ ниже - лучший способ написать перечисления в Javascript. См. Мой блог для более подробной информации: Перечисления в Javascript .


Предупреждение о названии уже возможно:

if (currentColor == my.namespace.ColorEnum.RED) {
   // alert name of currentColor (RED: 0)
   var col = my.namespace.ColorEnum;
   for (var name in col) {
     if (col[name] == col.RED)
       alert(name);
   }
}

Кроме того, вы могли бы сделайте объекты значений, чтобы вы могли получить торт и съесть его:

var SIZE = {
  SMALL : {value: 0, name: "Small", code: "S"}, 
  MEDIUM: {value: 1, name: "Medium", code: "M"}, 
  LARGE : {value: 2, name: "Large", code: "L"}
};

var currentSize = SIZE.MEDIUM;
if (currentSize == SIZE.MEDIUM) {
  // this alerts: "1: Medium"
  alert(currentSize.value + ": " + currentSize.name);
}

В Javascript, так как это динамический язык, возможно даже добавить значения перечисления в набор позже:

// Add EXTRALARGE size
SIZE.EXTRALARGE = {value: 3, name: "Extra Large", code: "XL"};

Помните, что поля перечисления (значение, имя и код в этом примере) не нужны для проверки подлинности и доступны только для удобства. Также имя самого свойства size не обязательно должно быть жестко запрограммировано, но также может быть установлено динамически. Предположим, что вы знаете только имя для нового значения enum, вы можете добавить его без проблем:

// Add 'Extra Large' size, only knowing it's name
var name = "Extra Large";
SIZE[name] = {value: -1, name: name, code: "?"};

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

Помните, что в Javascript объект похож на карту или хеш-таблицу. Набор пар имя-значение.

EG:

for (var sz in SIZE) {
  // sz will be the names of the objects in SIZE, so
  // 'SMALL', 'MEDIUM', 'LARGE', 'EXTRALARGE'
  var size = SIZE[sz]; // Get the object mapped to the name in sz
  for (var prop in size) {
    // Get all the properties of the size object, iterates over
    // 'value', 'name' and 'code'. You can inspect everything this way.        
  }
} 

И, кстати, если вы заинтересованы в пространствах имен, вы можете захотеть взгляните на мое решение для простого, но мощного управления пространством имен и зависимостей для javascript: Пакеты JS

37
задан Andy Hayden 3 December 2012 в 12:08
поделиться

6 ответов

Подобно предложению @locojay, вы можете применить difflib 's get_closest_matches к индексу df2, а затем применить join :

In [23]: import difflib 

In [24]: difflib.get_close_matches
Out[24]: <function difflib.get_close_matches>

In [25]: df2.index = df2.index.map(lambda x: difflib.get_close_matches(x, df1.index)[0])

In [26]: df2
Out[26]: 
      letter
one        a
two        b
three      c
four       d
five       e

In [31]: df1.join(df2)
Out[31]: 
       number letter
one         1      a
two         2      b
three       3      c
four        4      d
five        5      e

.

Если это были столбцы, в том же духе вы могли бы применить к столбцу, тогда merge :

df1 = DataFrame([[1,'one'],[2,'two'],[3,'three'],[4,'four'],[5,'five']], columns=['number', 'name'])
df2 = DataFrame([['a','one'],['b','too'],['c','three'],['d','fours'],['e','five']], columns=['letter', 'name'])

df2['name'] = df2['name'].apply(lambda x: difflib.get_close_matches(x, df1['name'])[0])
df1.merge(df2)
52
ответ дан Andy Hayden 23 August 2018 в 22:45
поделиться

Вы можете использовать d6tjoin для этого

import d6tjocin.top1
d6tjoin.top1.MergeTop1(df1.reset_index(),df2.reset_index(),
       fuzzy_left_on=['index'],fuzzy_right_on=['index']).merge()['merged']

index number index_right letter 0 one 1 one a 1 two 2 too b 2 three 3 three c 3 four 4 fours d 4 five 5 five e

Он имеет множество дополнительных функций, таких как:

  • проверить качество соединения, предварительное и постсоединение
  • настроить функцию подобия, например, расстояние редактирования и расстояние hamming
  • указать максимальное расстояние
0
ответ дан citynorman 23 August 2018 в 22:45
поделиться

http://pandas.pydata.org/pandas-docs/dev/merging.html не имеет функции hook для этого на лету. Было бы неплохо, хотя ...

Я бы просто сделал отдельный шаг и использовал difflib getclosest_matches, чтобы создать новый столбец в одном из двух фреймов данных и слияние / объединение на нечетком совпадающем столбце

4
ответ дан locojay 23 August 2018 в 22:45
поделиться

Я бы использовал Jaro-Winkler, потому что это один из наиболее эффективных и точных приближенных алгоритмов сопоставления строк, доступных в настоящее время [ Cohen, et al. ], [ Winkler ].

Так я сделал бы это с Jaro-Winkler из пакета медузы :

def get_closest_match(x, list_strings):

  best_match = None
  highest_jw = 0

  for current_string in list_strings:
    current_score = jellyfish.jaro_winkler(x, current_string)

    if(current_score > highest_jw):
      highest_jw = current_score
      best_match = current_string

  return best_match

df1 = pandas.DataFrame([[1],[2],[3],[4],[5]], index=['one','two','three','four','five'], columns=['number'])
df2 = pandas.DataFrame([['a'],['b'],['c'],['d'],['e']], index=['one','too','three','fours','five'], columns=['letter'])

df2.index = df2.index.map(lambda x: get_closest_match(x, df1.index))

df1.join(df2)

Выход:

    number  letter
one     1   a
two     2   b
three   3   c
four    4   d
five    5   e
7
ответ дан lostsoul29 23 August 2018 в 22:45
поделиться

Как хэдз-ап, это в основном работает, за исключением случаев, когда совпадение не найдено, или если у вас есть NaNs в любом столбце. Вместо прямого применения get_close_matches мне было проще применить следующую функцию. Выбор заменителей NaN будет сильно зависеть от вашего набора данных.

def fuzzy_match(a, b):
    left = '1' if pd.isnull(a) else a
    right = b.fillna('2')
    out = difflib.get_close_matches(left, right)
    return out[0] if out else np.NaN
2
ответ дан Luke 23 August 2018 в 22:45
поделиться

Я написал пакет Python, целью которого является решение этой проблемы:

pip install fuzzymatcher

Здесь вы можете найти repo здесь и docs здесь .

Базовое использование:

Для двух фреймов данных df_left и df_right, которые вы хотите использовать нечеткое соединение, вы можете написать следующее:

from fuzzymatcher import link_table, left join

# Columns to match on from df_left
left_on = ["fname", "mname", "lname",  "dob"]

# Columns to match on from df_right
right_on = ["name", "middlename", "surname", "date"]

# The link table potentially contains several matches for each record
fuzzymatcher.link_table(df_left, df_right, left_on, right_on)

Или если вы просто хотите установить ссылку в ближайшем совпадении:

fuzzymatcher.fuzzy_left_join(df_left, df_right, left_on, right_on)
5
ответ дан RobinL 23 August 2018 в 22:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: