通过评估逻辑函数中的数值和字符串值,使用字符串响应计算数值

Compute numeric value using string response by evaluating numeric and string values in logical function

我正在尝试编写一个函数,它接受“频率”列中的字符串响应并计算某人每年饮酒的总天数。

我试图从字符串中获取的三个主要值是语句中存在的数字和单词(周、月、年),用于计算某人在一年内饮酒的平均总天数。例如,如果某人每月饮酒 2-3 次,则等式为 (2+3/2)*12 = 每年 30 次。下面的数据table显示了数据样本。

频率
每月 1 天
每周 3 天
每年 1 到 2 天
每周 2 天
每月 1 天
每年 6-11 天
每周 5-6 天

我尝试生成的 table 每年的平均天数如下所示:

每年的频率
12
156
1.5
104
12
8.5
286

到目前为止,我已经编写了以下代码:

import pandas as pd 
AlcData = pd.read_excel('Alcohol_Data.xlsx')

#add new column with unittime value for use in function 
AlcData['unittime'] = AlcData.Frequency.str.extract(r'\b(\w+)$', 
                                     expand = True)

def calculatetotaldays(row):
    for x in range(1,11):
#read in row item as string value 
        string = AlcData.Frequency
# create list of number values from the string
        numbers = [int(i) for i in string.split() if i.isdigit()]
 #compute total days if list has length of 1 
    if len(numbers) == 1:
         x = [numbers[j] for j in (0)]
    if row[AlcData.unittime] == 'week': 
        total = x*52
    elif row[AlcData.unittime] == 'month':
        total = x*12
    elif row[AlcData.unittime] == 'year': 
        total = x
#compute total days if list has length of 2 
    if len(numbers) == 2:
        x, y = [numbers[j] for j in (0, 1)]
    if row[AlcData.unittime] == 'week': 
        total = (((x+y)/2)*52)
    elif row[AlcData.unittime] == 'month': 
        total = (((x+y)/2)*12)
    elif row[AlcData.unittime] == 'year': 
        total = ((x+y)/2)
    return total

AlcData['totalperyear'] = AlcData.apply(calculatetotaldays, axis=1)

我目前收到错误:“'Series' 对象没有属性 'split'”,同时尝试将跨行的数字提取到列表中。有谁知道如何在函数中纠正这个错误?更重要的是,这种方法(使用列表的长度来分配这些变量并计算数字)是解决这个问题的最佳方法吗?

我为此苦苦挣扎了很长时间,所以关于如何计算此信息的任何和所有提示都将非常有用。

这主要是重写,但这里有一种方法,只需 pandas:

In [92]: (
    ...:     df['Frequency']
    ...:     .str.split()
    ...:     .str[-1].map({'week': 52, 'month': 12, 'year': 1})
    ...:     .mul(
    ...:         df['Frequency']
    ...:         .str.extract(r'(\d+)\D*(\d+)?')
    ...:         .ffill(axis=1)
    ...:         .astype(int).mean(axis=1)
    ...:     )
    ...: )
Out[92]:
0     12.0
1    156.0
2      1.5
3    104.0
4     12.0
5      8.5
6    286.0
dtype: float64

我们可以将其分解为数字部分的计算,然后是乘数。您可以使用类似于您之前所做的正则表达式来获取数字:

In [89]: df['Frequency'].str.extract(r'(\d+)\D*(\d+)?')
Out[89]:
   0    1
0  1  NaN
1  3  NaN
2  1    2
3  2  NaN
4  1  NaN
5  6   11
6  5    6

然后,您可以使用 .ffill().mean() 将其变成一个数字:

In [90]: df['Frequency'].str.extract(r'(\d+)\D*(\d+)?').ffill(axis=1).astype(int).mean(axis=1)
Out[90]:
0    1.0
1    3.0
2    1.5
3    2.0
4    1.0
5    8.5
6    5.5
dtype: float64

如果您知道它总是以 yearmonthweek 结尾,您可以将其去掉并使用 map 作为乘数:

In [91]: df['Frequency'].str.split().str[-1].map({'week': 52, 'month': 12, 'year': 1})
Out[91]:
0    12
1    52
2     1
3    52
4    12
5     1
6    52
Name: Frequency, dtype: int64

然后你可以像我上面那样将它们相乘。