我有一个权重列(实际上有5k权重),一个小批量看起来像这样:
weight
15.00 oz
19.00 oz
2 lb 15.00 oz
1 lb 19.00 oz
我要做的是把整个重量转换成磅,像这样:
weight
0.9375 lb
1.1875 lb
2.9375 lb
2.1875 lb
我该怎么做才能做到这一点?到目前为止,我所尝试的是:
df[['lbs','oz']] = df.Weight.str.split("lb",expand=True)
但这不起作用,对于没有'lb'单元的行,代码不起作用。它看起来像这样:
pounds ounces
15.00 oz
19.00 oz
2lb 15.00oz
1lb 19.00oz
这是有效的,但几乎肯定有一种更整洁的"更熊猫"的方式来做到这一点…这应该足够快,可以处理5000个值。
进口:
import pandas as pd
测试数据设置(包括。后面有oz值的数据):
df = pd.DataFrame(["15.00 oz",
"19.00 oz",
"2 lb 15.00 oz",
"1 lb 19.00 oz",
"1 lb 12.80 oz",
"1 lb",
"nothing"],
columns=["weight"])
生产:
weight
0 15.00 oz
1 19.00 oz
2 2 lb 15.00 oz
3 1 lb 19.00 oz
4 1 lb 12.80 oz
5 1 lb
6 nothing
定义一个函数将单个lb/oz值映射到单个lb值。这需要一个元组数组,它可以是空的,例如:[(,'15.00')]
或[]
或[('1', '12.80')]
(此时匹配中的'数字'仍然是str
类型):
def lbsFromMatchedNumbers(matchData):
if len(matchData) == 0:
return None
(lbs, oz) = matchData[0]
lbs = float(lbs or 0)
oz = float(oz or 0)
ounces_in_pound = 16.0
return lbs + (oz / ounces_in_pound)
找到'weight'行中的所有项目,然后用函数处理它们,并分配给新的'lb'列:
matchPattern = "^(?:(d+) lb ?)?(?:(d+(?:.d+)?) oz)?$"
df["lb"] = df["weight"].str.findall(matchPattern).apply(lbsFromMatchedNumbers)
生产:
weight lb
0 15.00 oz 0.9375
1 19.00 oz 1.1875
2 2 lb 15.00 oz 2.9375
3 1 lb 19.00 oz 2.1875
4 1 lb 12.80 oz 1.8000
5 1 lb 1.0000
6 nothing NaN
注意:这是如果只有磅或盎司数字,如额外的行所示我使用的样本数据。如果两者都不存在,则生成NaN
。
regex部分说明
我们使用regex('正则表达式')来匹配'weight'
文本内容的部分使用这种模式:"^(?:(d+) lb ?)?(?:(d+(?:.d+)?) oz)?$"
使用的正则表达式语法
- d查找单个0-9值
- d+查找一个或多个0-9值(例如,1或435245)
?
(a,然后a ?)查找空格,或者什么都不查找(?
使其成为可选的)(hello)?
查找'hello',但如果没有找到,则继续(由于?
)- 括号将项目组合在一起
- 括号,后面跟着
?:
,(?:like this)
,将项目分组在一起,但不要将其保存为"匹配组"之一。在我们的示例中,当它们匹配时,只返回两个数字(因为它们被括在普通括号中)
我们的特定示例regex
把它们放在一起,这个正则表达式基本上是说:
- 从字符串的最开始(由
^
标记) - 这部分是可选的:
- 查找1个或多个0-9位数字-如果您发现这是'组1'
- 然后是空格
- 然后是文本'lb'
- 然后(可选)一个空格
- 后面跟着(也是可选的):
- 这整个部分是'group 2':
- 1个或多个0-9位数字
- 这个位是可选的:
- a
.
,后面接一个或多个0-9位数字
- a
- 然后是空格
- 然后文本'oz'
- 然后是字符串的末尾(由
$
标记)
- 这整个部分是'group 2':
weights = [15, 19] #different weights here
for i in weights:
weight = i / 16
print(weight)
试试这个,它应该是工作的,这是一个更简单的是做你所展示的。希望它对你有用!