没有for循环的过程数据框

时间:2019-07-19 16:35:28

标签: python pandas dataframe

我下面列出了一个非常非结构化的数据框。目标是将信息组合成5行数据框(将字符串合并到第0-3、4-8、9-10、11-15和16行的项目中;代码在同一行集中是相同的;代码不是唯一的)。我能够获得起始索引的索引(0,4,9,11,16 ...; 起始行的上一行具有值'nan'的列'code')不使用for循环。但是我想不办法不使用for循环来组合这些行。有人可以帮忙吗?谢谢!

     code    item01  item02  item03  item04  item05
    0   1111    'a' 123 234 345 440
    1   1111    'b' nan nan nan nan
    2   nan     'c' nan nan nan nan
    3   nan     'd' nan nan nan nan
    4   2222    'b' 123 234 345 456
    5   2222    'b' nan nan nan nan
    6   nan     'c' nan nan nan nan
    7   nan     'd' nan nan nan nan
    8   nan     'e' nan nan nan nan
    9   3333    'd' 123 234 345 456
    10  nan     'b' nan nan nan nan
    11  1111    'c' 123 234 345 456
    12  1111    'b' nan nan nan nan
    13  nan     'c' nan nan nan nan
    14  nan     'd' nan nan nan nan
    15  nan     'e' nan nan nan nan
    16  5555    'a' nan nan nan nan

预期结果:

     code    item01  item02  item03  item04  item05
    0   1111    'abcd'  123 234 345 440
    1   2222    'bbcde' 123 234 345 456
    2   3333    'db'    123 234 345 456
    3   1111    'cbcde' 123 234 345 456
    4   5555    'a'     123 234 345 456

3 个答案:

答案 0 :(得分:4)

如果您定义

code_notnull = pd.notnull(df['code'])    

然后您可以使用来标识每个新组的开始

# True when the row is not null, but the prior row is null
mask = code_notnull & ~(code_notnull.shift(1, fill_value=False))
0      True
1     False
2     False
3     False
4      True
...

然后您可以使用来定义组号

group_num = mask.cumsum()
0     1
1     1
2     1
3     1
4     2
...

,然后按group_num分组:

import numpy as np
import pandas as pd
nan = np.nan

df = pd.DataFrame({'code': [1111.0, 1111.0, nan, nan, 2222.0, 2222.0, nan, nan, nan, 3333.0, nan,
    1111.0, 1111.0, nan, nan, nan, 5555.0], 'item01': ['a', 'b', 'c', 'd',
    'b', 'b', 'c', 'd', 'e', 'd', 'b', 'c', 'b', 'c', 'd',
    'e', 'a'], 'item02': [123.0, nan, nan, nan, 123.0, nan, nan, nan, nan,
    123.0, nan, 123.0, nan, nan, nan, nan, nan], 'item03': [234.0, nan, nan, nan,
    234.0, nan, nan, nan, nan, 234.0, nan, 234.0, nan, nan, nan, nan, nan],
    'item04': [345.0, nan, nan, nan, 345.0, nan, nan, nan, nan, 345.0, nan, 345.0,
    nan, nan, nan, nan, nan], 'item05': [440.0, nan, nan, nan, 456.0, nan, nan,
    nan, nan, 456.0, nan, 456.0, nan, nan, nan, nan, nan]})

code_notnull = pd.notnull(df['code'])
mask = code_notnull & ~(code_notnull.shift(1, fill_value=False))
group_num = mask.cumsum()

# Forward-fill all NaNs. 
df = df.ffill()
grouped = df.groupby(group_num)
result = grouped.first()
result['item01'] = grouped['item01'].sum()
print(result)

收益

        code item01  item02  item03  item04  item05
code                                               
1     1111.0   abcd   123.0   234.0   345.0   440.0
2     2222.0  bbcde   123.0   234.0   345.0   456.0
3     3333.0     db   123.0   234.0   345.0   456.0
4     1111.0  cbcde   123.0   234.0   345.0   456.0
5     5555.0      a   123.0   234.0   345.0   456.0

