逐行比较2个Pandas嵌套,并对每行执行计算

sqougxex  于 2023-10-14  发布在  其他
关注(0)|答案(2)|浏览(123)

我已经创建了2个Pandas嵌套框,我需要通过一个2列距离函数将DF 1中的行与DF 2中的行进行比较。
基本上,我需要DF 2中的每一行都与DF 1中的第1行进行比较;将DF 2中的每一行与DF 1中的第2行进行比较,等等,前提是它们具有相同的受试者编号相同的试验编号。如果得到的距离值小于特定的阈值,我需要在新列中记录来自DF 2的行。
我对Pandas非常陌生,所以我不太确定从哪里开始,但我在下面详细介绍了我的问题的一步一步的逻辑。
这里是我的2个框架(样本-实际的框架将非常大; 10,000+行):
DF1:
| IP_索引|IP_标签|参与者|审判|CURRENT_FIX_INDEX| PRE_FIX_X|修复前Y|
| --|--|--|--|--|--|--|
| 1 |第一个3秒|一| 1 | 1 | 550 | 150 |
| 1 |第一个3秒|一| 1 | 2 | 600 | 300 |
| 1 |第一个3秒|一| 2 | 1 | 250 | 600 |
| 1 |第一个3秒|B| 1 | 1 | 400 | 400 |
| 1 |第一个3秒|B| 2 | 1 | 600 | 400 |
DF2:
| IP_索引|IP_标签|参与者|审判|CURRENT_FIX_INDEX| POST_FIX_X| POST_FIX_Y|
| --|--|--|--|--|--|--|
| 2 |第二个3秒|一| 1 | 1 | 500 | 200 |
| 2 |第二个3秒|一| 1 | 2 | 650 | 350 |
| 2 |第二个3秒|一| 2 | 1 | 300 | 650 |
| 2 |第二个3秒|B| 1 | 1 | 250 | 700 |
| 2 |第二个3秒|B| 1 | 2 | 450 | 150 |
| 2 |第二个3秒|B| 2 | 1 | 550 | 350 |
| 2 |第二个3秒|B| 2 | 2 | 350 | 550 |
以下是我需要的(任何给定行的示例):
1.在DF 1中创建一个名为“REFIX”的新列。这将是空白的,但单元格将根据下面的公式填写。
1.如果DF 2“参与者”== DF 1“参与者 * 且 * DF 2”试验“== DF 1”试验“,
1.然后计算math.dist(p,q),其中p和q由DF 1和DF 2的 _FIX_X和 _FIX_Y值定义( 代表PRE或POST,取决于它是DF 1还是DF 2)。
1.否则(
即如果DF 2“参与者”!= DF 1“参与者”* 或 * DF 2“试验”!= DF 1 'TRIAL')*,然后移到DF 2中的下一行
1.如果math.dist(p,q)的结果<= 150,则在DF 1中的“REFIX”列(对于我们在DF 1中的行)中填充DF 2中的CURRENT_FIX_INDEX的值(对于我们在DF 2中的行)
1.保存DF 1作为新的csv文件
我不确定我在这里是否正确,但这是我为math.dist(p,q)函数确定p和q值的方法:

# Define p and q values for distance calculation
p = [(df1['PRE_FIX_X']), (df1['PRE_FIX_Y'])]
q = [(df2['POST_FIX_X']), (df2['POST_FIX_Y'])]

基于给出的示例框架,一个完整的DF 1文件看起来像这样:
| IP_索引|IP_标签|参与者|审判|CURRENT_FIX_INDEX| PRE_FIX_X|修复前Y|重新固定|
| --|--|--|--|--|--|--|--|
| 1 |第一个3秒|一| 1 | 1 | 550 | 150 | 1 |
| 1 |第一个3秒|一| 1 | 2 | 600 | 300 |一二|
| 1 |第一个3秒|一| 2 | 1 | 250 | 600 | 1 |
| 1 |第一个3秒|B| 1 | 1 | 400 | 400 ||
| 1 |第一个3秒|B| 2 | 1 | 600 | 400 | 1 |

sc4hvdpw

sc4hvdpw1#

  • 已编辑:现在包括注解中要求的每个试验的REFIX计数

