日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

pandas中的那些让人有点懵逼的异常(坑向)

發布時間:2023/12/13 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 pandas中的那些让人有点懵逼的异常(坑向) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

楔子

pandas是一個很強大的庫,但是在使用的過程中難免會遇見各種奇葩的異常,而這些異常卻又很難讓人定位到底是哪一步出了問題。下面就來看看pandas中的一些令人感到費解的異常吧,看看你有沒有遇到過,如果沒有的話,那么說明你pandas可能用的不夠多哦。

ヽ( ̄ω ̄( ̄ω ̄〃)ゝ一起來看看

1. SettingWithCopyWarning:

當然這不是個異常,而是一個警告,這個警告相信大多數人都遇到過,尤其是初學pandas的時候。這個警告具體內容如下:

SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/......

我們來復現一下這個警告:

import pandas as pd

df = pd.DataFrame({"name": ["mashiro", "koishi", "satori", "kurisu"],
                   "age": [17, 16, 17, 19],
                   "adult": [None, None, None, None]})

print(df)
"""
      name  age adult
0  mashiro   17  None
1   koishi   16  None
2   satori   17  None
3   kurisu   19  None
"""
# 我現在想將df中age > 18對應的audit設置為True

# 但是會發現沒有效果,并且SettingWithCopyWarning就是由這一行代碼引發的
df[df["age"] > 16]["adult"] = True
print(df)
"""
      name  age adult
0  mashiro   17  None
1   koishi   16  None
2   satori   17  None
3   kurisu   19  None
"""

為什么會出現這個原因呢?因為df[df["age"] > 16]得到的是原始DataFrame的一份拷貝,因此其相應的操作不會影響原來的DataFrame。盡管這樣的操作是允許的,但是卻無法得到正確的結果,因此pandas彈出了一個警告。

# 真正的做法是使用loc或者iloc
df.loc[df["age"] > 18, "adult"] = True
print(df)
"""
      name  age adult
0  mashiro   17  None
1   koishi   16  None
2   satori   17  None
3   kurisu   19  None
"""

2. TypeError: 'Series' objects are mutable, thus they cannot be hashed

這個異常實際上比較常見了,說白了就是你不小心把loc或者iloc給丟掉了,我們還用上面的例子

try:
    df[df["age"] > 18, "adult"] = True
except Exception as e:
    print(e)  # 'Series' objects are mutable, thus they cannot be hashed

3. ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all()

我們知道,像if a:,not a之類的,本質上都是調用a的__bool__方法,可以理解為bool(a)

class A:

    def __bool__(self):
        return True


if A():
    print("123")
else:
    print("456")
print(bool(A()))
"""
123
True
"""


# 由于A的__bool__返回了True, 所以bool(A())為True
# 我們將其改為False
A.__bool__ = lambda self: False
print(bool(A()))  # False

但是對于一個Series或者numpy中的array不可以這么做。

import pandas as pd

s = pd.Series([True, False])
try:
    bool(s)
except Exception as e:
    print(e)  # The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

try:
    if s.values:  # 得到一個numpy中的array
        pass
except Exception as e:
    print(e)  # The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()


"""
對于一個Series對象來說,不可以使用其布爾值,應當使用 s.all()、s.any()或者np.all(s)、np.any(s)

但是對于numpy中的array來講,如果這個array里面的元素不止一個,那么也不可以使用其布爾值,但如果該array中只有一個元素的話是個例外
此時:if np.array([123]) 等價于 if 123

因此如果使用其布爾值的話,最好使用np.all()或者np.any()將一個序列變成單個布爾值
"""

# 但如果只是希望像列表一樣,如果該Series對象里面有值就是真,否則就是假
# 那么建議通過 if len(s):這種方式來判斷
# 同理DataFrame也是如此

4. 布爾你咋啦?

我們知道,可以對兩個類型為bool的Series對象進行 與、或、非 等操作,但是結果真的一定是我們想要的嗎?

import pandas as pd

s1 = pd.Series([True, True, True])
s2 = pd.Series([True, False, True], index=[1, 2, 3])

print(s1 & s2)
"""
0    False
1     True
2    False
3    False
dtype: bool
"""
# 我們看到與運算之后,長度變成了4,究其原因就是兩個Series索引不同造成的
# 而Series的很多操作都是基于索引進行對齊的,并不是簡簡單單地按照順序
# 但如果對應的索引一樣的話,那么也可以認為就是按照順序從上到下
# 但如果索引不一樣的話,pandas是怎么做的呢?答案是使用reindex

# 首先找到兩個Series對象中出現的所有不重復索引
index = s1.index | s2.index
print(index)  # Int64Index([0, 1, 2, 3], dtype='int64')

# 使用reindex進行對齊, 不存在的使用NaN代替,當然我們也可以指定fill_value進行填充
# 比如fill_value=False
print(s1.reindex(index))
"""
0    True
1    True
2    True
3     NaN
dtype: object
"""
print(s2.reindex(index))
"""
0      NaN
1     True
2    False
3     True
dtype: object
"""

# 所以s1 & s2最終等價于 s1.reindex(index) & s2.reindex(index)
# 因此即使兩者個數不同也是沒有問題的
s1 = pd.Series([True, True, True, True])
s2 = pd.Series([True, True, True], index=[1, 2, 3])
print(s1 & s2)
"""
0    False
1     True
2     True
3     True
dtype: bool
"""

總之pandas中很多操作,并不是我們想的那么簡單,pandas的Series和DataFrame都具備索引的概念,通過索引來定位速度是非常快的。但是不注意就會造成陷阱,究其原因就是很多操作在定位的時候是基于索引來定位的,并不是簡單的按照順序。比如:s1 & s2,指的是s1和s2中相同索引對應的元素進行與運算,當然如果有對應不上的,事先已經通過reindex處理好了。

當然,如果我們不希望考慮索引的話,只是單純的希望按照順序進行位運算,該怎么做呢?辦法有兩種

import pandas as pd

s1 = pd.Series([True, True, True])
s2 = pd.Series([True, False, True], index=[1, 2, 3])

# 對Series使用reset_index即可,當然要指定drop=True,否則就變成DataFrame了
# 一旦reset_index之后兩者索引從頭到尾就是一致的了
print(s1.reset_index(drop=True) & s2.reset_index(drop=True))
"""
0     True
1    False
2     True
dtype: bool
"""

# 或者轉成numpy中的array
# 我們知道Series等價于numpy中的n個array,分別存放索引、值等等
# 我們調用s.index即可拿到索引,s.values即可拿到值
print(s1.values & s2)
"""
1     True
2    False
3     True
dtype: bool
"""
# 如果其中是一個array的話,那么它沒有索引的概念,索引此時也是單純的一個一個對應進行運算
# 當然得到的結果也是一個Series,索引和運算的Series的索引保持一致

# 或者都轉成array
print(s1.values & s2.values)  # [ True False  True]

# 但是注意:如果其中一方轉成了array,那么此時就要求兩個序列的布爾元素個數是必須相等的
# 此時就不會再通過reindex進行擴展了,因為array沒有reindex
# 當然都轉成array就更不用說了

我們說了很多關于索引的話題,之所以強調這一點,是因為這里面存在一個坑點。我們知道對于DataFrame對象來說,通過df[xxx]可以取得相應的數據,xxx的身份不同,取得的數據也不同

如果xxx是一個標量, 那么df[xxx]表示獲取df的某一列,得到一個Series對象
如果xxx是一個列表或者numpy的narray, 那么xxx里面可以是該DataFrame對象的列名,表示獲取指定的多個列,得到DataFrame對象
如果xxx是一個列表或者numpy的narray,那么這個xxx里面還可以是布爾值,并且其長度要和該DataFrame對象的行數相等,表示獲取對應的行數。對應為True的保留,為False的不要,也是得到DataFrame對象

舉個栗子

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})


