Python 从按另一列分组的元素返回列表列表

Python 从按另一列分组的元素返回列表列表,python,pandas,dataframe,group-by,Python,Pandas,Dataframe,Group By,我不知道如何描述我的问题,所以我将在这里展示一个示例 A B 1 3 1 4 2 5 2 8 2 6 3 6 3 8 4 10 4 1 数据框有两列A和B。我想让它返回这样一个列表 [[3,4],[5,8,6],[6,8],[10,1]] 如您所见,它按A分组,并返回B列中的数字列表。需要注意的是,B中元素的顺序没有改变。此外,子列表的顺序与A列中所示的顺序相同。(组1中的[3,4],组2中的[5,8,6],等等) 假设dataframe已由一个。我知道如何使用for循环来实现它,但我的数据

我不知道如何描述我的问题,所以我将在这里展示一个示例

A B
1 3
1 4
2 5
2 8
2 6
3 6
3 8
4 10
4 1
数据框有两列A和B。我想让它返回这样一个列表

[[3,4],[5,8,6],[6,8],[10,1]]
如您所见,它按
A
分组,并返回
B
列中的数字列表。需要注意的是,
B
中元素的顺序没有改变。此外,子列表的顺序与A列中所示的顺序相同。(组1中的
[3,4]
,组2中的
[5,8,6]
,等等)


假设dataframe已由一个。我知道如何使用for循环来实现它,但我的数据集有10亿条记录。因此,我正在寻找一些有效且干净的代码来解决这个问题。

您首先需要在第一列
A
上分组,然后在
B
中获取唯一值(假设您只需要唯一值而不需要重复值)。完成此操作后,使用lambda表达式将每个np.array值转换为列表,然后使用
.tolist()
将生成的序列转换为列表

或者

或者

我还建议不要对groupby操作进行排序

以下是一些有兴趣的人的时间比较:

df_ = pd.concat([df] * 10000)  # Set-up larger dataframe with 90k rows.

%timeit df_.groupby('A', sort=False)['B'].unique().apply(list).tolist()
# 100 loops, best of 3: 5.9 ms per loop

%timeit df_.groupby('A', sort=False)['B'].apply(list).tolist()
# 100 loops, best of 3: 6.79 ms per loop

%timeit list(map(list, df_.groupby('A', sort=False)['B'].apply(list)))
# 100 loops, best of 3: 8.02 ms per loop
另一种方法是将
list
应用于
groupby.apply(list)
对象的每个元素

一般来说,我更喜欢这个解决方案,而不是基于
lambda
的解决方案,它只是一个循环

res = list(map(list, df.groupby('A', sort=False)['B'].apply(list)))
结果:

[[3, 4], [5, 8, 6], [6, 8], [10, 1]]

有不同的方法:

数据如下:

with open('textrr','r') as f:
    data=[line.split() for line in f.readlines()]
使用collections.defaultdict()的第一种方法

输出:

[['10', '1'], ['3', '4'], ['6', '8'], ['5', '8', '6']]
订单将不一样:

[['10', '1'], ['6', '8'], ['3', '4'], ['5', '8', '6']]
使用itertools.grouby:

import itertools
print([[sub[1] for sub in i] for j,i in itertools.groupby(data,key=lambda x:x[0]) if list(j)[0].isdigit()])
输出:

[['10', '1'], ['3', '4'], ['6', '8'], ['5', '8', '6']]
顺序是一样的

[['3', '4'], ['5', '8', '6'], ['6', '8'], ['10', '1']]
最后,如果您不想使用任何导入,则可以尝试手动方法:

groupby={}

for item in data:
    if item[0].isdigit() and item[0] not in groupby:
        groupby[item[0]]=[item[1]]
    elif item[0].isdigit():
        groupby[item[0]].append(item[1])

print(groupby.values())
输出:

[['10', '1'], ['3', '4'], ['6', '8'], ['5', '8', '6']]
对于大型数据集,我建议使用Numpy,因为它速度更快。 我还建议不要使用for循环进行排序,
df.sort\u values()
要快得多

下面是我处理的1500万行数据集的比较

通过
Numpy
将numpy导入为np
df=df[['a','b']]
键,值=df.sort_值('a').values.T
ukeys,index=np.unique(键,True)
数组=np.split(值,索引[1:])
df=pd.DataFrame({'a':ukeys,'b':[数组中a的列表(a)])
与熊猫“群比”
首先展示你的低效方法对于给定的a值,如果B中有重复的值怎么办。你想要集合,还是想看到重复的值?我想你可以使用
df.groupby('a').B.apply(pd.Series.tolist).tolist()
,但如果你真的像你所说的那样拥有10亿条记录,我怀疑任何东西都不够快you@cᴏʟᴅsᴘᴇᴇᴅ 非常感谢。这很好用。现在真的需要很多时间@亚历山大:是的,我忘了提那件事。对不起。我考虑重复。为你摆脱了lambda,因为这似乎是另一个回答者的USP。
[['3', '4'], ['5', '8', '6'], ['6', '8'], ['10', '1']]
groupby={}

for item in data:
    if item[0].isdigit() and item[0] not in groupby:
        groupby[item[0]]=[item[1]]
    elif item[0].isdigit():
        groupby[item[0]].append(item[1])

print(groupby.values())
[['10', '1'], ['3', '4'], ['6', '8'], ['5', '8', '6']]
NUMPY
Total time: 102.379 s for 15,397,309 rows
Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     3         1    1205208.0 1205208.0      1.2    
     4         1   60671365.0 60671365.0     59.3   
     5         1   16897187.0 16897187.0     16.5    
     6         1    1430774.0 1430774.0      1.4     
     7         1   22174794.0 22174794.0     21.7     
     8         1          4.0      4.0      0.0      
df.groupby('a')['b'].apply(list)
PANDAS GROUPBY
Total time: 146.23 s for 15,397,309 rows

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     3         1    1181714.0 1181714.0      0.8     
     4         1  145048477.0 145048477.0     99.2      
     5         1          3.0      3.0      0.0