请注意,以上我假设您在item01中的字符串不以单引号开头和结尾。 如果这样做,您可以使用

将其删除
df['item01'] = df['item01'].str[1:-1]

然后按照上述步骤进行。

import numpy as np
import pandas as pd
nan = np.nan

df = pd.DataFrame({'code': [1111.0, 1111.0, nan, nan, 2222.0, 2222.0, nan, nan, nan, 3333.0, nan,
    1111.0, 1111.0, nan, nan, nan, 5555.0], 'item01': ["'a'", "'b'", "'c'", "'d'",
    "'b'", "'b'", "'c'", "'d'", "'e'", "'d'", "'b'", "'c'", "'b'", "'c'", "'d'",
    "'e'", "'a'"], 'item02': [123.0, nan, nan, nan, 123.0, nan, nan, nan, nan,
    123.0, nan, 123.0, nan, nan, nan, nan, nan], 'item03': [234.0, nan, nan, nan,
    234.0, nan, nan, nan, nan, 234.0, nan, 234.0, nan, nan, nan, nan, nan],
    'item04': [345.0, nan, nan, nan, 345.0, nan, nan, nan, nan, 345.0, nan, 345.0,
    nan, nan, nan, nan, nan], 'item05': [440.0, nan, nan, nan, 456.0, nan, nan,
    nan, nan, 456.0, nan, 456.0, nan, nan, nan, nan, nan]})
df['item01'] = df['item01'].str[1:-1]
print(df)

收益(df['item0']中的单引号已删除)

      code item01  item02  item03  item04  item05
0   1111.0      a   123.0   234.0   345.0   440.0
1   1111.0      b     NaN     NaN     NaN     NaN
2      NaN      c     NaN     NaN     NaN     NaN
3      NaN      d     NaN     NaN     NaN     NaN
...

如果要将单引号添加回最终结果,可以使用:

result['item01'] = "'" + result['item01'] + "'"

答案 1 :(得分:1)

在创建具有唯一代码的有效分组列之后,可以使用groupby进行操作。

如果每个组的所有行都是连续的,并且标识新组的逻辑是:

  

起始行的上一行包含列'code',其值为'nan'

您只需要检查上一个为空时的代码值不为空。您可以通过将'code'列移动一并通过列表理解来检查已移位列和原始列的值。
然后,累积总和将为分组创建唯一的值。

df['uniquecode'] = [pd.notnull(curr) and pd.isnull(prev) for curr, prev in zip(df['code'], df['code'].shift(1))]
df['uniquecode'] = df['uniquecode'].cumsum()
ddf = df.groupby('uniquecode').agg({'code':'mean', 'item01':'sum', 'item02':'sum', 'item03':'sum', 'item04':'sum', 'item05':'sum'}))
ddf['item01'] = ddf['item01'].apply(lambda x : "'" + x.replace("'","") + "'")

这将返回ddf

              code   item01  item02  item03  item04  item05
uniquecode                                                 
1           1111.0   'abcd'   123.0   234.0   345.0   440.0
2           2222.0  'bbcde'   123.0   234.0   345.0   456.0
3           3333.0     'db'   123.0   234.0   345.0   456.0
4           1111.0  'cbcde'   123.0   234.0   345.0   456.0
5           5555.0      'a'     0.0     0.0     0.0     0.0

最后一行使用apply删除了不需要的'字符,因为您的所有字符都被顶点包围。
您可以通过执行'uniquecode'

来摆脱ddf.reset_index(drop=True, inplace=True)索引

答案 2 :(得分:0)

您可以检查此代码是否适合您? (我编辑了代码)

df1=df.ffill()
df1['prev_code']=df1['code'].shift(1)
df1['grkey']=df1.reset_index().apply(lambda x: x['index'] if x.code!=x.prev_code else float('nan'), axis=1)
df1=df1.ffill().groupby('grkey').agg({'code':'first', 'item01':'sum','item02':'first','item03':'first','item04':'first','item05':'first'}).reset_index().drop('grkey',axis=1)
df1['item01']=df1['item01'].apply(lambda x: x.replace("''",""))