Python 展开DataFrame列中的整数范围

Python 展开DataFrame列中的整数范围,python,python-3.x,pandas,dataframe,Python,Python 3.x,Pandas,Dataframe,我有一个数据框,看起来像: d = {'value': ['a','b','c','d','e','f','g', 'h'],\ 'id' : ['0101', '0208', '0103', '0405', '0105,0116,0117', '0108-0110', '0231, 0232, 0133-0150', '0155, 0152-0154, 0151']} df = pd.DataFrame(d) >>>

我有一个数据框,看起来像:

d = {'value': ['a','b','c','d','e','f','g', 'h'],\
     'id'   : ['0101', '0208', '0103', '0405', '0105,0116,0117',
                '0108-0110', '0231, 0232, 0133-0150', '0155, 0152-0154, 0151']}
df = pd.DataFrame(d)
>>>
       value                     id
0      a                   0101
1      b                   0208
2      c                   0103
3      d                   0405
4      e                   0105
5      e                   0116
6      e                   0117
7      f                   0108
8      f                   0109
9      f                   0110
10     g  0231, 0232, 0133-0150
11     h  0155, 0152-0154, 0151
但我需要扩展这些ID,使每一行都是一个数字,因此看起来更像:

   value    id
0      a  0101
1      b  0208
2      c  0103
3      d  0405
4      e  0105
5      e  0116
6      e  0117
7      f  0108
8      f  0109
9      f  0110
10     g   ...
其中,每行在ID分组的位置重复(范围扩展,对于小于4位的ID保留前导零)

我已经到了

df['id'].str.split(",")
df['id'].str.contains("-")

但我想不出一个好办法来做这件事。有人能帮忙吗

您可以编写一个小例程来展平范围,然后根据需要重复原始值

from itertools import chain

flattened = []
for x in df['id'].str.split(r',\s*'):
    flattened.append([])
    for y in x:
        if '-' in y:
            start, end = pd.to_numeric(y.split('-'))
            flattened[-1].extend(pd.RangeIndex(start, end+1))
        else: 
            flattened[-1].append(int(y))

repeats = [len(f) for f in flattened]


事实证明,即使对于更大的数据,这也是非常有效的

df_ = df
df = pd.concat([df_] * 1000, ignore_index=True)

%timeit flatten(df)  # Function running code above.
244 ms ± 15.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
以下是一种方法:

s = (df['id'].str.split(r"[, ]|[-]")
             .apply(pd.Series)
             .stack()
             .reset_index(level=1, drop=True))

df.drop('id', axis =1).join(s.to_frame()).reset_index(drop=True)

 value     0
0      a  0101
1      b  0208
2      c  0103
3      d  0405
4      e  0105
5      e  0116
6      e  0117
7      f  0108
8      f  0109
9      f  0110
10     g  0231
11     g  0232
12     g  0133
13     g  0150
14     h  0155
15     h  0152
16     h  0154
17     h  0151

我认为您的示例已损坏或不完整是的,很抱歉,还需要扩展范围,已编辑虽然技术上没有错误,
apply(pd.Series)
已知存在一些严重的性能问题。。。并与stack复合。。。不要让简洁欺骗你:-)是的,我知道:)。如果数据框较大,我还将添加一个更有效的解决方案。数据框不大(~1000行),但我还需要填写范围,即0133-0150变为0133、0134、0135。。。我明白了。将修改当前的解决方案我很欣赏这是多么的干净和可读,但目前还不能完全解决问题,尽管@NixonTanks对此表示感谢,但我无法真正阅读或理解它,但它工作得非常好。谢谢,而且似乎很有效。此解决方案适用于n>2列吗?由于以下错误,我似乎无法使其适用于我的实际示例:
ValueError:int()的文本无效,以10为基数:“0 0 0…\n1 0 0…\n2 0…”
@BenJones它目前适合于两列,但您始终可以打开一个后续问题,询问如何推广它(提示:尝试使用
df.apply
)在我打开一个新问题之前,我已经修复了
df_flat=pd.DataFrame中的硬编码字典部分({
…等,但看不出问题出在哪里,哪一行是需要应用的部分?很多appreciated@BenJones正则表达式以逗号和可选空格分隔。在给出的解释中,您的错误对我来说仍然没有意义。最好的做法是打开一个新的Q。。。 :)
s = (df['id'].str.split(r"[, ]|[-]")
             .apply(pd.Series)
             .stack()
             .reset_index(level=1, drop=True))

df.drop('id', axis =1).join(s.to_frame()).reset_index(drop=True)

 value     0
0      a  0101
1      b  0208
2      c  0103
3      d  0405
4      e  0105
5      e  0116
6      e  0117
7      f  0108
8      f  0109
9      f  0110
10     g  0231
11     g  0232
12     g  0133
13     g  0150
14     h  0155
15     h  0152
16     h  0154
17     h  0151