优化将列中的范围值重写为单独的行
Optimizing the rewriting of the range values in a column into separate rows
我有一个数据框 clothes_acc
,列 shoe_size
包含如下值:
index shoe_size
134 37-38
963 43-45
968 39-42
969 43-45
970 37-39
我想做的是在每一行中分别写下整个范围的值。所以我会得到:
index shoe_size
134 37
134 38
963 43
963 44
963 45
968 39
968 40
968 41
968 42
...
目前,我有以下代码可以正常工作,但对于具有 500k 行的数据帧来说它非常慢。 (clothes_acc
实际上包含列中的其他值,这些值在这里并不重要,这就是为什么我使用提到的值获取数据帧的一个子集并将其保存在 tmp
变量中)。
for i, row in tqdm(tmp.iterrows(), total=tmp.shape[0]):
clothes_acc = clothes_acc.drop([i])
spl = [int(s) for s in row['shoe_size']]
for j in range(spl[0],spl[1]+1):
replicate = row.copy()
replicate['shoe_size'] = str(j)
clothes_acc = clothes_acc.append(replicate)
clothes_acc.reset_index(drop=True,inplace=True)
有人可以提出改进建议吗?
将字符串范围转换为整数大小列表并调用 explode()
:
df['shoe_size'] = df.apply(lambda x:
[i for i in range(int(x['shoe_size'].split('-')[0]), int(x['shoe_size'].split('-')[1]) + 1)],
axis=1)
df = df.explode(column='shoe_size')
例如,如果 df 是:
df = pd.DataFrame({
'shoe_size': ['37-38', '43-45', '39-42', '43-45', '37-39']
})
...这将给出以下结果:
shoe_size
0 37
0 38
1 43
1 44
1 45
2 39
2 40
2 41
2 42
3 43
3 44
3 45
4 37
4 38
4 39
一个选项(更多的内存密集型)是提取范围的边界,合并所有可能的值,然后过滤到合并值在范围之间的位置。当许多产品的 shoe_sizes 重叠时,这会正常工作,因此交叉连接不会非常大。
import pandas as pd
# Bring ranges over to df
ranges = (clothes_acc['shoe_size'].str.split('-', expand=True)
.apply(pd.to_numeric)
.rename(columns={0: 'lower', 1: 'upper'}))
clothes_acc = pd.concat([clothes_acc, ranges], axis=1)
# index shoe_size lower upper
#0 134 37-38 37 38
#1 963 43-45 43 45
#2 968 39-42 39 42
#3 969 43-45 43 45
#4 970 37-39 37 39
vals = pd.DataFrame({'shoe_size': np.arange(clothes_acc.lower.min(),
clothes_acc.upper.max()+1)})
res = (clothes_acc.drop(columns='shoe_size')
.merge(vals, how='cross')
.query('lower <= shoe_size <= upper')
.drop(columns=['lower', 'upper']))
print(res)
index shoe_size
0 134 37
1 134 38
15 963 43
16 963 44
17 963 45
20 968 39
21 968 40
22 968 41
23 968 42
33 969 43
34 969 44
35 969 45
36 970 37
37 970 38
38 970 39
我有一个数据框 clothes_acc
,列 shoe_size
包含如下值:
index shoe_size
134 37-38
963 43-45
968 39-42
969 43-45
970 37-39
我想做的是在每一行中分别写下整个范围的值。所以我会得到:
index shoe_size
134 37
134 38
963 43
963 44
963 45
968 39
968 40
968 41
968 42
...
目前,我有以下代码可以正常工作,但对于具有 500k 行的数据帧来说它非常慢。 (clothes_acc
实际上包含列中的其他值,这些值在这里并不重要,这就是为什么我使用提到的值获取数据帧的一个子集并将其保存在 tmp
变量中)。
for i, row in tqdm(tmp.iterrows(), total=tmp.shape[0]):
clothes_acc = clothes_acc.drop([i])
spl = [int(s) for s in row['shoe_size']]
for j in range(spl[0],spl[1]+1):
replicate = row.copy()
replicate['shoe_size'] = str(j)
clothes_acc = clothes_acc.append(replicate)
clothes_acc.reset_index(drop=True,inplace=True)
有人可以提出改进建议吗?
将字符串范围转换为整数大小列表并调用 explode()
:
df['shoe_size'] = df.apply(lambda x:
[i for i in range(int(x['shoe_size'].split('-')[0]), int(x['shoe_size'].split('-')[1]) + 1)],
axis=1)
df = df.explode(column='shoe_size')
例如,如果 df 是:
df = pd.DataFrame({
'shoe_size': ['37-38', '43-45', '39-42', '43-45', '37-39']
})
...这将给出以下结果:
shoe_size
0 37
0 38
1 43
1 44
1 45
2 39
2 40
2 41
2 42
3 43
3 44
3 45
4 37
4 38
4 39
一个选项(更多的内存密集型)是提取范围的边界,合并所有可能的值,然后过滤到合并值在范围之间的位置。当许多产品的 shoe_sizes 重叠时,这会正常工作,因此交叉连接不会非常大。
import pandas as pd
# Bring ranges over to df
ranges = (clothes_acc['shoe_size'].str.split('-', expand=True)
.apply(pd.to_numeric)
.rename(columns={0: 'lower', 1: 'upper'}))
clothes_acc = pd.concat([clothes_acc, ranges], axis=1)
# index shoe_size lower upper
#0 134 37-38 37 38
#1 963 43-45 43 45
#2 968 39-42 39 42
#3 969 43-45 43 45
#4 970 37-39 37 39
vals = pd.DataFrame({'shoe_size': np.arange(clothes_acc.lower.min(),
clothes_acc.upper.max()+1)})
res = (clothes_acc.drop(columns='shoe_size')
.merge(vals, how='cross')
.query('lower <= shoe_size <= upper')
.drop(columns=['lower', 'upper']))
print(res)
index shoe_size
0 134 37
1 134 38
15 963 43
16 963 44
17 963 45
20 968 39
21 968 40
22 968 41
23 968 42
33 969 43
34 969 44
35 969 45
36 970 37
37 970 38
38 970 39