将lambda函数应用于pandas数据帧

时间:2017-10-14 05:46:50

标签: python-3.x pandas lambda

第一次在stackoverflow上发帖,所以如果我做了一些失礼,请耐心等待。)

我试图使用geopy来计算两点之间的距离,但我无法完全实现计算的实际应用。

这是我正在使用的数据框的负责人(稍后在数据框中有一些缺失值,不确定这是否是问题或如何处理它):

start lat  start long    end_lat   end_long
0  38.902760  -77.038630  38.880300 -76.986200
2  38.895914  -77.026064  38.915400 -77.044600
3  38.888251  -77.049426  38.895914 -77.026064
4  38.892300  -77.043600  38.888251 -77.049426

我已经设置了一个功能:

def dist_calc(st_lat, st_long, fin_lat, fin_long):
   from geopy.distance import vincenty
   start = (st_lat, st_long)
   end = (fin_lat, fin_long)
   return vincenty(start, end).miles

当手动输入时,这个工作正常。

但是,当我尝试应用()函数时,我遇到了以下代码的问题:

distances = df.apply(lambda row: dist_calc(row[-4], row[-3], row[-2], row[-1]), axis=1)

我对python很新,任何帮助都会非常感激!

编辑:错误讯息:

distances = df.apply(lambda row: dist_calc2(row[-4], row[-3], row[-2], row[-1]), axis=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/frame.py", line 4262, in apply
    ignore_failures=ignore_failures)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pandas/core/frame.py", line 4358, in _apply_standard
    results[i] = func(v)
  File "<stdin>", line 1, in <lambda>
  File "<stdin>", line 5, in dist_calc2
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/geopy/distance.py", line 322, in __init__
    super(vincenty, self).__init__(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/geopy/distance.py", line 115, in __init__
    kilometers += self.measure(a, b)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/geopy/distance.py", line 414, in measure
    u_sq = cos_sq_alpha * (major ** 2 - minor ** 2) / minor ** 2
UnboundLocalError: ("local variable 'cos_sq_alpha' referenced before assignment", 'occurred at index 10')

1 个答案:

答案 0 :(得分:1)

pandas函数的默认设置(通常用于导入这样的文本数据(pd.read_table()等))会将前2列名称中的空格解释为分隔符,因此您最终将使用6列代替4,您的数据将不对齐:

In [23]: df = pd.read_clipboard()

In [24]: df
Out[24]:
   start        lat    start.1       long    end_lat  end_long
0      0  38.902760 -77.038630  38.880300 -76.986200       NaN
1      2  38.895914 -77.026064  38.915400 -77.044600       NaN
2      3  38.888251 -77.049426  38.895914 -77.026064       NaN
3      4  38.892300 -77.043600  38.888251 -77.049426       NaN

In [25]: df.columns
Out[25]: Index(['start', 'lat', 'start.1', 'long', 'end_lat', 'end_long'], dtype='object')

注意列名称错误,最后一列充满了NaN等。如果我将此函数应用于此表单中的数据框,我会得到与您相同的错误。

通常最好在将其作为数据框导入之前尝试修复此问题。我可以想到两种方法:

  1. 在导入之前清理数据,例如将其复制到编辑器中并用下划线替换有问题的空格。这是最简单的。
  2. 在导入期间使用正则表达式修复它。如果数据集非常大,或者从网站中提取数据集并且必须定期刷新,则可能需要这样做。
  3. 以下是案例(2)的一个例子:

    In [35]: df = pd.read_clipboard(sep=r'\s{2,}|\s(?=-)', engine='python')
    
    In [36]: df = df.rename_axis({'start lat': 'start_lat', 'start long': 'start_long'}, axis=1)
    
    In [37]: df
    Out[37]:
       start_lat  start_long    end_lat   end_long
    0  38.902760  -77.038630  38.880300 -76.986200
    2  38.895914  -77.026064  38.915400 -77.044600
    3  38.888251  -77.049426  38.895914 -77.026064
    4  38.892300  -77.043600  38.888251 -77.049426
    

    指定的分隔符必须包含2个以上的空格字符,或1个空格后跟连字符(减号)。然后我将列重命名为我认为的预期值。

    从这一点开始,你的函数/ apply工作正常,但我已经改变了一点:

    • PEP8建议将导入放在每个文件的顶部,而不是放在函数
    • 按名称提取列更加健壮,并且比geopy抛出的奇怪错误更容易理解错误。

    例如:

    In [51]: def dist_calc(row):
        ...:    start = row[['start_lat','start_long']]
        ...:    end = row[['end_lat', 'end_long']]
        ...:    return vincenty(start, end).miles
        ...:
    
    In [52]: df.apply(lambda row: dist_calc(row), axis=1)
    Out[52]:
    0    3.223232
    2    1.674780
    3    1.365851
    4    0.420305
    dtype: float64