#python #pandas #numpy #dataframe
#python #pandas #numpy #фрейм данных
Вопрос:
У меня есть два фрейма данных pandas: один с идентификаторами и значениями, а другой, который сопоставляет идентификаторы с другими идентификаторами. Цель состоит в том, чтобы создать новый фрейм данных, основанный на df1. Он перебирает каждый SourceID в df1 и ищет df2, отображающий df, для совпадений в SourceID. Если найдено совпадение, создается новая строка с тем же значением, что и в df1. Поэтому, если найдено несколько совпадений, цикл создает несколько строк (например, с идентификаторами A и C). Если найдено только одно совпадение (например, с идентификатором B), создается только одна строка.
Приведенный ниже код делает именно то, что я хочу, но делает это очень медленно. В моем исходном наборе данных df1 составляет 440 тыс. строк, а df2 имеет сопоставления для тысяч разных идентификаторов — в настоящее время код выполняется со скоростью 10-25 ит / с, что слишком много.
Есть ли более быстрый способ сделать это, который выиграет от матричных вычислений / других преимуществ numpy / pandas?
import pandas as pd
df1 = pd.DataFrame({
'SourceId': ['A', 'B', 'C', 'A', 'C', 'B'],
'value': [1, 5, 12, 30, 32, 55],
'time': [pd.to_datetime('2020-04-04 08:49:52.166498900 0000'),
pd.to_datetime('2020-08-14 06:12:40.860460500 0000'),
pd.to_datetime('2020-05-13 09:20:50.052688900 0000'),
pd.to_datetime('2020-03-09 13:55:17.335340600 0000'),
pd.to_datetime('2020-08-14 09:30:56.359635400 0000'),
pd.to_datetime('2020-01-31 23:03:46.539892900 0000')],
'otherInfo': ['0A10a', '055jA', 'boAqz', '0t,m5A', '09tjq1', 'akk_1!']})
df2 = pd.DataFrame({'SourceId': ['A', 'A', 'B', 'C', 'C', 'C'], 'TargetId': ['A', 'Q', 'B', 'C', 'B', 'X'], 'trueIfMatch': [1, 0, 1, 1, 0, 0]})
df3 = pd.DataFrame()
for r in df1.itertuples():
SourceId = r.SourceId
value = r.value
time = r.time
otherInfo = r.otherInfo
if SourceId in df2.SourceId.unique():
entries = df2.loc[df2.SourceId == SourceId].TargetId.tolist()
for entry in entries:
df3 = df3.append({
'sourceId': SourceId,
'targetId': entry,
'value': value,
'time': time,
'otherInfo': otherInfo
}, ignore_index=True)
display(df3)
Ответ №1:
Использовать df.merge
с sort_values
:
In [2293]: df3 = df1.merge(df2, on='SourceId').sort_values('value')
In [2294]: df3
Out[2294]:
SourceId value TargetId
0 A 1 A
1 A 1 Q
4 B 5 B
6 C 12 C
7 C 12 B
8 C 12 X
2 A 30 A
3 A 30 Q
9 C 32 C
10 C 32 B
11 C 32 X
5 B 55 B
Комментарии:
1. Спасибо, это сработало с предоставленными исходными простыми данными, но не с моими фактическими данными. Обновил вопрос лучшим примером данных, которые у меня действительно есть. РЕДАКТИРОВАТЬ: неважно, это все еще работает. Я должен выяснить, что так отличается от моих данных, однако это решение кажется правильным. Спасибо!