我有一个数据框,其中一些列可能在一次观察中有多个值。无论是否存在多个,这些行中的每个观察在观察结束时都具有“/”。这意味着某些值看起来像这样:'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)
这有效,但我认为它是在每个'/'之后创建新行,这意味着只为一个值为每个观察创建 一个 新行(我希望零新行),并为每个观察创建两个新行,两个值(只需要一个),等等。
在观察中有三个或更多值的情况下,这尤其令人沮丧,因为我得到了几个不必要的行。
有没有办法解决这个问题,以便只有多个观察结果被添加到新行?
答案 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