# 只有第一個為True,因此被保留了下來
print(df[[True, False, False]])
"""
   a   b
0  1  11
"""

try:
    # 但此時指定的4個布爾值
    print(df[[True, False, False, False]])
except Exception as e:
    print(e)  # Item wrong length 4 instead of 3.
"""
告訴我們個數不匹配
所以上面之所以說了索引,就是因為在做運算的的時候可能導致布爾值的個數最終和DataFrame的行數不匹配
從而在篩選指定記錄的時候發生報錯
"""

如果是Series也是可以的

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})

flag = pd.Series([True, False, False])
print(df[flag])
"""
   a   b
0  1  11
"""
# 當然里面也可以是一個Series,當然這個Series不僅個數要匹配,索引也要匹配
# 我們知道df的索引是 0 1 2,那么該flag的索引也必須是0 1 2(但是順序不要求)
flag.index = [1, 2, 3]
try:
    df[flag]
except Exception as e:
    print(e)
# Unalignable boolean Series provided as indexer (index of the boolean Series and of the indexed object do not match).


"""
我們看到報了上面那個錯誤,意思我們傳遞了bool類型的Series對象,但是其索引和DataFrame的索引不匹配
"""

# 我們再改一下
flag.index = [1, 2, 0]
print(flag)
"""
1     True
2    False
0    False
dtype: bool
"""
print(df[flag])
"""
   a   b
1  2  22
"""
# 我們看到此時布爾值True對應的索引為1,那么篩選的就不再是df中的第一行了
# 而是索引為1的行,也就是第二行。
# 因此盡管對Series的索引的值有要求,但是對順序卻并沒有要求
# 所以這種情況下,篩選出來的數據可能就和我們想象的不一樣,明明第一個是True,為啥卻把DataFrame的第二行選出來了
# 原因就是,雖然第一個是True,但是它對應的索引是1

