【问题标题】:Using a function to calculate new column values from old column values in pandas row by row使用函数从熊猫中的旧列值逐行计算新列值
【发布时间】:2016-09-07 16:51:23
【问题描述】:

我知道关于这个主题有很多问题,但在这种情况下,建议的答案似乎都不起作用,我认为这是微不足道的,但现在已经杀死了我 2 天。

这是我第一次尝试使用 pandas 处理来自眼动仪的导出文件。导出文件包含大约 50 列,其中 2 列包含瞳孔扩张度量,PupilLeft 和 PupilRight。我想创建一个新列 PupilAvg,将两者取平均值。当眼动仪无法读取一个或两个瞳孔时,它会记录 -1。由于所需的逻辑很简单,但对于 lambda 来说似乎有点长,我编写了一个函数来为我的新列返回值:

def getEyeAvg(left, right): 
    # calcs avg for Left and Right where one or both may be missing (= -1)
    if left == -1 and right == -1: return np.nan
    if left == -1: return right
    if right == -1: return left  
    return (left + right)/2.0 

这是数据框的示例版本:

In[25]: dfd = pd.DataFrame.from_items([('PupilLeft', [3., -1., 4., -1]), ('PupilRight', [4., 4., -1., -1])])

In[26]: dfd
Out[26]: 
   PupilLeft  PupilRight
0        3.0         4.0
1       -1.0         4.0
2        4.0        -1.0
3       -1.0        -1.0

我想在 PupilRight 之后插入我的新列,所以我尝试了命令:

In[27]: dfd.insert(2, 'PupilAvg', getEyeAvg(dfd.PupilLeft, dfd.PupilRight))

我对 PupilAvg 的期望是:

   PupilLeft  PupilRight  PupilAvg
0        3.0         4.0       3.5
1       -1.0         4.0       4.0
2        4.0        -1.0       4.0
3       -1.0        -1.0       NaN

当然这不起作用,我明白了

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

我已经看到这个问题的变体一遍又一遍地被问到,而且考虑到我的相对初学者状态,似乎每个答案都使用了一些不同的“技巧”,这对我来说似乎难以理解。例如,我既不想要 left == -1 的 'any' 也不是 'all' 行,我只想要当前行,但这似乎是 pandas 很难处理的请求。

如果有人可以为这个问题提供一个明确的通用解决方案,那将非常有帮助,这基本上可以归结为

“我想使用一个函数来逐行使用其他列的值来计算新列的值,而不是一次全部计算。你知道,就像在 Excel 中一样。有没有一个简单的、通用的怎么办?”

对于像我这样试图从 Excel 解决方案过渡到 python/pandas 的人来说,这尤其困难,因为 Excel 自然是逐行进行的。您只需在第一行单元格中输入一个公式并将其一直复制到该列。显然,这种心态让我对 pandas 的准备不足。

【问题讨论】:

    标签: python pandas dataframe calculated-columns


    【解决方案1】:

    在对整个列进行操作时,有一种简单的方法可以实现您的目标。

    dfd.replace({-1:np.nan}, inplace=True)
    dfd['PupilAvg'] = dfd.mean(axis=1)
    

    如果您出于某种原因需要保留原始的 -1 值,只需先复制它们然后继续。有了明确的 nan 值,pandas 中的一切都变得更容易了。

    您的原始代码失败了,因为您将整列数据传递到 getEyeAvg。在您的示例中,它试图评估 pd.DataFrame.from_items([('PupilLeft', [3., -1., 4., -1]) == -1, not 3. == 1. 操作一次整列是 pandas 的默认模式,因此它确实需要一种新的思维方式。没有任何一种最好的方法可以做到这一点,因为最有意义的方法来自 Excel(直接通过index 或使用 df.apply(lambda, axis=1)) 比使用整列慢得多。

    【讨论】:

    • 很好的解决方案。两个后续问题。如何将 dfd.replace 限制为仅在公式中使用的两列?我可能在 50 列导出数据中的其他地方有 -1,我不想弄乱这些。同样,如何将 dfd.mean 函数限制为仅计算两个源列的平均值,而不包括其他列中同一行中的所有其他数值?谢谢!
    • dfd[['PupilLeft', 'PupilRight']] = dfd[['PupilLeft', 'PupilRight']].replace({-1:np.nan}) 然后dfd['PupilAvg'] = dfd[['PupilLeft', 'PupilRight']].mean(axis=1)
    猜你喜欢
    • 2022-11-14
    • 1970-01-01
    • 2015-10-23
    • 2015-01-09
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    相关资源
    最近更新 更多