攝影或3C

Python 機器學習: 如何將if ~ else ~語法寫為一列,塞進lambda函數中, pandas.DataFrame 如何使用 .apply(func) 增加新的一欄? model = tensorflow.keras.models.Sequential()

原始資料如下:

原始資料的
最後一欄為RainTomorrow
如何再新增一欄
將該欄位的
Yes改為1
No改為0
code:

# -*- coding: utf-8 -*-
"""
Created on Sun Nov 12 15:27:56 2023

@author: SavingKing
"""

import os
import pandas as pd
dirname = r"C:\SavingKing\Downloads\day6\ch07-MLP-flower"
basename = "weather.csv"

fpath = os.path.join(dirname,basename)
#'C:\\Users\\SavingKing\\Downloads\\day6\\ch07-MLP-flower\\weather.csv'

df = pd.read_csv(fpath)

func = lambda strr: 1 if strr == "Yes" else 0

df["RainTomorrow_01"] = df["RainTomorrow"].apply( func )

輸出結果:

df多了一欄 RainTomorrow_01

推薦hahow線上學習python: https://igrape.net/30afN

weather.csv 的部分內容:

MinTempMaxTempRainfallEvaporationSunshineWindGustDirWindGustSpeedWindDir9amWindDir3pmWindSpeed9amWindSpeed3pmHumidity9amHumidity3pmPressure9amPressure3pmCloud9amCloud3pmTemp9amTemp3pmRainTodayRISK_MMRainTomorrow
824.303.46.3NW30SWNW62068291019.710157714.423.6No3.6Yes
1426.93.64.49.7ENE39EW41780361012.41008.45317.525.7Yes3.6Yes
13.723.43.65.83.3NW85NNNE6682691009.51007.28715.420.2Yes39.8Yes
13.315.539.87.29.1NW54WNWW302462561005.510072713.514.1Yes2.8Yes
7.616.12.85.610.6SSE50SSEESE202868491018.31018.57711.115.4Yes0No
6.216.905.88.2SE44SEE202470571023.81021.77510.914.8No0.2No
6.118.20.24.28.4SE43SEESE192663471024.61022.24612.417.3No0No
8.31705.64.6E41SEE112465571026.21024.26712.115.5No0No
8.819.5044.1S48EENE191770481026.11022.77714.118.9No16.2Yes

tensorflow.keras
code:

# -*- coding: utf-8 -*-
"""
Created on Sun Nov 12 15:27:56 2023

@author: SavingKing
"""

import os
import pandas as pd
import numpy as np
dirname = r"P:\Python class\powen\AI人工智慧自然語言與語音語意辨識開發應用實務班\powen2_AI人工智慧自然語言與語音語意辨識開發應用實務班\day6\ch07-MLP-flower"
basename = "weather.csv"

fpath = os.path.join(dirname,basename)
#'C:\\Users\\SavingKing\\Downloads\\day6\\ch07-MLP-flower\\weather.csv'

df = pd.read_csv(fpath)

func = lambda strr: 1 if strr == "Yes" else 0

df["RainTomorrow_01"] = df["RainTomorrow"].apply( func )

lis_drop_col = ["WindGustDir", "WindDir9am","WindDir3pm","RainToday","RainTomorrow"]
#非數值資料的欄位先drop只留下數值資料的欄位
#WindSpeed9am 資料含有NA

df_dp = df.drop(columns = lis_drop_col)
#[366 rows x 18 columns]
df_dp.dropna(axis=0, how='any', subset=None, inplace=True)
#[354 rows x 18 columns]

#資料中含有NA,需要先dropna做資料清洗,不然loss, predict會出現nan
df_dp.dropna(axis=0, how='any', subset=None, inplace=True)
#[354 rows x 18 columns]

X = df_dp.drop(columns="RainTomorrow_01").values
#[366 rows x 17 columns]
Y = df_dp.iloc[:,-1].values
#pandas.core.series.Series
"""
X.shape
Out[61]: (366, 17)

Y.shape
Out[62]: (366,)
"""

from sklearn.model_selection import train_test_split
import tensorflow as tf