因此索引這個東西在定位數據的時候,會非常方便,因為我們可以直接通過索引去定位。但是在一些操作方面,我們關心的并不是它的索引,而是它的值,比如:s1 & s2,或者df[flag],這個時候我們只是對內部的布爾值感興趣,那么直接把s1、s2、flag這些變成numpy中的array之后,再去傳遞即可。此時就無需考慮索引啥的了。

5. 怎么給DataFrame添加字段呢?

給一個DataFrame添加一個字段,并附上初始值有以下幾種方式。

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})

# 可以給一個標量,然后會自動進行廣播
df["c"] = "xx"

# 也可以是一個列表,如果里面只有一個元素,那么和標量是等價的
df["d"] = "yy"
print(df)
"""
   a   b   c   d
0  1  11  xx  yy
1  2  22  xx  yy
2  3  33  xx  yy
"""

# 如果是列表里面有多個值,那么個數必須和df的行數匹配
# 否則會報出ValueError: Length of values does not match length of index
df["e"] = ["x", "y", "z"]
print(df)
"""
   a   b   c   d  e
0  1  11  xx  yy  x
1  2  22  xx  yy  y
2  3  33  xx  yy  z
"""

# 還有一種辦法是通過df.assign,這種辦法可以同時創建多個列
df = df[["a", "b"]]
df = df.assign(
    # 這里指定接收一個參數的函數,這個參數就是整個df
    # 通過關鍵字參數,那么參數名就是列名
    c=lambda x: x["a"] + 1,
    d=lambda x: x["b"] * 2,
    e=lambda x: ["i", "j", "k"],
    f=lambda x: "哼哼"
)
print(df)
"""
   a   b  c   d  e   f
0  1  11  2  22  i  哼哼
1  2  22  3  44  j  哼哼
2  3  33  4  66  k  哼哼
"""

給一個DataFrame添加一個字段,同樣存在索引的陷阱

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})

df["c"] = pd.Series(["x", "y", "z"], index=[0, 2, 3])
print(df)
"""
   a   b    c
0  1  11    x
1  2  22  NaN
2  3  33    y
"""

原因無需我再多解釋,總而言之就是我們剛才說的那樣,如果我們只關心值,不關心索引,那么就不要傳遞Series對象,直接傳遞numpy中的array或者列表即可,這樣我們就根本不需要考慮索引對齊的問題。

傳遞一個一維序列是可以的,那么傳遞一個DataFrame對象會如何呢?

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})

try:
    # 因為df1有兩個字段,這里我們只指定了一個
    df["c"] = df1
except Exception as e:
    print(e)  # Wrong number of items passed 2, placement implies 1

# 我們知道df1["x"]是個Series,所以df["c"] = df1["x"]肯定沒有錯
# 但是df["c"] = df1[["x"]]呢?  df1[["x"]]顯然是個DataFrame
df["c"] = df1[["x"]]
print(df)
"""
   a   b     c
0  1  11    aa
1  2  22    22
2  3  33  None
"""
# 可以看到,如果DataFrame只有一個字段,那么等價于Series


# 最后,df["xx"] = xx 這種方式, 在xx是一維序列的前提下 完全等價于 df.loc[:, "xx"] = xx
# 但如果xx是一個DataFrame的話就不一樣了
df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})

