将多个值拆分为新行

时间:2018-05-02 15:55:37

标签: python python-3.x pandas split append

我有一个数据框,其中一些列可能在一次观察中有多个值。无论是否存在多个,这些行中的每个观察在观察结束时都具有“/”。这意味着某些值看起来像这样:'OneThing /',而其他值如下:'OneThing / AnotherThing /'

我需要获取观察中有多个值的值,并将它们分成单独的行。

这是数据帧之前的一般示例:

ID  Date   Name ColA   ColB   Col_of_Int                        ColC   ColD
1   09/12  Ann  String String OneThing/                         String String
2   09/13  Pete String String OneThing/AnotherThing             String String
3   09/13  Ann  String String OneThing/AnotherThing/ThirdThing/ String String
4   09/12  Pete String String OneThing/                         String String

我想要的输出是什么:

ID  Date   Name ColA   ColB   Col_of_Int                        ColC   ColD
1   09/12  Ann  String String OneThing                         String String
2   09/13  Pete String String OneThing                         String String
2   09/13  Pete String String Another Thing                    String String
3   09/13  Ann  String String OneThing                         String String
3   09/13  Ann  String String AnotherThing                     String String
3   09/13  Ann  String String ThirdThing                       String String
4   09/12  Pete String String OneThing/                        String String

我尝试了以下内容:

df = df[df['Column1'].str.contains('/')]
df_split = df[df['Column1'].str.contains('/')]
df1 = df_split.copy()
df2 = df_split.copy()

split_cols = ['Column1']

for c in split_cols:
    df1[c] = df1[c].apply(lambda x: x.split('/')[0])
    df2[c] = df2[c].apply(lambda x: x.split('/')[1])

new_rows = df1.append(df2)
df.drop(df_split.index, inplace=True)
df = df.append(new_rows, ignore_index=True)

这有效,但我认为它是在每个'/'之后创建新行,这意味着只为一个值为每个观察创建 一个 新行(我希望零新行),并为每个观察创建两个新行,两个值(只需要一个),等等。

在观察中有三个或更多值的情况下,这尤其令人沮丧,因为我得到了几个不必要的行。

有没有办法解决这个问题,以便只有多个观察结果被添加到新行?

1 个答案:

答案 0 :(得分:1)

如果你使用df['column_of_interest'] = df['column_of_interest'].str.rstrip('/'),你的方法会起作用(我认为),因为它会在你的观察结束时摆脱那令人讨厌的/。但是,循环是有效的,并且您拥有它的方式要求您知道列中最大的观察数量。这是另一种方式,我认为可以实现您的需求:

举个例子df

df = pd.DataFrame({'column_of_interest':['onething/', 
                                         'onething/twothings/', 
                                         'onething/twothings/threethings/'], 
                   'values1': [1,2,3], 
                   'values2': [5,6,7]})

>>> df
                column_of_interest  values1  values2
0                        onething/        1        5
1              onething/twothings/        2        6
2  onething/twothings/threethings/        3        7

这有点乱,因为您希望将列中的数据保留在column_of_interest之外。所以,您可以暂时找到这些并将它们放在一边,使用:

value_columns = [i for i in df.columns if i != 'column_of_interest']

并将它们放入索引中以进行以下操作(最后将其恢复):

new_df = (df.set_index(value_columns)
          .column_of_interest.str.rstrip('/')
          .str.split('/')
          .apply(pd.Series)
          .stack()
          .rename('new_column_of_interest')
          .reset_index(value_columns))

然后您的new_df看起来像:

>>> new_df
   values1  values2 new_column_of_interest
0        1        5               onething
0        2        6               onething
1        2        6              twothings
0        3        7               onething
1        3        7              twothings
2        3        7            threethings

或者,使用merge

new_df = (df[value_columns].merge(df.column_of_interest
                        .str.rstrip('/')
                        .str.split('/')
                        .apply(pd.Series)
                        .stack()
                        .reset_index(1, drop=True)
                        .to_frame('new_column_of_interest'),
                        left_index=True, right_index=True))

编辑:在您发布的数据框中,结果为:

   ID   Date  Name    ColA    ColB    ColC    ColD new_column_of_interest
0   1  09/12   Ann  String  String  String  String               OneThing
0   2  09/13  Pete  String  String  String  String               OneThing
1   2  09/13  Pete  String  String  String  String           AnotherThing
0   3  09/13   Ann  String  String  String  String               OneThing
1   3  09/13   Ann  String  String  String  String           AnotherThing
2   3  09/13   Ann  String  String  String  String             ThirdThing
0   4  09/12  Pete  String  String  String  String               OneThing