《使用Python和Dask實現分布式並行計算》5. Cleaning and transforming DataFrames(清洗和轉換DataFrame)


楔子

對於任何數據科學項目而言,數據清理都是非常重要的一個環節,因為數據中的異常值會對統計分析產生負面的影響,從而導致我們得出錯誤的結論,最終可能建立起無法成立的機器學習模型。因此在數據的探索性分析之前,盡可能地清洗數據是很有必要。

在我們清洗數據時,你還會了解到Dask提供的許多操作DataFrame的方法,當然這些方法和pandas的DataFrame是非常類似的,可以說幾乎沒什么區別,因為Dask DataFrame就是由多個pandas DataFrame組成的。所以在介紹的時候,我們不會說的那么詳細,其實如果你會pandas的話,這一章你幾乎可以一目十行的瀏覽。不過有些操作雖然看起來相同,但由於Dask的分布式特性,我們還會看到這些相同的操作會有一些不同的表現、以及Dask如何處理這些差異。

這里還是使用之前的nyc停車罰單數據,當然你也可以使用其它的數據,不過最好還是保持一致。

import dask.dataframe as dd
from dask.diagnostics import ProgressBar
import numpy as np
# 以上三個模塊提前導入一下, 這里我們的代碼都在jupyter notebook上運行

dtypes = {  # 共同的列以及合適的類型
    'Date First Observed': np.str,
    'Days Parking In Effect    ': np.str,
    'Double Parking Violation': np.str,
    'Feet From Curb': np.float32,
    'From Hours In Effect': np.str,
    'House Number': np.str,
    'Hydrant Violation': np.str,
    'Intersecting Street': np.str,
    'Issue Date': np.str,
    'Issuer Code': np.float32,
    'Issuer Command': np.str,
    'Issuer Precinct': np.float32,
    'Issuer Squad': np.str,
    'Issuing Agency': np.str,
    'Law Section': np.float32,
    'Meter Number': np.str,
    'No Standing or Stopping Violation': np.str,
    'Plate ID': np.str,
    'Plate Type': np.str,
    'Registration State': np.str,
    'Street Code1': np.uint32,
    'Street Code2': np.uint32,
    'Street Code3': np.uint32,
    'Street Name': np.str,
    'Sub Division': np.str,
    'Summons Number': np.uint32,
    'Time First Observed': np.str,
    'To Hours In Effect': np.str,
    'Unregistered Vehicle?': np.str,
    'Vehicle Body Type': np.str,
    'Vehicle Color': np.str,
    'Vehicle Expiration Date': np.str,
    'Vehicle Make': np.str,
    'Vehicle Year': np.float32,
    'Violation Code': np.uint16,
    'Violation County': np.str,
    'Violation Description': np.str,
    'Violation In Front Of Or Opposite': np.str,
    'Violation Legal Code': np.str,
    'Violation Location': np.str,
    'Violation Post Code': np.str,
    'Violation Precinct': np.float32,
    'Violation Time': np.str
}

# 這里的read_csv除了讀取csv文件之外, 還可以讀取txt文件
# 只要是分隔符文本文件, read_csv都是可以讀取的, 只是需要注意分隔符
nyc_data_raw = dd.read_csv(r"C:\Users\satori\Desktop\nyc\*.csv", dtype=dtypes, usecols=dtypes.keys())
print(nyc_data_raw.npartitions)  # 142

注意:這一章內容非常簡單,都是一些pandas DataFrame的一些基礎操作,因為書中是默認你沒有pandas基礎的。但我這里則是認為你有pandas基礎的,所以一些東西我介紹的就不那么詳細了,比如:drop、rename等等,直接就一筆帶過了。事實上,你也會認為我的決定是正確的。

使用索引和軸

之前我們了解到Dask DataFrame有三個結構元素:一個索引和兩個軸,那么下面我們就來看看。

從DataFrame中選擇指定的列

到目前為止,我們除了為每個列選擇了適當的數據類型並讀入到Dask DataFrame之外,我們還沒有對nyc停車罰單數據進行過多的處理。那么下面就來學習如何使用DataFrame的索引和軸,熟悉了它們,我們就可以輕松地開始對數據的探索。

nyc_data_raw["Plate ID"].head()
"""
0    GBB9093
1    62416MB
2    78755JZ
3    63009MA
4    91648MC
Name: Plate ID, dtype: object
"""

如果我們想篩選某一列,那么直接通過字典的方式獲取即可。

nyc_data_raw[["Plate ID", "Registration State"]].head()