你的问题看起来很复杂,有点难以理解,但我认为这可能是你想要的?
我不认为用嵌套的if语句迭代两个df是最有效的方法,但我现在想不出更好的选择:)
第1部分:加载您提供的数据:(你显然可以忽略这一点,但为了便于再现性/测试,把它放进去:

import pandas as pd

# Define the data for DF1
data_df1 = {
    'IP_INDEX': [1, 1, 1, 1, 1],
    'IP_LABEL': ['1st 3 Seconds', '1st 3 Seconds', '1st 3 Seconds', '1st 3 Seconds', '1st 3 Seconds'],
    'PARTICIPANT': ['a', 'a', 'a', 'b', 'b'],
    'TRIAL': [1, 1, 2, 1, 2],
    'CURRENT_FIX_INDEX': [1, 2, 1, 1, 1],
    'PRE_FIX_X': [550, 600, 250, 400, 600],
    'PRE_FIX_Y': [150, 300, 600, 400, 400]
}

# Create DF1
df1 = pd.DataFrame(data_df1)

data_df2 = {
    'IP_INDEX': [2, 2, 2, 2, 2, 2, 2],
    'IP_LABEL': ['2nd 3 Seconds', '2nd 3 Seconds', '2nd 3 Seconds', '2nd 3 Seconds', '2nd 3 Seconds', '2nd 3 Seconds', '2nd 3 Seconds'],
    'PARTICIPANT': ['a', 'a', 'a', 'b', 'b', 'b', 'b'],
    'TRIAL': [1, 1, 2, 1, 1, 2, 2],
    'CURRENT_FIX_INDEX': [1, 2, 1, 1, 2, 1, 2],
    'POST_FIX_X': [500, 650, 300, 250, 450, 550, 350],
    'POST_FIX_Y': [200, 350, 650, 700, 150, 350, 550]
}

# Create DF2
df2 = pd.DataFrame(data_df2)

第二部分:计算:

import math

#Create function to calculate distance between coordinates
def calculate_distance(df1_row,df2_row):
    p = (df1_row['PRE_FIX_X'], df1_row['PRE_FIX_Y'])
    q = (df2_row['POST_FIX_X'], df2_row['POST_FIX_Y'])
    return math.dist(p, q)

refix_values = [] #Create empty list to hold lists of matching FIX_INDEX values in df2

for index, df1_row in df1.iterrows(): #Iterate through each row in df1
    fix_index_list = [] #Create empty list to hold matching INDEX values for loop row
    df2_subset = df2.loc[(df2['PARTICIPANT'] == df1_row['PARTICIPANT']) & (df2['TRIAL'] == df1_row['TRIAL'])] #Subset out matching data in df2 so we're not looping through the entirety of df2
    for i, df2_row in df2_subset.iterrows(): #Iterate through df2 subset
        dist = calculate_distance(df1_row,df2_row) #Calculate dist for each row
        if dist <= 150:
            fix_index_list.append(df2_row['CURRENT_FIX_INDEX']) #Add dist to list if greater or equal to 150
    refix_values.append(','.join(map(str, fix_index_list))) #Add list of matching INDEX values to list of lists

df1['REFIX'] = refix_values #Convert list of lists to new column

def count_refix_items(row_refix_value):
    integers = [int(s) for s in row_refix_value.split(',') if s.isdigit()] #Split string by commas and count resultant elements
    return len(integers)

refix_per_trial = df1[df1['REFIX'].notna()].groupby(['TRIAL','PARTICIPANT'])['REFIX'].apply(lambda x: x.apply(count_refix_items).sum()).reset_index()
refix_per_trial = refix_per_trial.rename(columns={'REFIX': 'REFIXes/trial/participant'}) #Rename column

df1 = pd.merge(df1, refix_per_trial, on = ['TRIAL','PARTICIPANT'], how = 'outer')

#Write df to csv
df1.to_csv('REFIX_calc_output.tab', sep='\t', index=False) #Change name of file to whatever you want

我使用你提供的输入得到的输出:
| IP_索引|IP_标签|参与者|审判|CURRENT_FIX_INDEX| PRE_FIX_X|修复前Y|重新固定|REFIX/试验/受试者|
| --|--|--|--|--|--|--|--|--|
| 1 |第一个3秒|一| 1 | 1 | 550 | 150 | 1 | 3 |
| 1 |第一个3秒|一| 1 | 2 | 600 | 300 |一二| 3 |
| 1 |第一个3秒|一| 2 | 1 | 250 | 600 | 1 | 1 |
| 1 |第一个3秒|B| 1 | 1 | 400 | 400 || 0 |
| 1 |第一个3秒|B| 2 | 1 | 600 | 400 | 1 | 1 |

ldioqlga

ldioqlga2#

  1. merge两个 Dataframe
    1.计算距离
    1.当距离小于150时指定REFIX
    1.将REFIX化为字符串以进行聚合
  2. groupbyagg以获得所需的输出
merged = df1.merge(df2, on=["PARTICIPANT","TRIAL"], suffixes=("","_y"))
merged["DIST"] = (merged["PRE_FIX_X"].sub(merged["POST_FIX_X"]).pow(2).add(merged["PRE_FIX_Y"].sub(merged["POST_FIX_Y"]).pow(2))).pow(0.5)
merged["REFIX"] = merged["CURRENT_FIX_INDEX_y"].where(merged["DIST"].lt(150))
merged["REFIX"] = merged["REFIX"].fillna(0).astype(int).astype(str).replace({"0":""})

output = merged.groupby(list(df1.columns), as_index=False)["REFIX"].agg(",".join)
output["REFIX"] = output["REFIX"].str.rstrip(",")

>>> output
   IP_INDEX       IP_LABEL PARTICIPANT  TRIAL  CURRENT_FIX_INDEX  PRE_FIX_X  \
0         1  1st 3 Seconds           a      1                  1        550   
1         1  1st 3 Seconds           a      1                  2        600   
2         1  1st 3 Seconds           a      2                  1        250   
3         1  1st 3 Seconds           b      1                  1        400   
4         1  1st 3 Seconds           b      2                  1        600   

   PRE_FIX_Y REFIX  
0        150     1  
1        300   1,2  
2        600     1  
3        400        
4        400     1

相关问题