Python/R 中两个不同大小的数据帧中的 1 到 2 匹配
1 to 2 matching in two dataframes with different sizes in Python/R
请帮我解决这个问题,我整天都在苦苦挣扎,哈哈,Python 或 R 中的解决方案都可以! 请帮助我真的卡住了!!!
我有两个数据框——df1 有 44 行,df2 有 100 行,它们都有这些列:
ID、状态 (0,1)、年龄、性别、种族、民族、身高、体重
对于 df1 中的每一行,我需要在 df2 中找到 age 匹配项:
- 它可以是精确的年龄匹配,但应该使用的标准是 - df2[age]-5 <= df1[age]<= df2[age]+5
- 我需要一个 list/dictionary 来存储哪些是 df1 的年龄匹配,以及他们的 ID
- 然后我需要从df2中随机select 2个ID作为df1 age
的最终匹配
- 我还需要确保 2 个 df2 匹配项与 df1
具有相同的性别和种族
我试过 R 和 Python,都卡在嵌套循环部分。
我不确定如何遍历 df1 和 df2 的每条记录,将 df1 age 与 df2 age-5 和 df2 age+5 进行比较,并存储匹配项
以下是 df1 和 df2 的示例数据格式:
|编号 |性别 |年龄 |比赛 |
| ------ | -------------- |--------|--------|
| 284336 |女性 | 42.8 | 2 |
| 294123 |男性 | 48.5 | 1 |
这是我在 R 中的尝试:
id_match <- NULL
for (i in 1:nrow(gwi_case)){
age <- gwi_case$age[i]
gender <- gwi_case$gender[i]
ethnicity <- gwi_case$hispanic_non[i]
race <- gwi_case$race[i]
x <- which(gwi_control$gender==gender & gwi_control$age>=age-5 & gwi_control$age<=age+5 & gwi_control$hispanic_non==ethnicity & gwi_control$race==race)
y <- sample(x, min(2, length(x)))
id_match <- c(id_match, y)
}
id_match <- id_match[!duplicated(id_match)]
length(id_match)
不确定我是否完全理解要求,但是...在 python 中,您可以使用应用于数据框和 lambda 函数来执行一些时髦的事情
df1['age_matched_ids'] = df1.apply(lambda x: list(df2.loc[df2['Age'] >= x['Age'] - 5 & df2['Age'] <= x['Age'] + 5, 'ID']), axis=1)
这将在 'age_matched_ids' 列中存储 df2 中年龄在 +/- 5 岁之间的 ID 列表。您可以从这里执行#2 和#3。
问题是这样问的:
- 对于
df1
中的每一行,找到 df2
中的年龄匹配,使得 df2[age] - 5 <= df1[age] <= df2[age] + 5
- 创建一个 list/dictionary 来保存 df1
的年龄匹配和 ID
- 随机select来自df2的2个ID作为df1年龄的最终匹配
这是一些 Python 代码:
- 使用条件填充列表列表
ageMatches
,其中包含与每个唯一 df1
年龄 匹配的唯一 df2
年龄列表
- 为
df1
中的每个年龄在 df2
上调用 DataFrame.query()
以填充 idMatches
与年龄匹配每个唯一 df1
年龄
- 使用唯一的
df1
年龄键填充 age1ToID2
并使用 2 个(或更少,如果可用数量 < 2)列表的值随机 selected df2
ID匹配年龄
- 向
df1
添加一列,其中包含一对 selected df2
ID 对应于每一行的年龄(即 age1ToID2
中的值)
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'ID':list(range(101,145)), 'Age':[v % 11 + 21 for v in range(44)], 'Height':[67]*44})
df2 = pd.DataFrame({'ID':list(range(1,101)), 'Age':[v % 10 + 14 for v in range(50)] + [v % 20 + 25 for v in range(0,100,2)], 'Height':[67]*100})
ages1 = np.sort(df1['Age'].unique())
ages2 = np.sort(df2['Age'].unique())
ageMatches = [[] for _ in ages1]
j1, j2 = 0, 0
for i, age1 in enumerate(ages1):
while j1 < len(ages2) and ages2[j1] < age1 - 5:
j1 += 1
if j2 <= j1:
j2 = j1 + 1
while j2 < len(ages2) and ages2[j2] <= age1 + 5:
j2 += 1
ageMatches[i] += list(ages2[j1:j2])
idMatches = [df2.query('Age in @m')['ID'].to_list() for i, m in enumerate(ageMatches)]
# select random pair of df2 IDs for each unique df1 age and put them into a new df1 column
from random import sample
age1ToID2 = {ages1[i]:m if len(m) < 2 else sample(m, 2) for i, m in enumerate(idMatches)}
df1['df2_matches'] = df1['Age'].apply(lambda x: age1ToID2[x])
print(df1)
输出:
ID Age Height df2_matches
0 101 21 67 [24, 30]
1 102 22 67 [50, 72]
2 103 23 67 [10, 37]
3 104 24 67 [63, 83]
4 105 25 67 [83, 49]
5 106 26 67 [20, 52]
6 107 27 67 [49, 84]
7 108 28 67 [54, 55]
8 109 29 67 [91, 55]
9 110 30 67 [65, 51]
10 111 31 67 [75, 72]
11 112 21 67 [24, 30]
...
42 143 30 67 [65, 51]
43 144 31 67 [75, 72]
这有望提供 OP 要求的结果和中间集合,或者足够接近以获得所需结果的东西。
或者,要让 df1
中每一行的随机 selection 不同,我们可以这样做:
# select random pair of df2 IDs for each df1 row and put them into a new df1 column
from random import sample
age1ToID2 = {ages1[i]:m for i, m in enumerate(idMatches)}
def foo(x):
m = age1ToID2[x]
return m if len(m) < 2 else sample(m, 2)
df1['df2_matches'] = df1['Age'].apply(foo)
print(df1)
输出:
ID Age Height df2_matches
0 101 21 67 [71, 38]
1 102 22 67 [71, 5]
2 103 23 67 [9, 38]
3 104 24 67 [49, 61]
4 105 25 67 [27, 93]
5 106 26 67 [40, 20]
6 107 27 67 [9, 19]
7 108 28 67 [53, 72]
8 109 29 67 [82, 53]
9 110 30 67 [74, 62]
10 111 31 67 [52, 62]
11 112 21 67 [71, 39]
...
42 143 30 67 [96, 66]
43 144 31 67 [63, 83]
请帮我解决这个问题,我整天都在苦苦挣扎,哈哈,Python 或 R 中的解决方案都可以! 请帮助我真的卡住了!!!
我有两个数据框——df1 有 44 行,df2 有 100 行,它们都有这些列: ID、状态 (0,1)、年龄、性别、种族、民族、身高、体重
对于 df1 中的每一行,我需要在 df2 中找到 age 匹配项:
- 它可以是精确的年龄匹配,但应该使用的标准是 - df2[age]-5 <= df1[age]<= df2[age]+5
- 我需要一个 list/dictionary 来存储哪些是 df1 的年龄匹配,以及他们的 ID
- 然后我需要从df2中随机select 2个ID作为df1 age 的最终匹配
- 我还需要确保 2 个 df2 匹配项与 df1 具有相同的性别和种族
我试过 R 和 Python,都卡在嵌套循环部分。 我不确定如何遍历 df1 和 df2 的每条记录,将 df1 age 与 df2 age-5 和 df2 age+5 进行比较,并存储匹配项
以下是 df1 和 df2 的示例数据格式: |编号 |性别 |年龄 |比赛 | | ------ | -------------- |--------|--------| | 284336 |女性 | 42.8 | 2 | | 294123 |男性 | 48.5 | 1 |
这是我在 R 中的尝试:
id_match <- NULL
for (i in 1:nrow(gwi_case)){
age <- gwi_case$age[i]
gender <- gwi_case$gender[i]
ethnicity <- gwi_case$hispanic_non[i]
race <- gwi_case$race[i]
x <- which(gwi_control$gender==gender & gwi_control$age>=age-5 & gwi_control$age<=age+5 & gwi_control$hispanic_non==ethnicity & gwi_control$race==race)
y <- sample(x, min(2, length(x)))
id_match <- c(id_match, y)
}
id_match <- id_match[!duplicated(id_match)]
length(id_match)
不确定我是否完全理解要求,但是...在 python 中,您可以使用应用于数据框和 lambda 函数来执行一些时髦的事情
df1['age_matched_ids'] = df1.apply(lambda x: list(df2.loc[df2['Age'] >= x['Age'] - 5 & df2['Age'] <= x['Age'] + 5, 'ID']), axis=1)
这将在 'age_matched_ids' 列中存储 df2 中年龄在 +/- 5 岁之间的 ID 列表。您可以从这里执行#2 和#3。
问题是这样问的:
- 对于
df1
中的每一行,找到df2
中的年龄匹配,使得df2[age] - 5 <= df1[age] <= df2[age] + 5
- 创建一个 list/dictionary 来保存 df1 的年龄匹配和 ID
- 随机select来自df2的2个ID作为df1年龄的最终匹配
这是一些 Python 代码:
- 使用条件填充列表列表
ageMatches
,其中包含与每个唯一df1
年龄 匹配的唯一 - 为
df1
中的每个年龄在df2
上调用DataFrame.query()
以填充idMatches
与年龄匹配每个唯一df1
年龄 - 使用唯一的
df1
年龄键填充age1ToID2
并使用 2 个(或更少,如果可用数量 < 2)列表的值随机 selecteddf2
ID匹配年龄 - 向
df1
添加一列,其中包含一对 selecteddf2
ID 对应于每一行的年龄(即age1ToID2
中的值)
df2
年龄列表
import pandas as pd
import numpy as np
df1 = pd.DataFrame({'ID':list(range(101,145)), 'Age':[v % 11 + 21 for v in range(44)], 'Height':[67]*44})
df2 = pd.DataFrame({'ID':list(range(1,101)), 'Age':[v % 10 + 14 for v in range(50)] + [v % 20 + 25 for v in range(0,100,2)], 'Height':[67]*100})
ages1 = np.sort(df1['Age'].unique())
ages2 = np.sort(df2['Age'].unique())
ageMatches = [[] for _ in ages1]
j1, j2 = 0, 0
for i, age1 in enumerate(ages1):
while j1 < len(ages2) and ages2[j1] < age1 - 5:
j1 += 1
if j2 <= j1:
j2 = j1 + 1
while j2 < len(ages2) and ages2[j2] <= age1 + 5:
j2 += 1
ageMatches[i] += list(ages2[j1:j2])
idMatches = [df2.query('Age in @m')['ID'].to_list() for i, m in enumerate(ageMatches)]
# select random pair of df2 IDs for each unique df1 age and put them into a new df1 column
from random import sample
age1ToID2 = {ages1[i]:m if len(m) < 2 else sample(m, 2) for i, m in enumerate(idMatches)}
df1['df2_matches'] = df1['Age'].apply(lambda x: age1ToID2[x])
print(df1)
输出:
ID Age Height df2_matches
0 101 21 67 [24, 30]
1 102 22 67 [50, 72]
2 103 23 67 [10, 37]
3 104 24 67 [63, 83]
4 105 25 67 [83, 49]
5 106 26 67 [20, 52]
6 107 27 67 [49, 84]
7 108 28 67 [54, 55]
8 109 29 67 [91, 55]
9 110 30 67 [65, 51]
10 111 31 67 [75, 72]
11 112 21 67 [24, 30]
...
42 143 30 67 [65, 51]
43 144 31 67 [75, 72]
这有望提供 OP 要求的结果和中间集合,或者足够接近以获得所需结果的东西。
或者,要让 df1
中每一行的随机 selection 不同,我们可以这样做:
# select random pair of df2 IDs for each df1 row and put them into a new df1 column
from random import sample
age1ToID2 = {ages1[i]:m for i, m in enumerate(idMatches)}
def foo(x):
m = age1ToID2[x]
return m if len(m) < 2 else sample(m, 2)
df1['df2_matches'] = df1['Age'].apply(foo)
print(df1)
输出:
ID Age Height df2_matches
0 101 21 67 [71, 38]
1 102 22 67 [71, 5]
2 103 23 67 [9, 38]
3 104 24 67 [49, 61]
4 105 25 67 [27, 93]
5 106 26 67 [40, 20]
6 107 27 67 [9, 19]
7 108 28 67 [53, 72]
8 109 29 67 [82, 53]
9 110 30 67 [74, 62]
10 111 31 67 [52, 62]
11 112 21 67 [71, 39]
...
42 143 30 67 [96, 66]
43 144 31 67 [63, 83]