将数据帧行分割成多个小数值



样本数据:

sample = pd.DataFrame({'split_me': [1.5, 2, 4, 3.2], 'copy_me': ['A', 'B', 'C', 'D']})
out = pd.DataFrame({'split_me': [1, 0.5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.2], 'copy_me': ['A', 'A', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D']})
sample:  # input
split_me    copy_me
0   1.5 A
1   2.0 B
2   4.0 C
3   3.2 D
out:  # desired output
split_me    copy_me
0   1.0 A
1   0.5 A
2   1.0 B
3   1.0 B
4   1.0 C
5   1.0 C
6   1.0 C
7   1.0 C
8   1.0 D
9   1.0 D
10  1.0 D
11  0.2 D

我试过使用sample.loc[sample.index.repeat(sample['split_me'])]之类的东西。然而,这只对整数重复,当我需要它返回2时,像1.9这样的值返回1行,并且它使split_me中的值保持不变,而我需要复制行,如果大于1,则将1分配给split_me,否则分配值。

我想不出一种方法来做到这一点,而不会变得循环和复杂,我最好的方法是ceil(split_me),然后运行repeat,但我仍然需要一种方法来分配值到重复的行。寻找一个更简单的解决方案,如果有人有的话。

是的,我们可以这样做

out = sample.reindex(sample.index.repeat(np.ceil(sample['split_me'])))
out['new'] = 1
con = ~out['copy_me'].duplicated(keep='last') & (out['split_me']%1!=0)
out['new'] = out['new'].mask(con, out['split_me']%1)
out
Out[195]: 
split_me copy_me  new
0       1.5       A  1.0
0       1.5       A  0.5
1       2.0       B  1.0
1       2.0       B  1.0
2       4.0       C  1.0
2       4.0       C  1.0
2       4.0       C  1.0
2       4.0       C  1.0
3       3.2       D  1.0
3       3.2       D  1.0
3       3.2       D  1.0
3       3.2       D  0.2

使用自定义重复函数

repeat_float = lambda x: ([1.] * int(x // 1)) + ([x % 1] if x % 1 != 0 else [])
out = df['split_me'].apply(repeat_float).explode().astype(float) 
.to_frame().join(df['copy_me']).reset_index(drop=True)

输出:

>>> out
split_me copy_me
0        1.0       A
1        0.5       A
2        1.0       B
3        1.0       B
4        1.0       C
5        1.0       C
6        1.0       C
7        1.0       C
8        1.0       D
9        1.0       D
10       1.0       D
11       0.2       D

我们可以使用np.modfsplit_me的小数部分和整数部分分开,然后基于唯一的整数部分的repeat创建一个新的1系列。append非零小数部分,sort_index进入预期的顺序,最后join返回列,reset_index恢复范围索引:

fractional, integral = np.modf(sample['split_me'])
df = (
pd.Series(1, index=integral.index.repeat(integral), name=integral.name)
.append(fractional[fractional.ne(0)]).sort_index(kind='stable')
.to_frame().join(sample[['copy_me']]).reset_index(drop=True)
)

df:

split_me copy_me
0        1.0       A
1        0.5       A
2        1.0       B
3        1.0       B
4        1.0       C
5        1.0       C
6        1.0       C
7        1.0       C
8        1.0       D
9        1.0       D
10       1.0       D
11       0.2       D

Setup and imports:

import numpy as np
import pandas as pd
sample = pd.DataFrame({
'split_me': [1.5, 2, 4, 3.2],
'copy_me': ['A', 'B', 'C', 'D']
})

尝试:

import pandas as pd
import numpy as np
sample = pd.DataFrame({'split_me': [1.5, 2, 4, 3.2], 'copy_me': ['A', 'B', 'C', 'D']})

def expanded_index(s, c):
index = np.repeat(1.0, s // 1)
if (s % 1) > 0:
index = np.append(index, [s % 1])
return pd.Series(c, index)

res = pd.concat([expanded_index(s, c) for s, c in zip(sample["split_me"], sample["copy_me"])])
print(res)

1.0    A
0.5    A
1.0    B
1.0    B
1.0    C
1.0    C
1.0    C
1.0    C
1.0    D
1.0    D
1.0    D
0.2    D
dtype: object

最新更新