篩選多個列的話,那么通過一個列表傳遞即可,篩選單個列得到的是Series,篩選多個列得到的是DataFrame。如果想篩選單個列也得到DataFrame的話,那么也通過列表的方式傳遞即可,比如:nyc_data_raw[["Plate ID"]]

另外,如果是pandas DataFrame的話,那么還有一個filter方法,也是用來篩選指定列的。

def filter(
    self: FrameOrSeries,
    items=None,
    like: Optional[str] = None,
    regex: Optional[str] = None,
    axis=None,
) -> FrameOrSeries:

支持的篩選方式也很多,但是Dask DataFrame中沒有這個方法,切記。

丟棄DataFrame的列

如果我們不想要某些列的話,我們可以手動輸入要篩選的列,但是如果列非常多的話將會是一個可怕的數據量。而Dask DataFrame提供了drop方法,這個和pandas中的drop是一樣的。

len(nyc_data_raw.columns), len(nyc_data_raw.drop(["Violation Code"], axis=1).columns)  # (43, 42)

這里需要指定axis=1,因為我們刪除的是列,刪除列的話顯然是1軸的維度會發生變化,所以要指定axis=1表示對1軸進行操作。或者我個人更喜歡這么做:

len(nyc_data_raw.columns), len(nyc_data_raw.drop(columns=["Violation Code"]).columns)  # (43, 42)

通過關鍵字參數columns指定,這樣就知道你刪除的是列了,同理刪除行是index。

另外,如果刪除一個不存在的列的話會報錯,這個時候可以通過errors參數來避免這一點。

nyc_data_raw.drop(columns=["xxx"], errors="ignore")  
# errors默認是"raise", 列不存在的話會報錯
# 指定為"ignore"的話, 則會忽略這一點

另外,如果刪除一個不存在的列的話會報錯,這個時候可以通過errors參數來避免這一點。

關於篩選想要的列和刪除不想要的列,這兩者是等價的,關鍵是看在輸入方面哪個更方便。

對DataFrame中的列重命名

如果你發現名字不合適,那么你可以對列進行重命名。

print("Plate Type" in nyc_data_raw.columns)  # True
print("Plate Type" in nyc_data_raw.rename(columns={"Plate Type": "Plate Type1"}))  # False

比較簡單,這里不廢話了。

從DataFrame中選擇指定的行

書中介紹的是loc和iloc,我們演示一下吧。

nyc_data_raw.loc[100: 300, ["Plate Type", "Violation Code"]].head()

注意:loc中篩選索引的時候支持切片操作(還有標量),如果是篩選指定的多個索引是不行的。比如:nyc_data_raw.loc[100: 102]可以,nyc_data_raw.loc[100]也可以,但是nyc_data_raw.loc[[100, 101, 102]]不行。

nyc_data_raw.iloc[:, [0, 33]].head()

如果是iloc的話,那么只能選擇列,也就是說使用iloc的話必須是df.iloc[:, column_indexer]形式。

處理缺失值

通常情況下,數據會含有缺失值,這個時候我們需要先對缺失值進行處理,而處理的辦法有多種方式:

  • 刪除數據中含有缺失值的行或者列
  • 給缺失值一個默認值
  • 推算缺失值

計算DataFrame中的缺失值

我們先來看看nyc停車罰單數據中有哪些列有缺失值:

# 默認計算每一列的缺失值數量,如果想計算每一行的缺失值數量的話, 只需在sum函數中傳遞axis=1即可
nyc_data_raw.isnull().sum().compute()
"""
Summons Number                              0
Plate ID                                 8835
Registration State                          0
Plate Type                                  0
Issue Date                                  0
Violation Code                              0
Vehicle Body Type                      239185
Vehicle Make                           275429
Issuing Agency                              0
Street Code1                                0
Street Code2                                0
Street Code3                                0
Vehicle Expiration Date                     1
Violation Location                    6411396
Violation Precinct                          1
Issuer Precinct                             1
Issuer Code                                 1
Issuer Command                        6358897
Issuer Squad                          6360470
Violation Time                           8132
Time First Observed                  38122805
Violation County                      4299524
Violation In Front Of Or Opposite     6754530
House Number                          7169114
Street Name                             23242
Intersecting Street                  30726552
Date First Observed                         3
Law Section                                 3
Sub Division                             5255
Violation Legal Code                 35975989
Days Parking In Effect                9833514
From Hours In Effect                 18976964
To Hours In Effect                   18976961
Vehicle Color                          487877
Unregistered Vehicle?                37463680
Vehicle Year                                5
Meter Number                         34344009
Feet From Curb                              5
Violation Post Code                  11233648
Violation Description                 4878815
No Standing or Stopping Violation    42339437
Hydrant Violation                    42339437
Double Parking Violation             42339437
dtype: int64
"""