df.loc[:, "c"] = df1
print(df)
"""
   a   b   c
0  1  11 NaN
1  2  22 NaN
2  3  33 NaN
"""
# 我們驚奇地發現它居然沒有報錯,但結果卻是NaN
# 我們rename一下
df1 = df1.rename(columns={"y": "c"})
df.loc[:, "c"] = df1
print(df)
"""
   a   b   c
0  1  11  >>
1  2  22  ^^
2  3  33  YY
"""
# 因此我們發現在使用df.loc[:, "xx"] = df1的時候
# 會自動去找df1中列名為"xx"的列,如果找不到就為NaN

如果給DataFrame添加多個字段的話,除了assign之外,還有什么辦法呢?

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})

df[["c", "d"]] = df1
print(df)
"""
   a   b     c   d
0  1  11    aa  >>
1  2  22    22  ^^
2  3  33  None  YY
"""
# 這里可以要求列名不一致,但是個數必須要匹配


df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})
# 但是對于loc來說,無法添加多個字段
# 添加一個字段是可以的,但是多個不行
try:
    df.loc[:, ["c", "d"]] = df1
except Exception as e:
    # loc表示篩選,而df的列中沒有"c"和"d"
    # 即使是df.loc[:, ["c"]]也不可以,但是df.loc[:, "c"]是可以的
    print(e)  # "None of [Index(['c', 'd'], dtype='object')] are in the [columns]"

# 所以df[["c", "d"]] = df1,如果列c、d不存在, 那么會自動添加
# 但是對于df.loc[:, ["c", "d"]] = df1,如果c、d不存在,則報錯,注意:不是都不存在,而是只要有一個不存在就報錯
# 如果是指定了不存在的索引,暫時不會報錯,而是彈出一個警告
print(df.loc[[1, 11]])
"""
      a     b
1   2.0  22.0
11  NaN   NaN
"""
# 我們看到指定了不存在的索引,那么自動為NaN
# 但同時會拋出一個FutureWarning:
"""
Passing list-likes to .loc or [] with any missing label will raise
KeyError in the future, you can use .reindex() as an alternative.
"""
# 意思是讓我們先reindex一下

所以如果想添加多個字段,可以直接通過df[["c1", "c2"]] = df1的方式,但是注意:右邊寫的df1,所以右邊需要也是一個DataFrame,并且兩者列數相等

import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3], "b": [11, 22, 33]})
df1 = pd.DataFrame({"x": ["aa", 22, None], "y": [">>", "^^", "YY"]})

# 這里我們本意是想創建兩個字段,值都為None
# 但是很遺憾這樣不可以
try:
    # 右邊的值也需要是一個DataFrame
    df[["c", "d"]] = None
except Exception as e:
    # 我們看到這里也同樣報出了相應的錯誤
    # 因此只有當右邊的值是DataFrame的時候,df[["c", "d"]]才能具備創建新字段的能力
    print(e)  # "None of [Index(['c', 'd'], dtype='object')] are in the [columns]"

# 如果想創建多個新字段,并且還希望通過廣播的方式賦上同一個值,那么上面做法是行不通的
# 解決辦法是一個字段一個字段的創建,這樣百分之百是沒有任何問題的,既可以df["c"]也可以df.loc[:, "c"]
# 但是也可以通過我們之前說的assign
df = df.assign(
    c=lambda x: None,
    d=lambda x: None,
)
print(df)
"""
   a   b     c     d
0  1  11  None  None
1  2  22  None  None
2  3  33  None  None
"""

# 除此之外,還有一個insert方法
# 這個方法接收:插入的位置、列名、值
# 比如我想在列c的后面插入一個新列age,值全部是18,該怎么做呢?
df.insert(df.columns.get_loc("c") + 1, "age", 18)
print(df)
"""
   a   b     c  age     d
0  1  11  None   18  None
1  2  22  None   18  None
2  3  33  None   18  None
"""
# 我們看到insert這個方法是在本地進行操作的
# 關鍵是第一個參數,我們希望插在c的后面,那么就必須獲取c所在的索引,當然也可以直接數出來
# 通過columns.get_loc即可獲取,然后再加上1即可

6. ValueError: cannot compute isin with a duplicate axis.

這個錯誤當初也是把我搞懵逼了半天,在復現這個異常之前,我們先來聊聊非常常用的isin

isin我們一般是對Series對象使用,判斷這個序列中每一個元素是不是在另一個序列里面,下面舉例說明:

import pandas as pd

s = pd.Series(["a", "b", "c", "d"])
print(s.isin(["a", "c", "e"]))
"""
0     True
1    False
2     True
3    False
dtype: bool
"""

這個方法是我們經常使用的,但是你對DataFrame使用過isin嗎?我們有時候需要判斷兩個序列,看這兩個序列中的值是否在另外兩個序列里面。