category=2   #下雨/不下雨 分別用1 0 代表, 兩種結果
dim=X.shape[1] #有幾個特徵值?
x_train , x_test , y_train , y_test = train_test_split(X,Y,test_size=0.05)
y_train2=tf.keras.utils.to_categorical(y_train, num_classes=(category))
y_test2=tf.keras.utils.to_categorical(y_test, num_classes=(category))
#One-hot Encoding 單熱編碼
#y_train y_test 都是一維的資料

print("x_train[:4]",x_train[:4])
print("y_train[:4]",y_train[:4])
print("y_train2[:4]",y_train2[:4])

# 建立模型
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Dense(units=200,
    activation=tf.nn.relu,
    input_dim=dim)) #input_dim 有幾個特徵值不能錯
model.add(tf.keras.layers.Dense(units=200,
    activation=tf.nn.relu ))
model.add(tf.keras.layers.Dense(units=200,
    activation=tf.nn.relu ))
model.add(tf.keras.layers.Dense(units=200,
    activation=tf.nn.relu ))
model.add(tf.keras.layers.Dense(units=category,
    activation=tf.nn.softmax )) #最後一層units=category也不能錯
model.compile(optimizer='adam',
    loss=tf.keras.losses.categorical_crossentropy,
    metrics=['accuracy'])
model.fit(x_train, y_train2,
          epochs=1000,
          batch_size=64)

#測試
model.summary()

score = model.evaluate(x_test, y_test2)
print("score:",score)

predict = model.predict(x_test)
print("predict:",predict)
lis_ans = [np.argmax(predict[i]) for i in range(predict.shape[0]) ]
print("Ans:\t",lis_ans)
# print("Ans:",np.argmax(predict[0]),np.argmax(predict[1]),np.argmax(predict[2]),np.argmax(predict[3]))

# =============================================================================
# predict2 = model.predict_classes(x_test)
# print("predict_classes:",predict2)
# print("y_test",y_test[:])
# =============================================================================

輸出結果:

若在輸出結果中看到
loss, predict會出現nan
應該有所警覺,
這是不尋常的現象

检查数据

  • 确保输入数据(X)中没有NaN或无限大(Infinity)值。
  • 检查数据的范围和分布。有时,数据标准化(例如,使用StandardScaler)可以帮助避免数值不稳定。

在处理多类别分类问题时,最后一层最推荐使用Softmax激活函数。这是因为Softmax可以将输出转换为一个概率分布,每个类别的输出值在0和1之间,并且所有输出值加起来等于1。这样,每个输出可以被解释为模型对于每个可能类别的预测概率。

对于二分类问题,虽然也可以使用Softmax,但通常只需一个输出节点,并使用Sigmoid激活函数。Sigmoid函数将单个输出压缩到0和1之间,可以直接解释为事件发生的概率。

要点如下:

  • 多类分类:使用Softmax,每个类别一个输出节点。
  • 二分类:使用Sigmoid,一个输出节点即可。

对于二分类问题,理论上可以使用Softmax激活函数,尽管它更常见于多分类问题。对于二分类,Softmax将会输出两个值,分别代表属于第一类和第二类的概率,这两个值加起来总和为1。在二分类情况下,Softmax实际上和使用单个Sigmoid激活函数的效果是等价的,因为Sigmoid函数输出的是一个概率值,表示为正类的概率,而1减去这个值则表示为负类的概率。

使用Sigmoid还是Softmax?

  • Sigmoid:在二分类问题中,你通常会看到使用Sigmoid函数,因为它输出一个单一的概率值,模型的输出可以直接解释为一个类别的概率,另一个类别的概率是1减去这个概率值。
  • Softmax:即使是在二分类问题中,使用Softmax也是可行的。它会提供两个输出值,一个为正类的概率,另一个为负类的概率,这两个概率相加等于1。

在实际操作中,无论是使用Softmax还是Sigmoid,通常都会根据模型的输出选择合适的阈值来确定最终的类别。例如,如果正类的概率大于0.5(或另一个选定的阈值),则预测为正类,否则预测为负类。

为什么二分类问题中还是可以使用Softmax?

在一些深度学习框架中,出于实现的便利性或者为了保持模型架构的一致性,即使在二分类问题中也可以使用Softmax。特别是当你有可能将二分类问题扩展到多分类问题时,使用Softmax可以使得模型的输出层在不同配置间更容易切换。此外,在某些框架中,针对二分类问题的交叉熵损失函数实际上在内部计算时会使用与Softmax相似的数学公式。

