如何使用Pandas在没有字典的情况下处理保留ID列的行对?

2024-10-03 04:38:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一个更好的解决方案来解决我在研究中遇到的数据处理问题。我有一个Pandas DataFrame,我试图提取一个组(Frame)中特定列(Z)的所有值,保留由不同列(Name)给定的ID对。最终的结果不一定是熊猫的对象了,但它会很好地做到这一点完全在熊猫。这个任务用一个例子说明得最清楚。你知道吗

d=[['7500', '3.2900', '0', 'apple'],['7500', '-0.3500', '1', 'orange'],['7500', '-4.1400', '2', 'orange'],['7501', '3.4625', '0', 'apple'],['7501', '-0.2275', '1', 'apple'],['7501', '-4.1175', '2', 'orange'],['7502', '3.2087', '0', 'orange'],['7502', '-0.7313', '1', 'apple'],['7502', '-4.7513', '2', 'apple']]
df=pd.DataFrame(d, columns=["Frame","Z","Order","Name"])


>>> df
    Frame       Z   Order   Name
0   7500     3.2900 0   apple
1   7500    -0.3500 1   orange
2   7500    -4.1400 2   orange
3   7501     3.4625 0   apple
4   7501    -0.2275 1   apple
5   7501    -4.1175 2   orange
6   7502     3.2087 0   orange
7   7502    -0.7313 1   apple
8   7502    -4.7513 2   apple

因此,对于每个帧组,我想根据“顺序”列采用唯一的组合,因此对于帧7500组:

(0,1)
(0,2)
(1,2) 

但请注意,每组中的行数可以在1到5之间变化,而不仅仅是0、1、2。然后我会记录这些对的“Name”值

(apple, orange)
(apple, orange)
(orange, orange)

然后我会把这两个对的“Z”值取出来,如下所示:

( 3.2900, -0.3500)
( 3.2900, -4.1400)
(-0.3500, -4.1400)

最后,结合这些数据,我希望根据Name列为每一个唯一的对创建两个列表。在本例中,我们将这些列表称为第一个值和第二个值,但这完全是任意的

(apple, orange)
first_vals = [3.2900, 3.2900, ...]
second_vals = [-0.3500, -4.1400, ...]

(orange, orange)
first_vals = [-0.3500, ...]
second_vals = [-4.140, ...]

这里有一个解决办法,我想出了使用字典。它工作,但我认为它相当丑陋,它隐藏了字典键中的数据结构。本例依赖于按Order列对组进行预排序,但这实际上没有问题。你知道吗

from itertools import combinations
from collections import defaultdict

zpairs = defaultdict(list)

for name, group in df.groupby(["Frame"]):
    order_pairs = combinations(range(len(group)), 2)
    zvals = group["Z"].values
    rowids = group["Name"].values
    for pair in order_pairs:
        pair_str = str(rowids[pair[0]])+"-"+str(rowids[pair[1]])
        zpairs[pair_str+"-first"].append(zvals[pair[0]])
        zpairs[pair_str+"-second"].append(zvals[pair[1]])

该代码的结果如下所示:

>>> dict(zpairs)

{'apple-apple-first': ['3.4625', '-0.7313'],
'apple-apple-second': ['-0.2275', '-4.7513'],
'apple-orange-first': ['3.2900', '3.2900', '3.4625', '-0.2275'],
'apple-orange-second': ['-0.3500', '-4.1400', '-4.1175', '-4.1175'],
'orange-apple-first': ['3.2087', '3.2087'],
'orange-apple-second': ['-0.7313', '-4.7513'],
'orange-orange-first': ['-0.3500'],
'orange-orange-second': ['-4.1400']}

有没有一种方法来处理我的数据帧,它不依赖字典,也不使用字典键来存储数据?这并不是为了提高性能,但这会很有帮助。你知道吗


Tags: 数据nameappledf字典grouporderframe
1条回答
网友
1楼 · 发布于 2024-10-03 04:38:14

以下是一个熊猫方法,分两步完成:

  1. 获取每个帧组的名称和Z值对。你知道吗
  2. 组合每对名称的Z值分量。你知道吗

步骤1

为了获得名称和z值对,我将编写一个助手函数get_group_pairs,在执行groupby时调用它。我正在做一个与您在循环中所做的类似的过程,但是在DataFrame中返回输出:

def get_group_pairs(grp):
    pairs = combinations(grp.index, 2)
    data = [grp.loc[p, ('Name', 'Z')].values.flatten('F') for p in pairs]
    return pd.DataFrame(data, columns=['Name1', 'Name2', 'Z1', 'Z2'])

namepairs = df.groupby('Frame').apply(get_group_pairs).reset_index(level=1, drop=True)

执行reset_index纯粹是为了删除不必要的索引级别,以便中间输出看起来很好。如果你不关心中间输出,那就没有必要了。中间输出namepairs

        Name1   Name2       Z1       Z2
Frame                                  
7500    apple  orange   3.2900  -0.3500
7500    apple  orange   3.2900  -4.1400
7500   orange  orange  -0.3500  -4.1400
7501    apple   apple   3.4625  -0.2275
7501    apple  orange   3.4625  -4.1175
7501    apple  orange  -0.2275  -4.1175
7502   orange   apple   3.2087  -0.7313
7502   orange   apple   3.2087  -4.7513
7502    apple   apple  -0.7313  -4.7513

步骤2

与步骤1中相同的helper函数/groupby/apply模式。实际上,我只是使用这两个名称分组,然后将两个Z列转换为列表:

def merge_zpairs(grp):
    data = {'Z1': grp['Z1'].tolist(), 'Z2': grp['Z2'].tolist()}
    return pd.Series(data)

zpairs = namepairs.groupby(['Name1', 'Name2']).apply(merge_zpairs).reset_index()

同样地,reset_index也不是绝对必要的。没有它,你会得到一个由成对的名字组成的MultiIndex。这将产生最终输出zpairs

    Name1   Name2                                 Z1                                    Z2
0   apple   apple                  [3.4625, -0.7313]                    [-0.2275, -4.7513]
1   apple  orange  [3.2900, 3.2900, 3.4625, -0.2275]  [-0.3500, -4.1400, -4.1175, -4.1175]
2  orange   apple                   [3.2087, 3.2087]                    [-0.7313, -4.7513]
3  orange  orange                          [-0.3500]                             [-4.1400]

组合代码

为方便起见,以下是步骤1和步骤2的代码:

def get_group_pairs(grp):
    pairs = combinations(grp.index, 2)
    data = [grp.loc[p, ('Name', 'Z')].values.flatten('F') for p in pairs]
    return pd.DataFrame(data, columns=['Name1', 'Name2', 'Z1', 'Z2'])

def merge_zpairs(grp):
    data = {'Z1': grp['Z1'].tolist(), 'Z2': grp['Z2'].tolist()}
    return pd.Series(data)

namepairs = df.groupby('Frame').apply(get_group_pairs).reset_index(level=1, drop=True)
zpairs = namepairs.groupby(['Name1', 'Name2']).apply(merge_zpairs).reset_index()

获取词典

您可以得到与您的字典结构类似的字典结构,尽管不完全相同,但只需对步骤2代码进行一些小的修改。本质上,不要使用reset_index,而是将to_dictorient='index'一起使用:

zpairs = namepairs.groupby(['Name1', 'Name2']).apply(merge_zpairs)
zpairs_dict = zpairs.to_dict(orient='index')

这将生成一个字典字典:第一个键是一对名称,第二个键是所需的Z值。例如,'apple-apple-first'的语法是:

zpairs_dict[('apple', 'apple')]['Z1']

相关问题 更多 >