使用 Pandas 从另一列中显示的小数位数四舍五入一列中的数字
Round off numbers in one column from the number of decimal places shown in another column using Pandas
我想使用 Pandas.[=15= 根据另一列中显示的小数位数(不完全相同)对一列中的数字进行四舍五入]
我的数据
numbers decimal
1.2345 2
2.3456 3
3.4567 2
预期输出:
numbers decimal newcolA
0 1.2345 2 1.23
1 2.3456 3 2.346
2 3.4567 2 3.46
我的代码#1
import pandas as pd
df = pd.DataFrame(
data = {
'numbers' : [1.2345, 2.3456, 3.4567],
'decimal' : [2,3,2]
}
)
df['newcolA'] = round(df['numbers'] , df['decimal'])
我收到以下错误:
TypeError: 无法将系列转换为
但是,以下相似代码有效
我的代码#2
import pandas as pd
df = pd.DataFrame(
data = {
'numbers' : [1.2345, 2.3456, 3.4567],
'decimal' : [2,3,2]
}
)
df['newcolB'] = df['numbers']*df['decimal'] #The only difference
df
numbers decimal newcolB
0 1.2345 2 2.4690
1 2.3456 3 7.0368
2 3.4567 2 6.9134
我有什么不明白的?为什么代码 2 有效,但第一个无效
尝试:
>>> df.apply(lambda x: round(x['numbers'], int(x['decimal'])), axis=1)
0 1.230
1 2.346
2 3.460
dtype: float64
由于您的问题更多是关于理解两种不同的行为,因此将重点关注这一点。
代码 #1
df['newcolA'] = round(df['numbers'] , df['decimal'])
df['numbers'] & df['decimal'] 属于 Series
类型。实际上,您正在将一个 Series 传递给 round
但它需要一个数字。因此错误:TypeError:无法将系列转换为
代码 #2
df['numbers']*df['decimal']
Pandas 允许使用向量化运算在两个相同长度的序列之间进行各种运算。
解决方案
有多种可能的解决方案,最惯用的是使用 apply
(@Corralien 已发布)
我已经调整了@Corralien 的解决方案,以免引入任何多余的 0(这些数字都是大于 1 的非整数实数,所以我相信我的 noZero 函数是正确的)
import pandas as pd
from math import log10, floor
def noZero(x, rd): # rd digits at right
ld = floor(log10(x))+1 # ld digits at left
x = round(x,rd)
fmt = "{:<0" + str(ld + 1 + rd) + "." + str(rd) + "f}"
x_str = fmt.format(x)
return x_str
df = pd.DataFrame(
data = {
'numbers' : [1.2345, 2.3456, 3.4567, 3.399],
'decimal' : [2, 3, 2, 2]
}
)
df['newcolA'] = df.apply(lambda x: round(x['numbers'], int(x['decimal'])), axis=1)
df['happy :)'] = df.apply(lambda x: noZero(x['newcolA'], int(x['decimal'])), axis=1)
df
numbers decimal newcolA happy :)
0 1.2345 2 1.230 1.23
1 2.3456 3 2.346 2.346
2 3.4567 2 3.460 3.46
3 3.3990 2 3.400 3.40
我想使用 Pandas.[=15= 根据另一列中显示的小数位数(不完全相同)对一列中的数字进行四舍五入]
我的数据
numbers decimal
1.2345 2
2.3456 3
3.4567 2
预期输出:
numbers decimal newcolA
0 1.2345 2 1.23
1 2.3456 3 2.346
2 3.4567 2 3.46
我的代码#1
import pandas as pd
df = pd.DataFrame(
data = {
'numbers' : [1.2345, 2.3456, 3.4567],
'decimal' : [2,3,2]
}
)
df['newcolA'] = round(df['numbers'] , df['decimal'])
我收到以下错误:
TypeError: 无法将系列转换为
但是,以下相似代码有效
我的代码#2
import pandas as pd
df = pd.DataFrame(
data = {
'numbers' : [1.2345, 2.3456, 3.4567],
'decimal' : [2,3,2]
}
)
df['newcolB'] = df['numbers']*df['decimal'] #The only difference
df
numbers decimal newcolB
0 1.2345 2 2.4690
1 2.3456 3 7.0368
2 3.4567 2 6.9134
我有什么不明白的?为什么代码 2 有效,但第一个无效
尝试:
>>> df.apply(lambda x: round(x['numbers'], int(x['decimal'])), axis=1)
0 1.230
1 2.346
2 3.460
dtype: float64
由于您的问题更多是关于理解两种不同的行为,因此将重点关注这一点。
代码 #1
df['newcolA'] = round(df['numbers'] , df['decimal'])
df['numbers'] & df['decimal'] 属于 Series
类型。实际上,您正在将一个 Series 传递给 round
但它需要一个数字。因此错误:TypeError:无法将系列转换为
代码 #2
df['numbers']*df['decimal']
Pandas 允许使用向量化运算在两个相同长度的序列之间进行各种运算。
解决方案
有多种可能的解决方案,最惯用的是使用 apply
(@Corralien 已发布)
我已经调整了@Corralien 的解决方案,以免引入任何多余的 0(这些数字都是大于 1 的非整数实数,所以我相信我的 noZero 函数是正确的)
import pandas as pd
from math import log10, floor
def noZero(x, rd): # rd digits at right
ld = floor(log10(x))+1 # ld digits at left
x = round(x,rd)
fmt = "{:<0" + str(ld + 1 + rd) + "." + str(rd) + "f}"
x_str = fmt.format(x)
return x_str
df = pd.DataFrame(
data = {
'numbers' : [1.2345, 2.3456, 3.4567, 3.399],
'decimal' : [2, 3, 2, 2]
}
)
df['newcolA'] = df.apply(lambda x: round(x['numbers'], int(x['decimal'])), axis=1)
df['happy :)'] = df.apply(lambda x: noZero(x['newcolA'], int(x['decimal'])), axis=1)
df
numbers decimal newcolA happy :)
0 1.2345 2 1.230 1.23
1 2.3456 3 2.346 2.346
2 3.4567 2 3.460 3.46
3 3.3990 2 3.400 3.40