[英]How to make a python program that calculates a result for each row of the input table?
我正在嘗試制作一個 Python 程序,該程序將根據公式、給定因素和輸入數據框計算結果。
在給定的道路長度( l
)和它們的平均速度( v
)上,我有許多汽車( N_cars
):
input_columns = ['l', 'N_cars', 'v']
input_data = [[3.5, 1000, 100], [5.7, 500, 110],
[10, 367, 110], [11.1, 1800, 95],
[2.8, 960, 105], [4.7, 800, 120],
[10.4, 103, 111], [20.1, 1950, 115]]
input_df = pd.DataFrame(input_data, columns=input_columns)
input_df
l N_cars v
0 3.5 1000 100
1 5.7 500 110
2 10.0 367 110
3 11.1 1800 95
4 2.8 960 105
5 4.7 800 120
6 10.4 103 111
7 20.1 1950 115
我還知道每個類別汽車的公式所需的因素,並且我知道每個類別的百分比。 對於每個類別,我也有不同的選項(我這里有 3 個選項只是一個示例,還有更多選項)。
factors_columns = ['category', 'category %', 'option', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
factors_data = [['A', 58, 'opt_1', 0.000011, 0.23521, 0.93847, 0.39458, 0.00817, 0.24566, 0.0010, 0],
['A', 58, 'opt_2', 0.000011, 0.23521, 0.93145, 0.39458, 0.00467, 0.24566, 0.0010, 0],
['A', 58, 'opt_3', 0.000011, 0.23521, 0.93145, 0.39458, 0.00467, 0.24566, 0.0010, 0],
['B', 22, 'opt_1', 0.002452, 0.48327, 0.83773, 0.92852, 0.00871, 0.29568, 0.0009, 0.02],
['B', 22, 'opt_2', 0.002899, 0.49327, 0.83773, 0.92852, 0.00871, 0.30468, 0.0009, 0.02],
['B', 22, 'opt_3', 0.002452, 0.48327, 0.83773, 0.92852, 0.00771, 0.29568, 0.0119, 0.01],
['C', 17, 'opt_1', 0.082583, 0.39493, 0.02462, 0.82714, 0.00918, 0.28572, 0.0012, 0],
['C', 17, 'opt_2', 0.072587, 0.35493, 0.02852, 0.82723, 0.00912, 0.29572, 0.0018, 0],
['C', 17, 'opt_3', 0.082583, 0.39493, 0.02852, 0.82714, 0.00962, 0.28572, 0.0012, 0.01],
['D', 3, 'opt_1', 0.018327, 0.32342, 0.82529, 0.92752, 0.00988, 0.21958, 0.0016, 0],
['D', 3, 'opt_2', 0.014427, 0.32342, 0.82729, 0.92752, 0.00968, 0.22558, 0.0026, 0],
['D', 3, 'opt_3', 0.018327, 0.32342, 0.82729, 0.94452, 0.00988, 0.21258, 0.0016, 0]]
factors_df = pd.DataFrame(factors_data, columns=factors_columns)
factors_df
category category % option a b c d e f g h
0 A 58 opt_1 0.000011 0.23521 0.93847 0.39458 0.00817 0.24566 0.0010 0.00
1 A 58 opt_2 0.000011 0.23521 0.93145 0.39458 0.00467 0.24566 0.0010 0.00
2 A 58 opt_3 0.000011 0.23521 0.93145 0.39458 0.00467 0.24566 0.0010 0.00
3 B 22 opt_1 0.002452 0.48327 0.83773 0.92852 0.00871 0.29568 0.0009 0.02
4 B 22 opt_2 0.002899 0.49327 0.83773 0.92852 0.00871 0.30468 0.0009 0.02
5 B 22 opt_3 0.002452 0.48327 0.83773 0.92852 0.00771 0.29568 0.0119 0.01
6 C 17 opt_1 0.082583 0.39493 0.02462 0.82714 0.00918 0.28572 0.0012 0.00
7 C 17 opt_2 0.072587 0.35493 0.02852 0.82723 0.00912 0.29572 0.0018 0.00
8 C 17 opt_3 0.082583 0.39493 0.02852 0.82714 0.00962 0.28572 0.0012 0.01
9 D 3 opt_1 0.018327 0.32342 0.82529 0.92752 0.00988 0.21958 0.0016 0.00
10 D 3 opt_2 0.014427 0.32342 0.82729 0.92752 0.00968 0.22558 0.0026 0.00
11 D 3 opt_3 0.018327 0.32342 0.82729 0.94452 0.00988 0.21258 0.0016 0.00
對於每個選項(opt_1、opt_2、opt_3),我必須根據這個公式計算結果(因子取自因子表,但 v 來自輸入表):
formula = ( (a*v*v) + (b*v) + c + (d/v) ) / ( (e*v*v) + (f*v) + g) * (1 - h)
result = l * N_cars * formula
但是,我必須考慮到每類汽車的百分比。 對於input_df
的每一行,我必須執行三次計算,三個選項中的每一個都執行一次。 例如,對於input_df
的索引 0 ,我有N_cars=1000
、 v=100
和l=3.5
,輸出應該是這樣的:
# for opt_1:
result = 3.5 * 1000 * ((58% of category A {formula for index 0 of factors_df}) +
(22% of category B {formula for index 3 of factors_df) +
(17% of category C {formula for index 6 of factors_df}) +
(3% of category D {formula for index 9 of factors_df}) )
# for opt_2:
result = 3.5 * 1000 * ((58% of category A {formula for index 1 of factors_df}) +
(22% of category B {formula for index 4 of factors_df) +
(17% of category C {formula for index 7 of factors_df}) +
(3% of category D {formula for index 10 of factors_df}) )
# for opt_3:
result = 3.5 * 1000 * ((58% of category A {formula for index 2 of factors_df}) +
(22% of category B {formula for index 5 of factors_df) +
(17% of category C {formula for index 8 of factors_df}) +
(3% of category D {formula for index 11 of factors_df}) )
因此,作為輸出,對於input_df
中的每一行,我應該有三個結果,一個用於三個選項中的每一個。
我可以為每個步驟手動進行計算,但我遇到的麻煩是創建一個循環,自動為每個輸入行和所有 3 個選項執行計算,然后傳遞到下一個輸入行,依此類推,直到最后一個輸入行.
不確定您的預期結果是什么,但我相信這可以滿足您的要求:
def formula(g, *, l, N_cars, v):
x = (1 - g.h) * (g.a * v*v + g.b*v + g.c + g.d/v) / (g.e * v*v + g.f*v + g.g)
return N_cars * l * (x * g.pct / 100).sum()
groups = factors_df.rename(columns={"category %": "pct"}).groupby("option")
result = input_df.apply(lambda r: groups.apply(lambda g: formula(g, **r)), axis=1)
輸出:
In [5]: input_df.join(result)
Out[5]:
l N_cars v opt_1 opt_2 opt_3
0 3.5 1000 100 5411.685077 5115.048256 5500.985916
1 5.7 500 110 4425.339734 4169.893681 4483.595803
2 10.0 367 110 5698.595376 5369.652565 5773.612841
3 11.1 1800 95 30820.717985 29180.106606 31384.785443
4 2.8 960 105 4165.270216 3930.726187 4226.877893
5 4.7 800 120 5860.057879 5506.509637 5919.496692
6 10.4 103 111 1663.960420 1567.455541 1685.339848
7 20.1 1950 115 60976.735053 57375.300546 61685.075902
第一步是按option
對factors_df
進行分組。 只是為了展示它的樣子:
In [6]: groups.apply(print)
category pct option a b ... d e f g h
0 A 58 opt_1 0.000011 0.23521 ... 0.39458 0.00817 0.24566 0.0010 0.00
3 B 22 opt_1 0.002452 0.48327 ... 0.92852 0.00871 0.29568 0.0009 0.02
6 C 17 opt_1 0.082583 0.39493 ... 0.82714 0.00918 0.28572 0.0012 0.00
9 D 3 opt_1 0.018327 0.32342 ... 0.92752 0.00988 0.21958 0.0016 0.00
[4 rows x 11 columns]
category pct option a b ... d e f g h
1 A 58 opt_2 0.000011 0.23521 ... 0.39458 0.00467 0.24566 0.0010 0.00
4 B 22 opt_2 0.002899 0.49327 ... 0.92852 0.00871 0.30468 0.0009 0.02
7 C 17 opt_2 0.072587 0.35493 ... 0.82723 0.00912 0.29572 0.0018 0.00
10 D 3 opt_2 0.014427 0.32342 ... 0.92752 0.00968 0.22558 0.0026 0.00
[4 rows x 11 columns]
category pct option a b ... d e f g h
2 A 58 opt_3 0.000011 0.23521 ... 0.39458 0.00467 0.24566 0.0010 0.00
5 B 22 opt_3 0.002452 0.48327 ... 0.92852 0.00771 0.29568 0.0119 0.01
8 C 17 opt_3 0.082583 0.39493 ... 0.82714 0.00962 0.28572 0.0012 0.01
11 D 3 opt_3 0.018327 0.32342 ... 0.94452 0.00988 0.21258 0.0016 0.00
請注意,我將category %
重命名為pct
。 這不是必需的,但可以更簡潔地訪問formula()
函數中的該列( g.pct
與g["category %"]
)。
下一步是實現formula()
以接受來自factors_df
的組作為參數:
def formula(g, *, l, N_cars, v):
x = (1 - g.h) * (g.a * v*v + g.b*v + g.c + g.d/v) / (g.e * v*v + g.f*v + g.g)
return N_cars * l * (x * g.pct / 100).sum()
在函數簽名中, g
是來自factors_df
的組,然后是關鍵字參數l
、 N_cars
和v
,它們一次來自input_df
的單行。
上面顯示的三個組中的每一個都將一次一個地完整地輸入到formula()
函數中。 例如,在一次調用formula()
期間, g
參數將保存所有這些數據:
category pct option a b ... d e f g h
0 A 58 opt_1 0.000011 0.23521 ... 0.39458 0.00817 0.24566 0.0010 0.00
3 B 22 opt_1 0.002452 0.48327 ... 0.92852 0.00871 0.29568 0.0009 0.02
6 C 17 opt_1 0.082583 0.39493 ... 0.82714 0.00918 0.28572 0.0012 0.00
9 D 3 opt_1 0.018327 0.32342 ... 0.92752 0.00988 0.21958 0.0016 0.00
當公式使用類似ge
的東西時,它正在訪問整個e
列,並利用矢量化同時對整個列執行算術計算。 塵埃落定后, x
將成為一個Series
,其中系列中的每個項目將是四個汽車類別中每個類別的公式的結果。 這是一個例子:
0 0.231242
3 0.619018
6 7.188941
9 1.792376
注意到指數了嗎? 它們分別對應於factors_df
中A
、 B
、 C
和D
類別。
從那里,我們需要在input_df
的每一行上調用formula()
,使用pd.DataFrame.apply()
的axis
參數:
input_df.apply(lambda r: groups.apply(lambda g: formula(g, **r)), axis=1)
lambda r
是傳遞給apply
的匿名函數對象,應用於軸 1,這意味着r
一次將是input_df
的單行,例如:
In [13]: input_df.apply(print, axis=1)
l 3.5
N_cars 1000.0
v 100.0
Name: 0, dtype: float64
.
.
.
現在,在每個逐行apply
中,我們還使用lambda g: formula(g, **r)
對groups
groupby 對象應用formula()
函數。 **r
將input_df
中的行解包為關鍵字參數,這有助於確保v
、 l
和N_cars
的值不會在公式中被濫用(無需擔心它們傳遞到formula()
函數)。
這是我寫的代碼。 它有點長,但它有效。 可能是您(或某人)可以修改並使其更短。
# Transforming factors_df
df = factors_df.pivot(columns=["category", "option"])
df.reset_index(inplace=True)
# Renaming column names for each combination of option and category
df.columns = [s3 + s2 + s1 for (s1, s2, s3) in df.columns.to_list()]
df.drop(columns=["index"], inplace=True)
# Flattening to a single row to be able to apply formula
df = pd.DataFrame(df.max()).T
# Merging input with transformed factors data
input_df["tmp"] = 1
df["tmp"] = 1
df = pd.merge(input_df, df, on="tmp", how="left")
df.drop("tmp", axis=1, inplace=True)
# Calculating values for opt_1 using the formula
df["opt_1_value"] = (
df["l"]
* df["N_cars"]
* (
(
df["opt_1Acategory %"]
/ 100
* (
df["opt_1Aa"] * df["v"] * df["v"]
+ df["opt_1Ab"] * df["v"]
+ df["opt_1Ac"]
+ df["opt_1Ad"] / df["v"]
)
/ (
(
df["opt_1Ae"] * df["v"] * df["v"]
+ df["opt_1Af"] * df["v"]
+ df["opt_1Ag"]
)
* (1 - df["opt_1Ah"])
)
)
+ (
df["opt_1Bcategory %"]
/ 100
* (
df["opt_1Ba"] * df["v"] * df["v"]
+ df["opt_1Bb"] * df["v"]
+ df["opt_1Bc"]
+ df["opt_1Bd"] / df["v"]
)
/ (
(
df["opt_1Be"] * df["v"] * df["v"]
+ df["opt_1Bf"] * df["v"]
+ df["opt_1Bg"]
)
* (1 - df["opt_1Bh"])
)
)
+ (
df["opt_1Ccategory %"]
/ 100
* (
df["opt_1Ca"] * df["v"] * df["v"]
+ df["opt_1Cb"] * df["v"]
+ df["opt_1Cc"]
+ df["opt_1Cd"] / df["v"]
)
/ (
(
df["opt_1Ce"] * df["v"] * df["v"]
+ df["opt_1Cf"] * df["v"]
+ df["opt_1Cg"]
)
* (1 - df["opt_1Ch"])
)
)
)
)
# Calculating values for opt_2 using the formula
df["opt_2_value"] = (
df["l"]
* df["N_cars"]
* (
(
df["opt_2Acategory %"]
/ 100
* (
df["opt_2Aa"] * df["v"] * df["v"]
+ df["opt_2Ab"] * df["v"]
+ df["opt_2Ac"]
+ df["opt_2Ad"] / df["v"]
)
/ (
(
df["opt_2Ae"] * df["v"] * df["v"]
+ df["opt_2Af"] * df["v"]
+ df["opt_2Ag"]
)
* (1 - df["opt_2Ah"])
)
)
+ (
df["opt_2Bcategory %"]
/ 100
* (
df["opt_2Ba"] * df["v"] * df["v"]
+ df["opt_2Bb"] * df["v"]
+ df["opt_2Bc"]
+ df["opt_2Bd"] / df["v"]
)
/ (
(
df["opt_2Be"] * df["v"] * df["v"]
+ df["opt_2Bf"] * df["v"]
+ df["opt_2Bg"]
)
* (1 - df["opt_2Bh"])
)
)
+ (
df["opt_2Ccategory %"]
/ 100
* (
df["opt_2Ca"] * df["v"] * df["v"]
+ df["opt_2Cb"] * df["v"]
+ df["opt_2Cc"]
+ df["opt_2Cd"] / df["v"]
)
/ (
(
df["opt_2Ce"] * df["v"] * df["v"]
+ df["opt_2Cf"] * df["v"]
+ df["opt_2Cg"]
)
* (1 - df["opt_2Ch"])
)
)
)
)
# Calculating values for opt_3 using the formula
df["opt_3_value"] = (
df["l"]
* df["N_cars"]
* (
(
df["opt_3Acategory %"]
/ 100
* (
df["opt_3Aa"] * df["v"] * df["v"]
+ df["opt_3Ab"] * df["v"]
+ df["opt_3Ac"]
+ df["opt_3Ad"] / df["v"]
)
/ (
(
df["opt_3Ae"] * df["v"] * df["v"]
+ df["opt_3Af"] * df["v"]
+ df["opt_3Ag"]
)
* (1 - df["opt_3Ah"])
)
)
+ (
df["opt_3Bcategory %"]
/ 100
* (
df["opt_3Ba"] * df["v"] * df["v"]
+ df["opt_3Bb"] * df["v"]
+ df["opt_3Bc"]
+ df["opt_3Bd"] / df["v"]
)
/ (
(
df["opt_3Be"] * df["v"] * df["v"]
+ df["opt_3Bf"] * df["v"]
+ df["opt_3Bg"]
)
* (1 - df["opt_3Bh"])
)
)
+ (
df["opt_3Ccategory %"]
/ 100
* (
df["opt_3Ca"] * df["v"] * df["v"]
+ df["opt_3Cb"] * df["v"]
+ df["opt_3Cc"]
+ df["opt_3Cd"] / df["v"]
)
/ (
(
df["opt_3Ce"] * df["v"] * df["v"]
+ df["opt_3Cf"] * df["v"]
+ df["opt_3Cg"]
)
* (1 - df["opt_3Ch"])
)
)
)
)
# Removing unnecessary columns
df_final = df[["l", "N_cars", "v", "opt_1_value", "opt_2_value", "opt_3_value"]]
print(df_final)
輸出:
l N_cars v opt_1_value opt_2_value opt_3_value
0 3.5 1000 100 1496.002370 1420.656629 1534.748740
1 5.7 500 110 750.997279 710.944885 767.411691
2 10.0 367 110 551.157686 521.754019 562.906668
3 11.1 1800 95 2685.551348 2554.477141 2756.164589
4 2.8 960 105 1439.467965 1364.815604 1475.082027
5 4.7 800 120 1206.116125 1138.614075 1229.225287
6 10.4 103 111 154.744048 146.445615 157.990346
7 20.1 1950 115 2933.825622 2773.297776 2990.828374
另一種方法是,不像@ddejhon 的解決方案那樣優雅,但是:
def formula(input_index, factors_index):
formula = ((factors_df.loc[factors_index,'a']*input_df['v'][input_index]**2)+
(factors_df.loc[factors_index,'b']*input_df['v'][input_index])+
(factors_df.loc[factors_index,'c'])+
(factors_df.loc[factors_index,'d']/input_df['v'][input_index])
)/(
(factors_df.loc[factors_index,'e']*input_df['v'][input_index]**2)+
(factors_df.loc[factors_index,'f']*input_df['v'][input_index])+
(factors_df.loc[factors_index,'g'])
)*(1-factors_df.loc[factors_index,'h'])
return formula
index_list = [factors_df[factors_df['option'] == opt].index.tolist() for opt in factors_df['option'].unique().tolist()]
Edit1
:擺脫了丑陋的嵌套結構,並用列表理解代替了它
output_df = pd.DataFrame(np.repeat(input_df.values, len(factors_df['option'].unique()), axis=0))
output_df.columns = input_df.columns
output_df['option'] = factors_df['option'].unique().tolist()*len(input_df.index)
output_df['formula'] = [n for sub_list in [[sum(factors_df['category %'].unique()[k]/100 * formula(i,j[k])
for k in range(len(factors_df['category'].unique())))
for j in index_list] for i in input_df.index] for n in sub_list]
output_df['result'] = output_df['l'] * output_df['N_cars'] * output_df['formula']
輸出:
output_df
l N_cars v option formula result
0 3.5 1000.0 100.0 opt_1 1.546196 5411.685077
1 3.5 1000.0 100.0 opt_2 1.461442 5115.048256
2 3.5 1000.0 100.0 opt_3 1.571710 5500.985916
3 5.7 500.0 110.0 opt_1 1.552751 4425.339734
4 5.7 500.0 110.0 opt_2 1.463121 4169.893681
5 5.7 500.0 110.0 opt_3 1.573192 4483.595803
6 10.0 367.0 110.0 opt_1 1.552751 5698.595376
7 10.0 367.0 110.0 opt_2 1.463121 5369.652565
8 10.0 367.0 110.0 opt_3 1.573192 5773.612841
9 11.1 1800.0 95.0 opt_1 1.542578 30820.717985
10 11.1 1800.0 95.0 opt_2 1.460466 29180.106606
11 11.1 1800.0 95.0 opt_3 1.570810 31384.785443
12 2.8 960.0 105.0 opt_1 1.549580 4165.270216
13 2.8 960.0 105.0 opt_2 1.462324 3930.726187
14 2.8 960.0 105.0 opt_3 1.572499 4226.877893
15 4.7 800.0 120.0 opt_1 1.558526 5860.057879
16 4.7 800.0 120.0 opt_2 1.464497 5506.509637
17 4.7 800.0 120.0 opt_3 1.574334 5919.496692
18 10.4 103.0 111.0 opt_1 1.553361 1663.960420
19 10.4 103.0 111.0 opt_2 1.463271 1567.455541
20 10.4 103.0 111.0 opt_3 1.573319 1685.339848
21 20.1 1950.0 115.0 opt_1 1.555727 60976.735053
22 20.1 1950.0 115.0 opt_2 1.463842 57375.300546
23 20.1 1950.0 115.0 opt_3 1.573800 61685.075902
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.