将值重新格式化为单独的列

时间:2019-09-10 04:39:11

标签: pandas replace fill

我正在尝试将值分为pandas df中的不同列。具体来说,我在同一列中有代表标签和时间戳的字符串。我希望将它们分成单独的列。我只是不确定会更有效的过程。

对于下面的df,我想将时间字符串分成一个单独的列。

df = pd.DataFrame({
    'Value' : ['Foo X','10:00','10:00','10:00','10:00','Bar X','11:00','11:00','Cat X','12:00','12:00','12:00'],                 
    'Number' : [0,1,2,3,4,0,1,2,0,1,2,3],                      
    })

出局:

    Value  Number
0   Foo X       0
1   10:00       1
2   10:00       2
3   10:00       3
4   10:00       4
5   Bar X       0
6   11:00       1
7   11:00       2
8   Cat X       0
9   12:00       1
10  12:00       2
11  12:00       3

问题在于每个标签的时间戳数量不同,因此我不能仅在第n行中拆分。例如

df1 = pd.DataFrame({'Value':df['Value'].iloc[:1:4].values, 'Time':df['Value'].iloc[:1:4].values})

另一种尝试是创建一个单独的列,以传递df.Value中的所有值,然后将所有时间戳替换为np.nan并设置输出子集。但是我不确定这是否非常有效?

    Value  Number   Time
0   Foo X       0  Foo X
1   10:00       1  10:00
2   10:00       2  10:00
3   10:00       3  10:00
4   10:00       4  10:00
5   Bar X       0  Bar X
6   11:00       1  11:00
7   11:00       2  11:00
8   Cat X       0  Cat X
9   12:00       1  12:00
10  12:00       2  12:00
11  12:00       3  12:00

预期输出:

  Value  Number   Time
0  Foo X       1  10:00
1  Foo X       2  10:00
2  Foo X       3  10:00
3  Foo X       4  10:00
4  Bar X       1  11:00
5  Bar X       2  11:00
6  Cat X       1  12:00
7  Cat X       2  12:00
8  Cat X       3  12:00

4 个答案:

答案 0 :(得分:1)

以下功能应该会为您提供所需的输出。

def process_dataframe(df):
    s = df.loc[df.Number==0]['Value']
    labels = s.to_list()
    a = s.index.to_list()
    a.append(df.index.size)
    repnum = [x2 - x1 - 1 for x1,x2 in zip(a[:-1], a[1:])]
    df2 = df.loc[df['Number']!=0].copy()
    df2['Time'] = df2['Value']
    df2['Value'] = s.repeat(repnum).to_list()
    return df2
process_dataframe(df)
  

输出

  Value  Number   Time
0  Foo X       1  10:00
1  Foo X       2  10:00
2  Foo X       3  10:00
3  Foo X       4  10:00
4  Bar X       1  11:00
5  Bar X       2  11:00
6  Cat X       1  12:00
7  Cat X       2  12:00
8  Cat X       3  12:00

答案 1 :(得分:1)

您可以将groupbypd.Series.repat一起使用 创建Value列 然后通过使用boolean indexing选择TimeNumber

value_bool=pd.Series(['X' in key for key in df['Value']])
Value=df.loc[value_bool]['Value'] #selecting values ​​for the Value column
groups=df.groupby(value_bool.cumsum())
new_df=Value.repeat(groups.size()-1).to_frame().reset_index(drop=True) #create dataframe with new Value Column
new_df[['Number','Time']]=df.loc[~value_bool].reset_index(drop=True).reindex(columns=['Number','Value']) #creating Number and Time

输出:

   Value  Number   Time
0  Foo X       1  10:00
1  Foo X       2  10:00
2  Foo X       3  10:00
3  Foo X       4  10:00
4  Bar X       1  11:00
5  Bar X       2  11:00
6  Cat X       1  12:00
7  Cat X       2  12:00
8  Cat X       3  12:00

答案 2 :(得分:1)

想法是用to_datetimeerrors='coerce'来区分缺少的不匹配值的时间值:

mask = pd.to_datetime(df['Value'], errors='coerce').notna()

或用:Series.str.contains表示测试模式2位数字:

mask = df['Value'].str.contains(r'\d{2}:\d{2}')

可能的测试是否等于0

mask = df['Number'].ne(0)

然后创建新列,并用Series.maskValue的{​​{1}}替换为NaN,并向前填充缺失值,最后用boolean indexing进行过滤:

mask

答案 3 :(得分:1)

使用遮罩和填充的另一种解决方案:

%02.2hhx