刪除含有缺失值的列

現在我們可以處理了,可以將含有缺失值的列刪掉,當然我們這里是刪除缺失值超過總量百分之50列,不然的話整個DataFrame就沒有多少字段了。

# 默認計算每一列的缺失值數量,如果想計算每一行的缺失值數量的話, 只需在sum函數中傳遞axis=1即可
missing_percent = (nyc_data_raw.isnull().sum() / nyc_data_raw.index.size) * 100
nyc_data_clean_stage1 = nyc_data_raw.drop(columns=list(missing_percent[missing_percent >= 50].index))
nyc_data_raw.columns.difference(nyc_data_clean_stage1.columns)
"""
Index(['Double Parking Violation', 'Hydrant Violation', 'Intersecting Street',
       'Meter Number', 'No Standing or Stopping Violation',
       'Time First Observed', 'Unregistered Vehicle?', 'Violation Legal Code'],
      dtype='object')
"""

以上我們便刪除了一部分列。

推測缺失值

如果列只包含很少的缺失值的話,那么我們不應該丟棄整個列,而是應該丟棄行。不過在此之前,我們可以對缺失值進行一個猜測,假設一個列中大量都是重復的,在去重之后只有三個不同的值,那么我們可以選擇出現次數最多的值進行填充。盡管這個結論不總是正確的,但是可以最大程度地提高我們正確選擇的概率。我們以"Vehicle Color"這一列為例:

# 計算該列中出現的值和對應數量
count_of_vehicle_colors = nyc_data_clean_stage1["Vehicle Color"].value_counts().compute()
print(count_of_vehicle_colors)
"""
GY       6280314
WH       6074770
WHITE    5624960
BK       5121030
BLACK    2758479
          ...   
MAU            1
MATOO          1
MATH           1
MARY           1
$RY            1
Name: Vehicle Color, Length: 5744, dtype: int64
"""
# 獲取出現次數最多的元素
most_common_color = count_of_vehicle_colors.iloc[0]
# 填充,得到新的DataFrame,fillna如果接收一個標量是對所有的列進行填充,也可以傳入一個字典對指定的列進行填充
nyc_data_clean_stage2 = nyc_data_clean_stage1.fillna({"Vehicle Color": most_common_color})

刪除含有缺失值的行

現在我們已經對"Vehicle Color"這一列填充了缺失值,因為這一列是與顏色有關的,所以它肯定大部分都是重復的,因此我們選擇了這種做法。還有一些有缺失值、但是比較少的列,我們可以直接刪除它們的行。

# 找出缺失值在百分之0到百分之5之間的列
rows_to_drop = list(missing_percent[(missing_percent > 0) & (missing_percent < 5)].index)
# 刪除它們的缺失值, 使用dropna函數, 該函數和pandas中DataFrame的dropna用法一樣
# 里面可以指定一個how參數:默認為"any", 只要有一個列為缺失值、整行就刪掉;為"all"的話表示所有列都是缺失值、改行才刪掉
# 除此之外, 也可以指定axis, 默認為0、基於0軸操作。如果指定為1, 那么一旦有缺失值整個列就會被刪掉
nyc_data_clean_stage3 = nyc_data_clean_stage2.dropna(subset=rows_to_drop)

用缺失值填充多個列

我們目前已經做完大部分的事了,最后就是用默認值填充缺少數據的其余列。但是有一點很重要,我們為列設置的默認值要符合該列的數據類型,我們先來看看還剩下哪些列。

# 找到缺失值在百分之5到百分之50的
remaining_columns_to_clean = list(missing_percent[(missing_percent >= 5) & (missing_percent < 50)].index)
# 獲取它們的數據類型
nyc_data_raw.dtypes[remaining_columns_to_clean]
"""
Violation Location                   object
Issuer Command                       object
Issuer Squad                         object
Violation County                     object
Violation In Front Of Or Opposite    object
House Number                         object
Days Parking In Effect               object
From Hours In Effect                 object
To Hours In Effect                   object
Violation Post Code                  object
Violation Description                object
dtype: object
"""

我們剩下的列都是字符串類型,但是現實的都是object類型,你可能好奇為什么?答案是這只是一個裝飾,Dask僅顯示數值(int,float)等數據類型,任何非數值的類型都將顯示為對象。

