ECMAScript 6 имеет «генераторы», которые позволяют вам легко программировать в асинхронном стиле.
function* myGenerator() {
const callback = yield;
let [response] = yield $.ajax("https://stackoverflow.com", {complete: callback});
console.log("response is:", response);
// examples of other things you can do
yield setTimeout(callback, 1000);
console.log("it delayed for 1000ms");
while (response.statusText === "error") {
[response] = yield* anotherGenerator();
}
}
Для запуска вышеуказанного кода вы делаете это:
const gen = myGenerator(); // Create generator
gen.next(); // Start it
gen.next((...args) => gen.next([...args])); // Set its callback function
Если вам нужно настроить таргетинг на браузеры, которые не поддерживают ES6, вы можете запустить код через Babel или short-compiler для генерации ECMAScript 5.
Обратный вызов ...args
завернут в массив и разрушен, когда вы их читаете так что шаблон может справиться с обратными вызовами, которые имеют несколько аргументов. Например, с узлом fs :
const [err, data] = yield fs.readFile(filePath, "utf-8", callback);
Одно из возможных решений вашей проблемы - использовать merge . Проверка наличия любой строки (всех столбцов) из другого фрейма данных (df2) в df1 эквивалентна определению пересечения двух данных. Это может быть выполнено с помощью следующей функции:
pd.merge(df1, df2, on=['A', 'B', 'C', 'D'], how='inner')
Например, если df1 был
A B C D
0 0.403846 0.312230 0.209882 0.397923
1 0.934957 0.731730 0.484712 0.734747
2 0.588245 0.961589 0.910292 0.382072
3 0.534226 0.276908 0.323282 0.629398
4 0.259533 0.277465 0.043652 0.925743
5 0.667415 0.051182 0.928655 0.737673
6 0.217923 0.665446 0.224268 0.772592
7 0.023578 0.561884 0.615515 0.362084
8 0.346373 0.375366 0.083003 0.663622
9 0.352584 0.103263 0.661686 0.246862
, а df2 был определен как:
A B C D
0 0.259533 0.277465 0.043652 0.925743
1 0.667415 0.051182 0.928655 0.737673
2 0.217923 0.665446 0.224268 0.772592
3 0.023578 0.561884 0.615515 0.362084
4 0.346373 0.375366 0.083003 0.663622
5 2.000000 3.000000 4.000000 5.000000
6 14.000000 15.000000 16.000000 17.000000
Функция pd.merge(df1, df2, on=['A', 'B', 'C', 'D'], how='inner')
производит:
A B C D
0 0.259533 0.277465 0.043652 0.925743
1 0.667415 0.051182 0.928655 0.737673
2 0.217923 0.665446 0.224268 0.772592
3 0.023578 0.561884 0.615515 0.362084
4 0.346373 0.375366 0.083003 0.663622
Результаты - это все строки (все столбцы), которые находятся как в df1, так и в df2.
Мы также можем изменить этот пример если столбцы не совпадают в df1 и df2 и просто сравнивают значения строк, которые одинаковы для подмножества столбцов. Если мы изменим исходный пример:
df1 = pd.DataFrame(np.random.rand(10,4),columns=list('ABCD'))
df2 = df1.ix[4:8]
df2.reset_index(drop=True,inplace=True)
df2.loc[-1] = [2, 3, 4, 5]
df2.loc[-2] = [14, 15, 16, 17]
df2.reset_index(drop=True,inplace=True)
df2 = df2[['A', 'B', 'C']] # df2 has only columns A B C
Затем мы можем посмотреть на общие столбцы, используя common_cols = list(set(df1.columns) & set(df2.columns))
между двумя файлами данных, затем слить:
pd.merge(df1, df2, on=common_cols, how='inner')
EDIT: новый вопрос (комментарии), идентифицировав строки из df2, которые также присутствовали в первом фрейме данных (df1), можно взять результат pd.merge () и затем отбросить строки из df2, которые также присутствуют в df1
Я не знаю простого способа выполнить задачу по удалению строк из df2, которые также присутствуют в df1. Тем не менее, вы можете использовать следующее:
ds1 = set(tuple(line) for line in df1.values)
ds2 = set(tuple(line) for line in df2.values)
df = pd.DataFrame(list(ds2.difference(ds1)), columns=df2.columns)
Вероятно, существует лучший способ выполнить эту задачу, но я не знаю о таком методе / функции.
РЕДАКТИРОВАТЬ 2: Как удалить строки из df2, которые также присутствуют в df1, как показано в ответе @WR.
Предоставленный метод df2[~df2['A'].isin(df12['A'])]
не учитывает все типы ситуации. Рассмотрим следующие DataFrames:
df1:
A B C D
0 6 4 1 6
1 7 6 6 8
2 1 6 2 7
3 8 0 4 1
4 1 0 2 3
5 8 4 7 5
6 4 7 1 1
7 3 7 3 4
8 5 2 8 8
9 3 2 8 4
df2:
A B C D
0 1 0 2 3
1 8 4 7 5
2 4 7 1 1
3 3 7 3 4
4 5 2 8 8
5 1 1 1 1
6 2 2 2 2
df12:
A B C D
0 1 0 2 3
1 8 4 7 5
2 4 7 1 1
3 3 7 3 4
4 5 2 8 8
Использование выше DataFrames с целью удаления строк из df2, которые также присутствуют в df1, приведет к следующему:
A B C D
0 1 1 1 1
1 2 2 2 2
Строки (1, 1, 1, 1) и (2, 2, 2, 2) находятся в df2, а не в df1. К сожалению, использование предоставленного метода (df2[~df2['A'].isin(df12['A'])]
) приводит к:
A B C D
6 2 2 2 2
Это происходит из-за того, что значение 1 в столбце A находится как в пересечении DataFrame (т.е. (1, 0, 2, 3)) и df2 и таким образом удаляет оба (1, 0, 2, 3) и (1, 1, 1, 1). Это непреднамеренно, так как строка (1, 1, 1, 1) не находится в df1 и не должна удаляться.
Я думаю, что следующее будет служить решением. Он создает фиктивный столбец, который позже используется для подмножества DataFrame с желаемыми результатами:
df12['key'] = 'x'
temp_df = pd.merge(df2, df12, on=df2.columns.tolist(), how='left')
temp_df[temp_df['key'].isnull()].drop('key', axis=1)
@Andrew: Я считаю, что нашел способ отбросить строки одного кадра данных, которые уже присутствуют в другом (т. е. отвечать на мой EDIT), без использования циклов - сообщите мне, если вы не согласны и / или если мой OP + EDIT не ясно это сказал:
ЭТО РАБОТЫ
Столбы для обоих кадров данных всегда одинаковы - A
, B
, C
и D
. Имея это в виду, в основе которого лежит подход Андрея, вот как удалить строки из df2
, которые также присутствуют в df1
:
common_cols = df1.columns.tolist() #generate list of column names
df12 = pd.merge(df1, df2, on=common_cols, how='inner') #extract common rows with merge
df2 = df2[~df2['A'].isin(df12['A'])]
Строка 3 выполняет следующие действия:
df2
, которые не соответствуют строкам в df1
: A
, чтобы сделать это сравнение - можно использовать любые имена столбцов, но не ВСЕ имена столбцов. ПРИМЕЧАНИЕ. Этот метод по существу является эквивалентом SQL NOT IN()
.