根据DataFrame中的字符串格式创建额外的行

时间:2017-04-19 03:04:26

标签: python pandas dataframe string-formatting apply

我希望有效地在DataFrame上执行以下操作。 DataFrame有一个特殊列,包含字符串,其中某些行有格式问题。 Naemly,就我而言,它有一个+符号,分隔两个独立列的条目。

特别要考虑:

import pandas as pd
pd.DataFrame([ ['a',   0, 1  ], ['b+c', 2, 3  ], 
               ['d+e', 4, 5  ], ['f',   6, 7  ] ])

打印:

     0  1  2
0    a  0  1
1  b+c  2  3
2  d+e  4  5
3    f  6  7

我想将其转换为:

   0  1  2
0  a  0  1
1  b  2  3
2  c  2  3
3  d  4  5
4  e  4  5
5  f  6  7

那就是"展开"存在+符号的行,复制其他列。这可以通过循环遍历并使用正则表达式分配给新数据帧来完成,但我正在寻找一种更简单,更有效的方法。

编辑:最理想的是,该功能允许多个分隔符(+符号)。也就是说,也转变

import pandas as pd
pd.DataFrame([ ['a',   0, 1  ], ['b+c', 2, 3  ], 
               ['d+e+f', 4, 5  ], ['g',   6, 7  ] ])

   0  1  2
0  a  0  1
1  b  2  3
2  c  2  3
3  d  4  5
4  e  4  5
5  f  4  5
6  g  6  7

4 个答案:

答案 0 :(得分:3)

一种方法是将.str.splitstackjoin合并:

s = df[0].str.split("+", expand=True).stack()
s.index = s.index.droplevel(1)
result = s.to_frame().join(df.drop(0, axis=1)).reset_index(drop=True)

给了我

In [18]: result
Out[18]: 
   0  1  2
0  a  0  1
1  b  2  3
2  c  2  3
3  d  4  5
4  e  4  5
5  f  4  5
6  g  6  7

答案 1 :(得分:2)

我喜欢将其分解为numpy位并将数据帧重新组合在一起。

计划

  1. 拉出第一列的值并按location.pathname = '/home/home.html'
  2. 拆分
  3. 计算每个子数组的长度,并用于创建一个用
  4. 切片的索引
  5. 从步骤1的连接列表中重新构建数据,并在步骤2中使用切片器切片其余数据
  6. var fullUrl = location .protocol + "//" + location.host + "/home/home.html"

    快吗?
    确定它是!

    enter image description here

    如果您需要确保'+'保持不变,我们最后可以v = df.values[:, 1:] z = np.core.defchararray.split(df[0].values.astype(str), '+') i = np.arange(len(z)).repeat([len(x) for x in z]) pd.DataFrame(np.column_stack([np.concatenate(z), v[i]])) 0 1 2 0 a 0 1 1 b 2 3 2 c 2 3 3 d 4 5 4 e 4 5 5 f 6 7 。这会导致性能下降,但仍然很快。

    dtypes

    enter image description here

答案 2 :(得分:1)

您需要将加号的第一列中的字符串拆分为列表,将每个列表重新转换为Series对象,将Series个对象堆叠为单个Series,然后重置单级索引的索引,仅保留原始行标识符。

然后我们需要使用索引将此系列与原始DataFrame连接起来,然后删除原始列。为方便起见,我将列命名为:

import pandas as pd

df = pd.DataFrame([['a', 0, 1], ['b+c', 2, 3], ['d+e+f', 4, 5], ['g', 6, 7]], 
                  columns=list('ABC'))

s_A = df.A.str.split('+').apply(pd.Series).stack().reset_index(level=1, drop=True)
s_A.name = 'A_split'
pd.concat([df.drop('A', axis=1), s_A], axis=1)

# returns:
   B  C A_split
0  0  1       a
1  2  3       b
1  2  3       c
2  4  5       d
2  4  5       e
2  4  5       f
3  6  7       g

答案 3 :(得分:1)

如果您的问题特定于将每行拆分为两行或单独留下,您可以简单地收集要拆分的行,并将它们附加到您的数据帧:

import pandas as pd
df = pd.DataFrame([ ['a',   0, 1  ], ['b+c', 2, 3  ], 
                    ['d+e', 4, 5  ], ['f',   6, 7  ] ])
df_split = df[df[0].str.contains('\+')].copy()
df_split['new_col_name'] = df[0].str.extract('\+(.*)', expand = False)
df['new_col_name'] = df[0].str.extract('([^\+]*)', expand = False)

df.append(df_split) # required answer

如果行的排序很重要,您可以首先创建每个行号的列,例如df['no'] = list(range(len(df))),然后在最后做sort_values('no')