通过评估逻辑函数中的数值和字符串值,使用字符串响应计算数值
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
如果您知道它总是以 year
、month
或 week
结尾,您可以将其去掉并使用 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
然后你可以像我上面那样将它们相乘。
我正在尝试编写一个函数,它接受“频率”列中的字符串响应并计算某人每年饮酒的总天数。
我试图从字符串中获取的三个主要值是语句中存在的数字和单词(周、月、年),用于计算某人在一年内饮酒的平均总天数。例如,如果某人每月饮酒 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
如果您知道它总是以 year
、month
或 week
结尾,您可以将其去掉并使用 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
然后你可以像我上面那样将它们相乘。