import pandas as pd

df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "B", "c", "D"], "y": [1, 2, 4, 3]})
print(df1)
"""
   x  y
0  a  1
1  b  2
2  c  3
3  d  4
"""
print(df2)
"""
   x  y
0  a  1
1  B  2
2  c  4
3  D  3
"""
print(df1[["x"]].isin(df2))
# DataFrame中有兩列,所以是兩列布爾值
"""
       x      y
0   True   True
1  False   True
2   True  False
3  False  False
"""
# 我們來分析一下,對于df1來說,前兩行肯定是沒有問題的
# 但是第三行有點詭異,我們df1的第三行的y列是3,顯然3是在df2的y列當中啊,為什么是False
# 同理第4行,"d"不在df2的x列中我們知道,但是y列的4很明顯在df2的y列當中,為什么是False

估計有人猜到了,那就是對DataFrame使用isin的時候,多個列之間并不是獨立的。事實上,DataFrame使用isin也是根據索引來的,我們舉個栗子

import pandas as pd

df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
# 兩個一模一樣的DataFrame對象
print(df1.isin(df2))
"""
      x     y
0  True  True
1  True  True
2  True  True
3  True  True
"""
# 結果沒問題,但是我們將df2的索引改變一下
df2.index = [0, 1, 3, 2]
print(df1.isin(df2))
"""
       x      y
0   True   True
1   True   True
2  False  False
3  False  False
"""
# 此時我們就看到端倪了,對于DataFrame對象來講,isin是判斷對應索引的字段的值是否相同

但是問題又來了,因為這樣顯然不是我們期望的結果。因為即使df2中存在,但如果索引對不上的話也沒有任何意義,因此我們可以手動設置索引。

import pandas as pd

df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "b", "d", "c"], "y": [1, 2, 4, 3]})

# 我們將x和y設置為索引不就行了,加上drop=False表示設置索引的同時,還作為列
df1 = df1.set_index(["x", "y"], drop=False)
df2 = df2.set_index(["x", "y"], drop=False)
print(df1)
"""
     x  y
x y      
a 1  a  1
b 2  b  2
c 3  c  3
d 4  d  4
"""
print(df2)
"""
     x  y
x y      
a 1  a  1
b 2  b  2
d 4  d  4
c 3  c  3
"""

print(df1.isin(df2))
"""
        x     y
x y            
a 1  True  True
b 2  True  True
c 3  True  True
d 4  True  True
"""
# 在通過all(axis=1)即可找到滿足條件的值
print(df1.isin(df2).all(axis=1).values)  # [ True  True  True  True]

# 我們看到此時根據索引去找,就能夠準確的定位了
# 不過細心的人可能已經發現了,這個索引是由x和y兩列得到的,事實上索引如果匹配上了,那么值一定是相等的
# 所以此時就沒必要在進行對比了
# 是的,所以我們可以換一種方法
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "b", "d", "c"], "y": [1, 2, 4, 3]})

# pandas中有一個Index類,Series和DataFrame的索引就是Index類型
# 當然Index分為好幾種,但是它們繼承自Index
print(type(df1.index))  # <class 'pandas.core.indexes.range.RangeIndex'>
# 根據x和y兩列創建Index對象
index1 = pd.Index(df1[["x", "y"]])
index2 = pd.Index(df2[["x", "y"]])
print(index1)  # Index([('a', 1), ('b', 2), ('c', 3), ('d', 4)], dtype='object')
print(index2)  # Index([('a', 1), ('b', 2), ('d', 4), ('c', 3)], dtype='object')

# Index對象可以像集合一樣,取并集、交集,當然此時我們可以直接使用isin
# 因為它們整體變成了一個元組,也就是說,此時是一個一維序列,對于一維序列可以直接使用isin
# 直接返回一個numpy中的array
print(index1.isin(index2))  # [ True  True  True  True]

然而這么做有一個弊端,沒錯,我要復現我們上面的異常了

import pandas as pd

df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"x": ["a", "a", "c", "d"], "y": [1, 1, 3, 4]})

# 我們將x和y設置為索引不就行了,加上drop=False表示設置索引的同時,還作為列
df1 = df1.set_index(["x", "y"], drop=False)
df2 = df2.set_index(["x", "y"], drop=False)

try:
    print(df1.isin(df2))
except Exception as e:
    print(e)  # cannot compute isin with a duplicate axis.