# 我們將使用字符串"Unknow"來填充剩余的列
unknown_default_dict = dict(map(lambda x: (x, "Unknow"), remaining_columns_to_clean))
nyc_data_clean_stage4 = nyc_data_clean_stage3.fillna(unknown_default_dict)

# 看看最后還沒有缺失值
nyc_data_clean_stage4.isnull().sum().compute()
"""
Summons Number                       0
Plate ID                             0
Registration State                   0
Plate Type                           0
Issue Date                           0
Violation Code                       0
Vehicle Body Type                    0
Vehicle Make                         0
Issuing Agency                       0
Street Code1                         0
Street Code2                         0
Street Code3                         0
Vehicle Expiration Date              0
Violation Location                   0
Violation Precinct                   0
Issuer Precinct                      0
Issuer Code                          0
Issuer Command                       0
Issuer Squad                         0
Violation Time                       0
Violation County                     0
Violation In Front Of Or Opposite    0
House Number                         0
Street Name                          0
Date First Observed                  0
Law Section                          0
Sub Division                         0
Days Parking In Effect               0
From Hours In Effect                 0
To Hours In Effect                   0
Vehicle Color                        0
Vehicle Year                         0
Feet From Curb                       0
Violation Post Code                  0
Violation Description                0
dtype: int64
"""

此時我們就已經處理完了所有的缺失值,顯然nyc_data_clean_stage4是我們后續需要使用DataFrame,那么我們是不是應該要將其進行持久化呢?答案是顯然的。

nyc_final_data = nyc_data_clean_stage4.persist()

記錄數據

和缺失值一樣,數據中的一些實例雖然沒有丟失,但是其有效性讓人懷疑,這種情況也很常見。我們需要一種辦法來清理這些異常的數據,至於這里面的異常數據是什么我們就不說了,直接看書上是怎么做的吧。

nyc_data_clean_stage4['Plate Type'].value_counts().compute()
"""
PAS    30452502
COM     7966914
OMT     1389341
SRF      394656
OMS      368952
         ...   
HOU           4
JWV           3
LOC           3
HIF           2
SNO           2
Name: Plate Type, Length: 90, dtype: int64
"""

我們看到大部分的值都是"PAS"和"COM",至於其它的值我們可以使用字符串"Other"來代替。

# 找到"Plate Type"的值在['PAS', 'COM']里面的記錄
condition = nyc_final_data['Plate Type'].isin(['PAS', 'COM'])
# where:接收一個condition和value,將不滿足condition的值替換成value
plate_type_masked = nyc_final_data['Plate Type'].where(condition, 'Other')
# 刪除'Plate Type'這一列
nyc_data_recode_stage1 = nyc_data_clean_stage4.drop('Plate Type', axis=1)
# 我們看到pandas DataFrame中的assign在這里是支持的
nyc_data_recode_stage2 = nyc_data_recode_stage1.assign(PlateType=plate_type_masked)
# 不過原來的名字里面包含了一個空格, 這里再使用rename替換一下
nyc_data_recode_stage3 = nyc_data_recode_stage2.rename(columns={'PlateType':'Plate Type'})

然后我們再來看看里面的值:

nyc_data_recode_stage3['Plate Type'].value_counts().compute()
"""
PAS      30452502
COM       7966914
Other     3418586
Name: Plate Type, dtype: int64
"""

Nice,然后我們再來檢查一下"Vehicle Color"這一列。

nyc_data_recode_stage3['Vehicle Color'].value_counts().compute()
"""
GY       6247250
WH       6027292
WHITE    5550821
BK       5096575
BLACK    2731591
          ...   
REK            1
GJR            1
GJOLD          1
GJA            1
JCCY           1
Name: Vehicle Color, Length: 5335, dtype: int64
"""

這個數據集包含超過5335種獨特的顏色,但顯然這是非常奇怪的,而有大部分顏色都只出現了一次,所以我們將只出現一次的顏色替換為"Other"。

# 找出只出現了一次的顏色
single_color = list(count_of_vehicle_colors[count_of_vehicle_colors == 1].index)
# 獲取出現在里面的顏色
condition = nyc_data_clean_stage4['Vehicle Color'].isin(single_color)
# 注意:where是不滿足condition的值才會被替換為"Other", 所以我們應該對condition取反, 或者將where換成mask
vehicle_color_masked = nyc_data_clean_stage4['Vehicle Color'].mask(condition, 'Other')
# 刪除'Vehicle Color'這一列
nyc_data_recode_stage4 = nyc_data_recode_stage3.drop('Vehicle Color', axis=1)
# 將vehicle_color_masked這一列加進去,然后rename
nyc_data_recode_stage5 = nyc_data_recode_stage4.assign(VehicleColor=vehicle_color_masked)
nyc_data_recode_stage6 = nyc_data_recode_stage5.rename(columns={'VehicleColor':'Vehicle Color'})

