检查元素是否是邻居,然后创建一个新列

check if an element is a neighbor and then create a new column

我有一个数据框,它由五列“ID”、“Name”、“pos_x”、“pos_y”和“Volume”组成,如下所示:

ID | Name | pos_x | pos_y | volume
1  |  A   |  1    |  1.5  |  10
2  |  A   |  3.5  |  3    |   6
3  |  A   |  4    |  4    |   8
4  |  A   |  4.5  |  4.5  |   9
5  |  A   |  5    |  6    |  10
1  |  B   |  1.2  |  1.2  |   4
3  |  B   |  4.3  |  4.4  |   8
4  |  B   |  4.5  |  4.2  |   7
2  |  C   |  3    |  3.3  |   9
3  |  C   |  4.2  |  4.1  |  10

我现在想在数据框 ("volume_avg") 中创建一个新列,其中计算所有 ID 的体积的平均值,其半径在 2.5 毫米到各自的ID。

我的想法是先运行遍历每个名​​字的每个ID(因为名字+ID是主键)然后看每个ID的位置x和y。使用 if 循环,然后我将检查 ID 是否是邻居。

所以条件是:

if pos_x(当前 ID)< pos_x(所有其他 ID)- 2.5 或 > pos_x(所有其他 ID)+ 2.5

else if pos_y(当前 ID)< pos_y(所有其他 ID)- 2.5 或 > pos_y(所有其他 ID)+ 2.5

然后计算 sum(volume)/count(ID's)

否则什么都没有

不幸的是,我不知道如何在 python 代码中写下这些注意事项.... 如果你能帮助我,我会很高兴。非常感谢。

大卫

我将 if 和 else 部分中的条件解释为 (x,y) 坐标上的矩形限制。如果这不正确,请告诉我,我可以调整 if/else.

中的逻辑
import pandas as pd

# create the structure of example dataframe
df = pd.DataFrame([[1, 'A', 1, 1.5, 10],
                   [2, 'A', 3.5, 3, 6],
                   [3, 'A', 4, 4, 8],
                   [4, 'A', 4.5, 4.5, 9],
                   [5 ,'A' , 5 , 6 , 10],
                   [1 ,'B' , 1.2 , 1.2 , 4],
                   [3 ,'B' , 4.3 , 4.4 , 8],
                   [4 ,'B' , 4.5 , 4.2 , 7],
                   [2 ,'C' , 3 , 3.3 , 9],
                   [3 ,'C' , 4.2 , 4.1 , 10],
                   ],
                  columns=['ID', 'Name', 'pos_x', 'pos_y', 'volume'])

# create volume average with rows that meet criterion
volume_avgs = []
for g, grouper in df.groupby('Name'):
    for base_row in grouper.iterrows():
        v_sum = 0
        v_count = 0
        for row in grouper.iterrows():
            if row[1].ID == base_row[1].ID: # skip the item itself
                continue
            elif abs(row[1].pos_x - base_row[1].pos_x) < 2.5 or abs(row[1].pos_y - base_row[1].pos_y) < 2.5:
                 v_sum += row[1].volume
                 v_count += 1
        volume_avgs.append([base_row[1].ID, g, v_sum / v_count if v_count > 0 else 0, v_count])

df_vol_avgs = pd.DataFrame(volume_avgs, columns=['ID', 'Name', 'volume_avg', 'volume_count'])

merged_df = df.merge(df_vol_avgs, on=['ID', 'Name'])
merged_df

请注意,如果实际数据很大,这可能不会很好地扩展。由于双 for 循环,特别是对于具有大量数据的组。此外,如果您想要 NoneNan 如果附近的平均点总数为 0,您可以将 if/else 从

更改为
v_sum / v_count if v_count > 0 else 0

v_sum / v_count if v_count > 0 else None

对于 None 的情况和 Nan 的情况类似,比如使用 numpy.nan

我找到了一种可行的方法,但它不是最干净的方法,可能可以通过多种方式进行优化。

首先,我们导入 pandas 并创建数据框:

import pandas as pd
ID = [1,2,3,4,5,1,3,4,2,3]
name = ["A","A","A","A","A","B","B","B","C","C"]
pos_x = [1,3.5,4,4.5,5,1.2,4.3,4.5,3,4.2]
pos_y = [1.5,3,4,4.5,6,1.2,4.4,4.2,3.3,4.1]
volume = [10,6,8,9,10,4,8,7,9,10]
dict = {"ID": ID, "name": name, "pos_x":pos_x, "pos_y":pos_y,"volume":volume}
df = pd.DataFrame(dict)

然后,我们声明一个空列表来存储我们的结果并迭代数据框:

values = []
for i in df.itertuples():
    posX = i.pos_x
    posY = i.pos_y
    counter = 0
    volume_counter = 0
    for j in df.itertuples():
        if i == j:
            pass
        elif abs(j.pos_x - posX) <= 2.5 and abs(j.pos_y - posY) <= 2.5:
            counter += 1
            volume_counter += j.volume
        else:
            pass
    values.append(round(volume_counter/counter,2))

对于数据框的每一行,我们得到 x 和 y 位置。我们也将counter和volume_counter设置为0。Counter统计有多少物品满足距离其他位置2.5mm以内的条件,volume_counter将满足条件的行的体积相加。

然后,我们对数据框中的每一行再次迭代。第一个 if 子句丢弃值本身(如果你想在数据框中包含每个对象的体积,你可以简单地删除这个子句),elif 子句检查 x_pos 和 y_pos 是否是在 2.5 毫米的绝对距离内。

最后,我们将总体积除以项目数量(我也将结果四舍五入到小数点后两位,但如果您想要更多小数位,也可以将其删除)。这为我们提供了以下列表:

[6.33, 8.12, 8.43, 8.29, 8.4, 8.33, 8.43, 8.57, 7.75, 8.14]

因此,我们可以将计算出的列表加入到原始数据框中。

df["volume_avg"] = values
df

输出结果如下:

   ID name pos_x  pos_y  volume volume_avg
0   1   A   1.0     1.5     10  6.33
1   2   A   3.5     3.0     6   8.12
2   3   A   4.0     4.0     8   8.43
3   4   A   4.5     4.5     9   8.29
4   5   A   5.0     6.0     10  8.40
5   1   B   1.2     1.2     4   8.33
6   3   B   4.3     4.4     8   8.43
7   4   B   4.5     4.2     7   8.57
8   2   C   3.0     3.3     9   7.75
9   3   C   4.2     4.1     10  8.14

希望对您有所帮助。我确信有更简洁的方法可以做到这一点,我也非常感谢对提议的解决方案的反馈!