推薦hahow線上學習python: https://igrape.net/30afN

model.summary()


model.compilemodel.fit是TensorFlow中Keras API的两个关键步骤,它们在神经网络的训练过程中扮演不同但互补的角色。

model.compile

model.compile是用来配置训练模型的过程的。在这一步,你定义了三个重要的元素:

  1. 优化器(Optimizer):
    • 决定了模型如何更新权重以及学习速率。常见的优化器包括SGD、Adam、RMSprop等。
  2. 损失函数(Loss function):
    • 用于量化模型输出与目标值之间的差异。例如,用于回归问题的损失函数可能是均方误差(MSE),而用于分类问题的损失函数可能是交叉熵(Crossentropy)。
  3. 评估指标(Metrics):
    • 用于监视训练和测试过程。常见的指标包括准确度(accuracy)、召回率(recall)、精确度(precision)等。

model.fit

model.fit是用来训练模型的步骤。在这个阶段,模型开始学习数据,不断调整权重以最小化model.compile中定义的损失函数。model.fit需要以下几个参数:

  1. 输入数据(Input data):
    • 用于训练模型的特征数据。
  2. 目标数据(Target data):
    • 训练数据对应的标签或目标。
  3. 批次大小(Batch size):
    • 指定在更新模型之前要处理的数据的数量。较小的批量可以提高训练过程的泛化能力,但可能会增加训练时间。
  4. 迭代次数(Epochs):
    • 完整数据集的遍历次数。一个epoch意味着每个样本在训练过程中被使用了一次。
  5. 验证数据(Validation data)或分割比例(Validation split)(可选):
    • 用于在训练过程中评估模型性能的数据。这不会用于训练,仅用于评估。

区别

  • 作用model.compile用于配置训练模型的方式,而model.fit用于实际训练模型。
  • 时间点:首先执行model.compile来定义训练过程的参数,然后执行model.fit来开始训练过程。

简而言之,model.compile是设置训练模型的“规则”,而model.fit是根据这些“规则”进行训练的过程。

在机器学习和深度学习的上下文中,“Sparse”通常翻译为“稀疏”。在这种情况下,“稀疏”指的是大多数元素为零或不需要表示的情况。例如,稀疏矩阵中的大部分元素都是零。相对地,“稠密”(Dense)则意味着大多数的元素都是非零的。

sparse_categorical_crossentropy中,“稀疏”表明标签是以稀疏格式给出的,即直接用类别的索引来表示,而不是用One-hot 编码的方式(其中One-hot 编码的向量在除了一个位置为1外,其他位置都为0,更“稠密”)。所以,当你的分类标签是简单的整数列表(例如,[0, 2, 1, …]),而不是One-hot 编码的形式时,就会使用“稀疏分类交叉熵”作为损失函数。

label若使用one hot encoding
損失函數則需使用
tensorflow.keras.losses.categorical_crossentropy

推薦hahow線上學習python: https://igrape.net/30afN

新版本的
predict2 = model.predict_classes(x_test)

要改成
predict2 = model.predict(x_test)
predict2=np.argmax(predict2,axis=1)
#每row取出最大值的index

lis_ans:

predict = model.predict(x_test)
lis_ans = [np.argmax(predict[i]) for i in range(predict.shape[0]) ]

对predict数组进行迭代,其中predict是模型对x_test的预测。predict[i]给出了第i个测试样本的所有类别的预测概率。

当您使用np.argmax(predict[i])时,由于predict[i]本身是一维的,所以不需要指定axis参数;它默认就会在这个一维数组上操作。这段代码遍历每个样本的预测概率数组,并找出概率最高的类别索引。

而如果您直接在predict二维数组上使用np.argmax,您应该指定axis=1来沿着列(每个样本的所有类别的预测概率)查找最大值的索引。这样,您可以用一行代码替代整个for循环:

predict2 = np.argmax(predict, axis=1)

这里axis=1的含义是您要沿着横轴(每列)查找最大值的索引。这将返回每个样本预测概率最高的类别索引的一维数组,与您使用for循环得到的lis_ans数组相同。

推薦hahow線上學習python: https://igrape.net/30afN

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