Elementwise操作

下面了解一下DataFrame的apply操作。

from datetime import datetime
# apply也算是pandas中一個很常見的操作了,注意:該方法效率不高
# 但是注意里面meta參數,這是和pandas DataFrame中一個不同的地方,因為Dask會推斷輸出類型,但是根據我們之前說的。
# 最好不要讓Dask來猜,而是我們顯式地指定。
issue_date_parsed = nyc_data_recode_stage6['Issue Date'].apply(lambda x: datetime.strptime(x, "%m/%d/%Y"), meta=datetime)
# 刪除Issue Date這一列
nyc_data_derived_stage1 = nyc_data_recode_stage6.drop('Issue Date', axis=1)
# 增加新列
nyc_data_derived_stage2 = nyc_data_derived_stage1.assign(IssueDate=issue_date_parsed)
# 最后rename
nyc_data_derived_stage3 = nyc_data_derived_stage2.rename(columns={'IssueDate':'Issue Date'}

下面我們我們來看一下結果:

nyc_data_derived_stage3['Issue Date'].head()
"""
0   2013-08-04
1   2013-08-04
2   2013-08-05
3   2013-08-05
4   2013-08-08
Name: Issue Date, dtype: datetime64[ns]
"""

此時這一列就不再是我們原來的字符串類型了,而是我們希望的時間類型,那么下面我們再根據這一列得到年月吧。

issue_date_month_year = nyc_data_derived_stage3['Issue Date'].apply(lambda dt: f"{dt: %Y%m}", meta=int)
nyc_data_derived_stage4 = nyc_data_derived_stage3.assign(IssueMonthYear=issue_date_month_year)
nyc_data_derived_stage5 = nyc_data_derived_stage4.rename(columns={'IssueMonthYear':'Citation Issued Month Year'})

# 查看一下結果
nyc_data_derived_stage5['Citation Issued Month Year'].head()
"""
0     201308
1     201308
2     201308
3     201308
4     201308
Name: Citation Issued Month Year, dtype: object
"""

完美,這正是我們想要的結果。不過使用pandas的你肯定發現了,整個流程雖然沒有什么不妥,但是不是有點太麻煩了。直接通過df["col"] = df["col"].apply(lambda x: ...)這種方式不行嗎?為什么非要先刪除、再添加,然后再rename呢?因為書上就是這么寫的,當然我們使用這種方式也是可以的,而且是最正確的選擇。

我們之前說了,Dask DataFrame不支持insert,但是並不代表它就不支持本地修改,我們完全可以通過上面說的這種向量化賦值的操作實現。我們舉個栗子:

print("Citation Issued Month Year" in nyc_data_derived_stage5.columns)  # True
nyc_data_derived_stage5.pop("Citation Issued Month Year")
print("Citation Issued Month Year" in nyc_data_derived_stage5.columns)  # False
nyc_data_derived_stage5["Citation Issued Month Year"] = issue_date_month_year
print("Citation Issued Month Year" in nyc_data_derived_stage5.columns)  # True

對DataFrame進行過濾和重索引

比較簡單,主要是介紹&和|操作符將兩個條件連接起來,沒什么好說的。

對DataFrame進行join和合並

書中這里介紹的是join,但是說實話我個人不建議使用join,而是使用merge。這里我們使用簡單的數據集進行模擬吧。先來看看合並

import dask.dataframe as dd
import pandas as pd

df1 = pd.DataFrame({"id": [1, 2, 3], "name": ["夏色祭", "白上吹雪", "神樂mea"]})
df2 = pd.DataFrame({"id": [4, 5], "name": ["碧居結衣", "神樂七奈"]})

dask_df1 = dd.from_pandas(df1, npartitions=1)
dask_df2 = dd.from_pandas(df2, npartitions=2)

print(dask_df1.append(df2).compute())
"""
   id   name
0   1    夏色祭
1   2   白上吹雪
2   3  神樂mea
0   4   碧居結衣
1   5   神樂七奈
"""
# 或者使用dd.concat
print(dd.concat([dask_df1, dask_df2]).compute())
"""
   id   name
0   1    夏色祭
1   2   白上吹雪
2   3  神樂mea
0   4   碧居結衣
1   5   神樂七奈
"""
# 如果是左右合並的話
print(dd.concat([dask_df1, dask_df2], axis=1).compute())
"""
   id   name      id    name
0   1   夏色祭    4.0   碧居結衣
1   2   白上吹雪   5.0   神樂七奈
2   3  神樂mea    NaN   NaN
"""
# 結果和我們想的也是一樣的,只不過我們一般不會通過concat進行左右合並

再來看看merge:

import dask.dataframe as dd
import pandas as pd

df1 = pd.DataFrame({"id": [1, 2, 3], "name": ["夏色祭", "白上吹雪", "神樂mea"]})
df2 = pd.DataFrame({"id": [1, 3, 2], "age": [18, 38, 22]})

dask_df1 = dd.from_pandas(df1, npartitions=1)
dask_df2 = dd.from_pandas(df2, npartitions=2)

print(dd.merge(dask_df1, dask_df2, how="inner", on="id").compute())
"""
   id   name  age
0   1    夏色祭   18
1   2   白上吹雪   22
2   3  神樂mea   38
"""

一些高級操作

下面來介紹一下我個人在pandas中經常使用的一些操作吧,雖然也算不上高級,但是卻很好用。書上說,很多操作Dask都不支持,但是我發現很多還是可以用的,可能這本書在寫的時候Dask還沒有提供這些方法,而在更新的時候加進去了。

combine_first

這是一個挺好用的方法,專門用來填充缺失值的。

import dask.dataframe as dd
import pandas as pd

df = pd.DataFrame({"old_id": ["1", "2", "3"], "new_id": ["1001", None, "1003"]})

dask_df = dd.from_pandas(df, npartitions=1)
dask_df["new_id"] = dask_df["new_id"].combine_first(dask_df["old_id"])
print(dask_df.compute())
"""
  old_id new_id
0      1   1001
1      2      2
2      3   1003
"""

看出它的用法了嗎?df["a"].combine_first(df["b"]),如果"a"這一列不為空那么保留對應的值,否則使用"b"列中對應的值替換。

combine

它的功能比combine_first要更加豐富一些,比如:

import dask.dataframe as dd
import pandas as pd

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

dask_df = dd.from_pandas(df, npartitions=1)
dask_df["c"] = dask_df["a"].combine(
    dask_df["b"],
    lambda x, y: x if x > y else y
)
print(dask_df.compute())
"""
    a   b   c
0  11   1  11
1   2  22  22
2  33  33  33
"""

df["a"].combine(df["b"], lambda x, y: ...),會將a列和b列中的每一個值都傳遞給x、y,執行邏輯得到返回值。所以我們上面combine_first完全可以使用combine代替,y if dd.isna(x) else x

當然還有to_datetime,這個沒什么好說的,重點是里面的meta參數。此外Series對象下的str方法,在Dask中也是可以使用的。

將數據寫入到文本文件中

我們處理完數據之后,是不是還要將數據寫入到文件中呢?

nyc_data_with_temps.repartition(npartitions=1).to_csv('nyc-final-csv/part*.csv')

我們處理完數據之后,是不是還要將數據寫入到文件中呢?但是注意:我們在文件名中指定了一個*號,它會被Dask指定為文件的分區號。由於我們將所有分區都合並為一個分區,所以它將輸出一個part0.csv文件,但Dask是一個分布式第三方庫,將數據分割成多個文件更有意義,這些文件可以被並行讀取。

總結

  • 選擇列可以使用方括號的形式,里面指定想要篩選的列。
  • head方法默認顯示DataFrame的前10條數據,當然也可以在里面指定要顯示的行數。
  • 可以使用drop方法從DataFrame中刪除列,但是會得到一個新的DataFrame,原來的DataFrame不受影響。不過pandas DataFrame中drop默認情況下也是返回一個新的DataFrame,但是可以通過inplace參數本地修改,而Dask DataFrame不支持這個參數。
  • 可以通過dropna方法將缺失值從DataFrame中刪除。
  • 可以使用drop-assign-rename模式替換DataFrame中的列,但是也可以通過向量化的方式直接替換。
  • 可以使用apply方法對一個列執行元素替換。
  • 支持使用>、<、==過濾數據,如果需要多個條件,可以使用numpy風格的布爾函數。
  • 兩個DataFrame可以合並成一個DataFrame,通過append、concat。
  • 可以使用merge對兩個數據集進行join。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM