Python 迭代由数组组成的行的数据帧,并根据条件计算移动平均值

Python 迭代由数组组成的行的数据帧,并根据条件计算移动平均值,python,pandas,Python,Pandas,我想解决的问题我想不通。 我有一个熊猫数据框,来自: date, id, measure, result 2016-07-11, 31, "[2, 5, 3, 3]", 1 2016-07-12, 32, "[3, 5, 3, 3]", 1 2016-07-13, 33, "[2, 1, 2, 2]", 1 2016-07-14, 34, "[2, 6, 3, 3]", 1 2016-07-15, 35, "[39, 31, 73, 34

我想解决的问题我想不通。 我有一个熊猫数据框,来自:

date,       id,     measure,    result
2016-07-11, 31, "[2, 5, 3, 3]",     1
2016-07-12, 32, "[3, 5, 3, 3]",     1
2016-07-13, 33, "[2, 1, 2, 2]",     1
2016-07-14, 34, "[2, 6, 3, 3]",     1
2016-07-15, 35, "[39, 31, 73, 34]", 0
2016-07-16, 36, "[3, 2, 3, 3]",     1
2016-07-17, 37, "[3, 8, 3, 3]",     1
度量列由字符串格式的数组组成

我想从过去的3个测量记录中获得一个新的
移动平均数组
列,不包括那些
结果
为0的记录。过去的3条记录意味着对于
id
34,将使用
id
31,32,33的数组

这是关于取每一个第1点、第2点、第3点和第4点的平均值,以获得此移动平均线阵列

它是而不是关于获得第一个数组、第二个数组的平均值。。。然后取平均值,不

对于前3行,因为没有足够的历史记录,我只想使用它们自己的度量。因此,解决方案应该如下所示:

date,       id,     measure,    result .     Solution
2016-07-11, 31, "[2, 5, 3, 3]",     1,      "[2,   5, 3,   3]"
2016-07-12, 32, "[3, 5, 3, 3]",     1,      "[3,   5, 3,   3]"
2016-07-13, 33, "[2, 1, 2, 2]",     1,      "[2,   1, 2,   2]"
2016-07-14, 34, "[2, 6, 3, 3]",     1,      "[2.3, 3.6, 2.6, 2.6]"
2016-07-15, 35, "[39, 31, 73, 34]", 0,      "[2.3, 4, 2.6, 2.6]"
2016-07-16, 36, "[3, 2, 3, 3]",     1,      "[2.3, 4, 2.6, 2.6]"
2016-07-17, 37, "[3, 8, 3, 3]",     1,      "[2.3, 3, 2.6, 2.6]"
实际数据更大<代码>结果0也可以在彼此之后重复2次或更多次。我认为这将是一个关于跟踪以前的OK
result
s正确获得这些平均值的过程。我花了时间,但我不能

我在这里发布数据框:

 mydict = {'date': {0: '2016-07-11',
      1: '2016-07-12',
      2: '2016-07-13',
      3: '2016-07-14',
      4: '2016-07-15',
      5: '2016-07-16',
      6: '2016-07-17'},
     'id': {0: 31, 1: 32, 2: 33, 3: 34, 4: 35, 5: 36, 6: 37},
     'measure': {0: '[2, 5, 3, 3]',
      1: '[3, 5, 3, 3]',
      2: '[2, 1, 2, 2]',
      3: '[2, 6, 3, 3]',
      4: '[39, 31, 73, 34]',
      5: '[3, 2, 3, 3]',
      6: '[3, 8, 3, 3]'},
     'result': {0: 1, 1: 1, 2: 1, 3: 1, 4: 0, 5: 1, 6: 1}}

df = pd.DataFrame(mydict)

感谢您提供指导或指出如何使用。

仅使用1个for循环的解决方案:

考虑到数据:

mydict = {'date': {0: '2016-07-11',
      1: '2016-07-12',
      2: '2016-07-13',
      3: '2016-07-14',
      4: '2016-07-15',
      5: '2016-07-16',
      6: '2016-07-17'},
     'id': {0: 31, 1: 32, 2: 33, 3: 34, 4: 35, 5: 36, 6: 37},
     'measure': {0: '[2, 5, 3, 3]',
      1: '[3, 5, 3, 3]',
      2: '[2, 1, 2, 2]',
      3: '[2, 6, 3, 3]',
      4: '[39, 31, 73, 34]',
      5: '[3, 2, 3, 3]',
      6: '[3, 8, 3, 3]'},
     'result': {0: 1, 1: 1, 2: 1, 3: 1, 4: 0, 5: 1, 6: 1}}
df = pd.DataFrame(mydict)
我定义了一个简单的函数来计算平均值并返回一个列表。然后,应用以下规则循环数据帧:

def calc_mean(in_list):
    p0 = round((in_list[0][0] + in_list[1][0] + in_list[2][0])/3,1)
    p1 = round((in_list[0][1] + in_list[1][1] + in_list[2][1])/3,1)
    p2 = round((in_list[0][2] + in_list[1][2] + in_list[2][2])/3,1)
    p3 = round((in_list[0][3] + in_list[1][3] + in_list[2][3])/3,1)
    return [p0, p1, p2, p3]

Solution = []
aux_list = []
for index, row in df.iterrows():
    if index in [0,1,2]:
        Solution.append(row.measure)
        aux_list.append([int(x) for x in row.measure[1:-1].split(', ')])
    else:
        Solution.append('[' +', '.join(map(str, calc_mean(aux_list))) + ']')
        if row.result > 0:
            aux_list.pop(0)
            aux_list.append([int(x) for x in row.measure[1:-1].split(', ')])        
df['Solution'] = Solution
输出为:

请注意,结果四舍五入到小数点后1位,与您期望的输出略有不同。对我来说更有意义

编辑:

根据@Frenchy评论中的建议,要处理前3行中的result==0,我们需要稍微更改第一个if子句:

if index in [0,1,2] or len(aux_list) <3:
    Solution.append(row.measure)
    if row.result > 0:
        aux_list.append([int(x) for x in row.measure[1:-1].split(', ')])
如果索引位于[0,1,2]或len(辅助列表)0中:
aux_list.append([int(x)表示第行中的x。度量值[1:-1]。拆分(','))
您可以使用将
列表的
str
更改为适当的
列表
测量
结果
不为0的部分数据。与
平均值一起使用
,然后在下一行获得最后3行的滚动平均值。然后,将数据帧更改为具有
值的列表和
列表后,将
映射到
str
。最后,您只需替换前三行和缺少的数据:

df.loc[df.result.shift() != 0,'solution'] = list(map(str,
                              pd.DataFrame(pd.eval(df[df.result != 0].measure))
                                .rolling(3).mean().shift().values.tolist()))
df.loc[:2,'solution'] = df.loc[:2,'measure']
df.solution = df.solution.ffill()

下面是另一个解决方案:

# get data to reproduce example
from io import StringIO
data = StringIO(""" 
    date;id;measure;result 
    2016-07-11;31;"[2,5,3,3]";1 
    2016-07-12;32;"[3,5,3,3]";1 
    2016-07-13;33;"[2,1,2,2]";1 
    2016-07-14;34;"[2,6,3,3]";1 
    2016-07-15;35;"[39,31,73,34]";0 
    2016-07-16;36;"[3,2,3,3]";1 
    2016-07-17;37;"[3,8,3,3]";1 
    """)  

df = pd.read_csv(data, sep=";")
df
# Out:
#          date  id        measure  result
# 0  2016-07-11  31      [2,5,3,3]       1
# 1  2016-07-12  32      [3,5,3,3]       1
# 2  2016-07-13  33      [2,1,2,2]       1
# 3  2016-07-14  34      [2,6,3,3]       1
# 4  2016-07-15  35  [39,31,73,34]       0
# 5  2016-07-16  36      [3,2,3,3]       1
# 6  2016-07-17  37      [3,8,3,3]       1  

# convert values in measure column to lists
from ast import literal_eval
dm = df['measure'].apply(literal_eval)

# apply rolling mean with period 2 and recollect values into list in column means
df["means"] = dm.apply(pd.Series).rolling(2, min_periods=0).mean().values.tolist()                            

df                                                                                                           
# Out: 
#          date  id        measure  result                     means
# 0  2016-07-11  31      [2,5,3,3]       1      [2.0, 5.0, 3.0, 3.0]
# 1  2016-07-12  32      [3,5,3,3]       1      [2.5, 5.0, 3.0, 3.0]
# 2  2016-07-13  33      [2,1,2,2]       1      [2.5, 3.0, 2.5, 2.5]
# 3  2016-07-14  34      [2,6,3,3]       1      [2.0, 3.5, 2.5, 2.5]
# 4  2016-07-15  35  [39,31,73,34]       0  [20.5, 18.5, 38.0, 18.5]
# 5  2016-07-16  36      [3,2,3,3]       1  [21.0, 16.5, 38.0, 18.5]
# 6  2016-07-17  37      [3,8,3,3]       1      [3.0, 5.0, 3.0, 3.0]

# moving window of size 3
df["means"] = dm.apply(pd.Series).rolling(3, min_periods=0).mean().round(2).values.tolist()
df
# Out: 
#             date  id        measure  result                        means
# 0  2016-07-11  31      [2,5,3,3]       1         [2.0, 5.0, 3.0, 3.0]
# 1  2016-07-12  32      [3,5,3,3]       1         [2.5, 5.0, 3.0, 3.0]
# 2  2016-07-13  33      [2,1,2,2]       1     [2.33, 3.67, 2.67, 2.67]
# 3  2016-07-14  34      [2,6,3,3]       1      [2.33, 4.0, 2.67, 2.67]
# 4  2016-07-15  35  [39,31,73,34]       0   [14.33, 12.67, 26.0, 13.0]
# 5  2016-07-16  36      [3,2,3,3]       1  [14.67, 13.0, 26.33, 13.33]
# 6  2016-07-17  37      [3,8,3,3]       1  [15.0, 13.67, 26.33, 13.33]    

您的度量值是str或int列表,双引号表示str?您可以删除结果为0的行?它是一个字符串,您可以解析并生成一个数字列表。最初,它们是浮点数,如3.34、2.45。为了简单起见,我在那里输入了整数。我们不允许删除结果为0的行,我们需要它们。谢谢Daniel。这真的很有帮助。事实上,我的数据非常庞大而且非常肮脏。但是你的帮助为我扫清了道路。嗨@Silvana,很高兴知道这很有帮助。如果你认为我的答案是值得的,请你投票接受我的答案好吗?嗨,丹尼尔。我投了更高的票,但网站上说我没有任何声誉,所以我看不见。他们说,要想赢得声誉,我需要一些选票。所以,如果你认为这个问题对社区很有用,你能投票支持这个问题吗?谢谢。但我认为,即使没有声誉,你也能够接受答案……在这里,我真的看不到任何像
接受答案这样的东西。如果网站允许,我会继续检查并接受。谢谢。嗨@Ben.T。非常感谢。这真的帮了我很大的忙。你的方法很干净,效果很好。我对你的解决方案的唯一问题是来自与此条目相关的原因
eval
无法处理我的大数据:@Silvana感谢您指出这一点。我想,然后使用您提供的链接中的一个解决方案来替换
eval
可以处理更大的数据:)谢谢您的回复。但是,在计算平均值时,需要将[39,31,73,34]这样的大测量值包括在内。这就是你的解决方案的问题所在。看看你的平均值有多大。这是因为你包含了糟糕的结果。我希望这能说明问题。非常感谢。