# 我們對一個DataFrame使用isin,那么要求isin里面的DataFrame的索引是不可以重復的,否則就會報出上面這個錯誤
# 解決辦法是使用pd.Index
print(pd.Index(df1[["x", "y"]]).isin(pd.Index(df2[["x", "y"]])))  # [ True False  True  True]

# 然鵝,我記得pd.Index這種做法也不保險
# 由于索引的特殊性,好像這種情況我記得也報錯,但是目前沒有
# 因此最穩妥的辦法是再轉成Series
s1 = pd.Series(pd.Index(df1[["x", "y"]]))
s2 = pd.Series(pd.Index(df2[["x", "y"]]))

print(s1)
"""
0    (a, 1)
1    (b, 2)
2    (c, 3)
3    (d, 4)
dtype: object
"""
print(s2)
"""
0    (a, 1)
1    (a, 1)
2    (c, 3)
3    (d, 4)
dtype: object
"""
print(s1.isin(s2))
"""
0     True
1    False
2     True
3     True
dtype: bool
"""
# 這種做法是百分之百沒有問題的


# 忘記說了,df1.isin(df2)的時候,兩個列的名稱一定要對應
df1 = pd.DataFrame({"x": ["a", "b", "c", "d"], "y": [1, 2, 3, 4]})
df2 = pd.DataFrame({"a": ["a", "a", "c", "d"], "y": [1, 1, 3, 4]})
print(df1.isin(df2))
"""
       x      y
0  False   True
1  False  False
2  False   True
3  False   True
"""
# 由于df2中沒有x這一列,因此相當于NaN,所以結果為False
print(df1[["y"]].isin(df2))
"""
       y
0   True
1  False
2   True
3   True
"""
# 會自動找df2中名稱為y的列進行比較,因此記得注意列名
# 當然由于df1.isin(df2)在索引方面的局限性,我們一般也不會使用這種方法
# 而是會將DataFrame的每一個字段的值拼接成一個元組,整體得到一個Series對象
# 然后對Series對象使用isin,這是最正確的做法

7. ValueError: cannot set a frame with no defined index and a scalar

這個錯誤不是很常見,我們來看一下。

import pandas as pd

df = pd.DataFrame({"a": [1, 1, 1, 1], "b": [1, 1, 1, 1]})

df.loc[df["a"] > 2, "c"] = 1
print(df)
"""
   a  b   c
0  1  1 NaN
1  1  1 NaN
2  1  1 NaN
3  1  1 NaN
"""

我們將df["a"] > 2的記錄選出來,然后同時創建"c"這一列,并設置對應的記錄為1。如果不滿足條件,那么會自動為NaN,而我們沒有滿足條件的記錄,所以全部為NaN

import pandas as pd

df = pd.DataFrame({"a": [1, 1, 1, 1], "b": [1, 1, 1, 1]})

df.loc[:, "c"] = 1
print(df)
"""
   a  b  c
0  1  1  1
1  1  1  1
2  1  1  1
3  1  1  1
"""

上面這種賦值方式也是可以的,我們之前說,對于一維序列,df["xx"]等價于df.loc[:, "xx"],但實際上還是有點區別的,那就是后者要求DataFrame不可以為空

import pandas as pd

df = pd.DataFrame({"a": [], "b": []})
print(df)
"""
Empty DataFrame
Columns: [a, b]
Index: []
"""

try:
    df.loc[:, "c"] = 1
except Exception as e:
    print(e)  # cannot set a frame with no defined index and a scalar

# 空DataFrame的話,只能用df["c"] = 1的方式
df["c"] = 1
print(df)
"""
Empty DataFrame
Columns: [a, b, c]
Index: []
"""

8. ValueError: If using all scalar values, you must pass an index

這個錯誤應該遇見的比較少,我們看看這種錯誤是怎么發生的。

import pandas as pd

# 我們說通過字典構建DataFrame,value應該是序列,不應該是一個標量
try:
    df = pd.DataFrame({"a": 123, "b": None})
except Exception as e:
    print(e)  # If using all scalar values, you must pass an index

# 如果傳遞標量的話,那么應該同時指定一個index, index是只有一個元素的列表,里面是一個索引
df = pd.DataFrame({"a": 123, "b": None}, index=["索引"])
print(df)
"""
      a     b
索引  123  None
"""

有待發掘。。。。

總結

以上是生活随笔為你收集整理的pandas中的那些让人有点懵逼的异常(坑向)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。