成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

在數據科學中使用 C 和 C++

大數據 后端
我在一篇涉及 Python 和 GNU Octave 的文章中寫了我不斷學習編程語言的動機,值得大家回顧。這里所有的程序都需要在命令行上運行,而不是在圖形用戶界面(GUI)上運行。完整的示例可在 polyglot_fit 存儲庫中找到。

讓我們使用 C99 和 C++11 完成常見的數據科學任務。

雖然 Python 和 R 之類的語言在數據科學中越來越受歡迎,但是 C 和 C++ 對于高效的數據科學來說是一個不錯的選擇。在本文中,我們將使用 C99 和 C++11 編寫一個程序,該程序使用 Anscombe 的四重奏數據集,下面將對其進行解釋。

我在一篇涉及 Python 和 GNU Octave 的文章中寫了我不斷學習編程語言的動機,值得大家回顧。這里所有的程序都需要在命令行上運行,而不是在圖形用戶界面(GUI)上運行。完整的示例可在 polyglot_fit 存儲庫中找到。

編程任務

你將在本系列中編寫的程序:

  • 從 CSV 文件中讀取數據
  • 用直線插值數據(即 f(x)=m ⋅ x + q)
  • 將結果繪制到圖像文件

這是許多數據科學家遇到的普遍情況。示例數據是 Anscombe 的四重奏的第一組,如下表所示。這是一組人工構建的數據,當擬合直線時可以提供相同的結果,但是它們的曲線非常不同。數據文件是一個文本文件,其中的制表符用作列分隔符,前幾行作為標題。該任務將僅使用第一組(即前兩列)。

在數據科學中使用 C 和 C++

C 語言的方式

C 語言是通用編程語言,是當今使用最廣泛的語言之一(依據 TIOBE 指數、RedMonk 編程語言排名、編程語言流行度指數和 GitHub Octoverse 狀態 得來)。這是一種相當古老的語言(大約誕生在 1973 年),并且用它編寫了許多成功的程序(例如 Linux 內核和 Git 僅是其中的兩個例子)。它也是最接近計算機內部運行機制的語言之一,因為它直接用于操作內存。它是一種編譯語言;因此,源代碼必須由編譯器轉換為機器代碼。它的標準庫很小,功能也不多,因此人們開發了其它庫來提供缺少的功能。

我最常在數字運算中使用該語言,主要是因為其性能。我覺得使用起來很繁瑣,因為它需要很多樣板代碼,但是它在各種環境中都得到了很好的支持。C99 標準是最新版本,增加了一些漂亮的功能,并且得到了編譯器的良好支持。

我將一路介紹 C 和 C++ 編程的必要背景,以便初學者和高級用戶都可以繼續學習。

安裝

要使用 C99 進行開發,你需要一個編譯器。我通常使用 Clang,不過 GCC 是另一個有效的開源編譯器。對于線性擬合,我選擇使用 GNU 科學庫。對于繪圖,我找不到任何明智的庫,因此該程序依賴于外部程序:Gnuplot。該示例還使用動態數據結構來存儲數據,該結構在伯克利軟件分發版(BSD)中定義。

在 Fedora 中安裝很容易:

  1. sudo dnf install clang gnuplot gsl gsl-devel 

代碼注釋

在 C99 中,注釋的格式是在行的開頭放置 //,行的其它部分將被解釋器丟棄。另外,/* 和 */ 之間的任何內容也將被丟棄。

  1. // 這是一個注釋,會被解釋器忽略 
  2. /* 這也被忽略 */ 

必要的庫

庫由兩部分組成:

  • 頭文件,其中包含函數說明
  • 包含函數定義的源文件

頭文件包含在源文件中,而庫文件的源文件則鏈接到可執行文件。因此,此示例所需的頭文件是:

  1. // 輸入/輸出功能 
  2. #include <stdio.h> 
  3. // 標準庫 
  4. #include <stdlib.h> 
  5. // 字符串操作功能 
  6. #include <string.h> 
  7. // BSD 隊列 
  8. #include <sys/queue.h> 
  9. // GSL 科學功能 
  10. #include <gsl/gsl_fit.h> 
  11. #include <gsl/gsl_statistics_double.h> 

主函數

在 C 語言中,程序必須位于稱為主函數 main() 的特殊函數內:

  1. int main(void) { 
  2.     ... 

這與上一教程中介紹的 Python 不同,后者將運行在源文件中找到的所有代碼。

定義變量

在 C 語言中,變量必須在使用前聲明,并且必須與類型關聯。每當你要使用變量時,都必須決定要在其中存儲哪種數據。你也可以指定是否打算將變量用作常量值,這不是必需的,但是編譯器可以從此信息中受益。 以下來自存儲庫中的 fitting_C99.c 程序:

  1. const char *input_file_name = "anscombe.csv"
  2. const char *delimiter = "\t"
  3. const unsigned int skip_header = 3; 
  4. const unsigned int column_x = 0; 
  5. const unsigned int column_y = 1; 
  6. const char *output_file_name = "fit_C99.csv"
  7. const unsigned int N = 100; 

C 語言中的數組不是動態的,從某種意義上說,數組的長度必須事先確定(即,在編譯之前):

  1. int data_array[1024]; 

由于你通常不知道文件中有多少個數據點,因此請使用單鏈列表。這是一個動態數據結構,可以無限增長。幸運的是,BSD 提供了鏈表。這是一個示例定義:

  1. struct data_point { 
  2.     double x; 
  3.     double y; 
  4.     SLIST_ENTRY(data_point) entries; 
  5. }; 
  6. SLIST_HEAD(data_list, data_point) head = SLIST_HEAD_INITIALIZER(head); 
  7. SLIST_INIT(&head); 

該示例定義了一個由結構化值組成的 data_point 列表,該結構化值同時包含 x 值和 y 值。語法相當復雜,但是很直觀,詳細描述它就會太冗長了。

打印輸出

要在終端上打印,可以使用 printf() 函數,其功能類似于 Octave 的 printf() 函數(在第一篇文章中介紹):

  1. printf("#### Anscombe's first set with C99 ####\n"); 

printf() 函數不會在打印字符串的末尾自動添加換行符,因此你必須添加換行符。第一個參數是一個字符串,可以包含傳遞給函數的其他參數的格式信息,例如:

  1. printf("Slope: %f\n", slope); 

讀取數據

現在來到了困難的部分……有一些用 C 語言解析 CSV 文件的庫,但是似乎沒有一個庫足夠穩定或流行到可以放入到 Fedora 軟件包存儲庫中。我沒有為本教程添加依賴項,而是決定自己編寫此部分。同樣,討論這些細節太啰嗦了,所以我只會解釋大致的思路。為了簡潔起見,將忽略源代碼中的某些行,但是你可以在存儲庫中找到完整的示例代碼。

首先,打開輸入文件:

  1. FILE* input_file = fopen(input_file_name, "r"); 

然后逐行讀取文件,直到出現錯誤或文件結束:

  1. while (!ferror(input_file) && !feof(input_file)) { 
  2.     size_t buffer_size = 0; 
  3.     char *buffer = NULL
  4.     
  5.     getline(&buffer, &buffer_size, input_file); 
  6.     ... 

getline() 函數是 POSIX.1-2008 標準新增的一個不錯的函數。它可以讀取文件中的整行,并負責分配必要的內存。然后使用 strtok() 函數將每一行分成字元token。遍歷字元,選擇所需的列:

  1. char *token = strtok(buffer, delimiter); 
  2. while (token != NULL
  3.     double value; 
  4.     sscanf(token, "%lf", &value); 
  5.     if (column == column_x) { 
  6.         x = value; 
  7.     } else if (column == column_y) { 
  8.         y = value; 
  9.     } 
  10.     column += 1; 
  11.     token = strtok(NULL, delimiter); 

最后,當選擇了 x 和 y 值時,將新數據點插入鏈表中:

  1. struct data_point *datum = malloc(sizeof(struct data_point)); 
  2. datum->x = x; 
  3. datum->y = y; 
  4. SLIST_INSERT_HEAD(&head, datum, entries); 

malloc() 函數為新數據點動態分配(保留)一些持久性內存。

擬合數據

GSL 線性擬合函數 gslfitlinear() 期望其輸入為簡單數組。因此,由于你將不知道要創建的數組的大小,因此必須手動分配它們的內存:

  1. const size_t entries_number = row - skip_header - 1; 
  2. double *x = malloc(sizeof(double) * entries_number); 
  3. double *y = malloc(sizeof(double) * entries_number); 

然后,遍歷鏈表以將相關數據保存到數組:

  1. SLIST_FOREACH(datum, &head, entries) { 
  2.     const double current_x = datum->x; 
  3.     const double current_y = datum->y; 
  4.     x[i] = current_x; 
  5.     y[i] = current_y; 
  6.     i += 1; 

現在你已經處理完了鏈表,請清理它。要總是釋放已手動分配的內存,以防止內存泄漏。內存泄漏是糟糕的、糟糕的、糟糕的(重要的話說三遍)。每次內存沒有釋放時,花園侏儒都會找不到自己的頭:

  1. while (!SLIST_EMPTY(&head)) { 
  2.     struct data_point *datum = SLIST_FIRST(&head); 
  3.     SLIST_REMOVE_HEAD(&head, entries); 
  4.     free(datum); 

終于,終于!你可以擬合你的數據了:

  1. gsl_fit_linear(x, 1, y, 1, entries_number, 
  2.                &intercept, &slope, 
  3.                &cov00, &cov01, &cov11, &chi_squared); 
  4. const double r_value = gsl_stats_correlation(x, 1, y, 1, entries_number); 
  5. printf("Slope: %f\n", slope); 
  6. printf("Intercept: %f\n", intercept); 
  7. printf("Correlation coefficient: %f\n", r_value); 

繪圖

你必須使用外部程序進行繪圖。因此,將擬合數據保存到外部文件:

  1. const double step_x = ((max_x + 1) - (min_x - 1)) / N; 
  2. for (unsigned int i = 0; i < N; i += 1) { 
  3.     const double current_x = (min_x - 1) + step_x * i; 
  4.     const double current_y = intercept + slope * current_x; 
  5.     fprintf(output_file, "%f\t%f\n", current_x, current_y); 

用于繪制兩個文件的 Gnuplot 命令是:

  1. plot 'fit_C99.csv' using 1:2 with lines title 'Fit''anscombe.csv' using 1:2 with points pointtype 7 title 'Data' 

結果

在運行程序之前,你必須編譯它:

  1. clang -std=c99 -I/usr/include/ fitting_C99.c -L/usr/lib/ -L/usr/lib64/ -lgsl -lgslcblas -o fitting_C99 

這個命令告訴編譯器使用 C99 標準、讀取 fitting_C99.c 文件、加載 gsl 和 gslcblas 庫、并將結果保存到 fitting_C99。命令行上的結果輸出為:

  1. #### Anscombe's first set with C99 #### 
  2. Slope: 0.500091 
  3. Intercept: 3.000091 
  4. Correlation coefficient: 0.816421 

這是用 Gnuplot 生成的結果圖像:

在數據科學中使用 C 和 C++

C++11 方式

C++ 語言是一種通用編程語言,也是當今使用的最受歡迎的語言之一。它是作為 C 的繼承人創建的(誕生于 1983 年),重點是面向對象程序設計(OOP)。C++ 通常被視為 C 的超集,因此 C 程序應該能夠使用 C++ 編譯器進行編譯。這并非完全正確,因為在某些極端情況下它們的行為有所不同。 根據我的經驗,C++ 與 C 相比需要更少的樣板代碼,但是如果要進行面向對象開發,語法會更困難。C++11 標準是最新版本,增加了一些漂亮的功能,并且基本上得到了編譯器的支持。

由于 C++ 在很大程度上與 C 兼容,因此我將僅強調兩者之間的區別。我在本部分中沒有涵蓋的任何部分,則意味著它與 C 中的相同。

安裝

這個 C++ 示例的依賴項與 C 示例相同。 在 Fedora 上,運行:

  1. sudo dnf install clang gnuplot gsl gsl-devel 

必要的庫

庫的工作方式與 C 語言相同,但是 include 指令略有不同:

  1. #include <cstdlib> 
  2. #include <cstring> 
  3. #include <iostream> 
  4. #include <fstream> 
  5. #include <string> 
  6. #include <vector> 
  7. #include <algorithm> 
  8. extern "C" { 
  9. #include <gsl/gsl_fit.h> 
  10. #include <gsl/gsl_statistics_double.h> 

由于 GSL 庫是用 C 編寫的,因此你必須將這個特殊情況告知編譯器。

定義變量

與 C 語言相比,C++ 支持更多的數據類型(類),例如,與其 C 語言版本相比,string 類型具有更多的功能。相應地更新變量的定義:

  1. const std::string input_file_name("anscombe.csv"); 

對于字符串之類的結構化對象,你可以定義變量而無需使用 = 符號。

打印輸出

你可以使用 printf() 函數,但是 cout 對象更慣用。使用運算符 << 來指示要使用 cout 打印的字符串(或對象):

  1. std::cout << "#### Anscombe's first set with C++11 ####" << std::endl; 
  2. ... 
  3. std::cout << "Slope: " << slope << std::endl; 
  4. std::cout << "Intercept: " << intercept << std::endl; 
  5. std::cout << "Correlation coefficient: " << r_value << std::endl; 

讀取數據

該方案與以前相同。將打開文件并逐行讀取文件,但語法不同:

  1. std::ifstream input_file(input_file_name); 
  2. while (input_file.good()) { 
  3.     std::string line; 
  4.     getline(input_file, line); 
  5.     ... 

使用與 C99 示例相同的功能提取行字元。代替使用標準的 C 數組,而是使用兩個向量。向量是 C++ 標準庫中對 C 數組的擴展,它允許動態管理內存而無需顯式調用 malloc():

  1. std::vector<double> x; 
  2. std::vector<double> y; 
  3. // Adding an element to x and y: 
  4. x.emplace_back(value); 
  5. y.emplace_back(value); 

擬合數據

要在 C++ 中擬合,你不必遍歷列表,因為向量可以保證具有連續的內存。你可以將向量緩沖區的指針直接傳遞給擬合函數:

  1. gsl_fit_linear(x.data(), 1, y.data(), 1, entries_number, 
  2.                &intercept, &slope, 
  3.                &cov00, &cov01, &cov11, &chi_squared); 
  4. const double r_value = gsl_stats_correlation(x.data(), 1, y.data(), 1, entries_number); 
  5. std::cout << "Slope: " << slope << std::endl; 
  6. std::cout << "Intercept: " << intercept << std::endl; 
  7. std::cout << "Correlation coefficient: " << r_value << std::endl; 

繪圖

使用與以前相同的方法進行繪圖。 寫入文件:

  1. const double step_x = ((max_x + 1) - (min_x - 1)) / N; 
  2. for (unsigned int i = 0; i < N; i += 1) { 
  3.     const double current_x = (min_x - 1) + step_x * i; 
  4.     const double current_y = intercept + slope * current_x; 
  5.     output_file << current_x << "\t" << current_y << std::endl; 
  6. output_file.close(); 

然后使用 Gnuplot 進行繪圖。

結果

在運行程序之前,必須使用類似的命令對其進行編譯:

  1. clang++ -std=c++11 -I/usr/include/ fitting_Cpp11.cpp -L/usr/lib/ -L/usr/lib64/ -lgsl -lgslcblas -o fitting_Cpp11 

命令行上的結果輸出為:

  1. #### Anscombe's first set with C++11 #### 
  2. Slope: 0.500091 
  3. Intercept: 3.00009 
  4. Correlation coefficient: 0.816421 

這就是用 Gnuplot 生成的結果圖像:

在數據科學中使用 C 和 C++

結論

本文提供了用 C99 和 C++11 編寫的數據擬合和繪圖任務的示例。由于 C++ 在很大程度上與 C 兼容,因此本文利用了它們的相似性來編寫了第二個示例。在某些方面,C++ 更易于使用,因為它部分減輕了顯式管理內存的負擔。但是其語法更加復雜,因為它引入了為 OOP 編寫類的可能性。但是,仍然可以用 C 使用 OOP 方法編寫軟件。由于 OOP 是一種編程風格,因此可以在任何語言中使用。在 C 中有一些很好的 OOP 示例,例如 GObject 和 Jansson庫。

對于數字運算,我更喜歡在 C99 中進行,因為它的語法更簡單并且得到了廣泛的支持。直到最近,C++11 還沒有得到廣泛的支持,我傾向于避免使用先前版本中的粗糙不足之處。對于更復雜的軟件,C++ 可能是一個不錯的選擇。

你是否也將 C 或 C++ 用于數據科學?在評論中分享你的經驗。

責任編輯:未麗燕 來源: Linux.cn
相關推薦

2011-05-18 18:05:47

C#C++

2011-05-18 17:56:38

C#C++

2011-05-12 18:14:29

算法

2011-05-17 16:20:46

C++

2011-03-30 10:41:11

C++數據庫

2012-08-20 10:43:50

IBMdW

2010-01-26 15:51:06

C++變量

2016-08-31 16:39:59

PythonRC++

2009-04-14 14:53:06

C++Lambda函數多線程

2020-07-30 12:40:35

CC++編程語言

2009-08-19 10:09:21

C#和C++

2011-04-11 09:43:25

C++C

2021-02-26 10:41:59

C++程序員代碼

2020-08-18 08:09:55

Docker容器工具

2010-01-27 15:58:35

C++數據結構

2024-05-15 16:01:04

C++編程開發

2011-07-14 17:45:06

CC++

2011-05-19 09:53:33

數據庫對象

2010-01-20 09:54:27

C++數據類型

2009-09-04 17:34:11

C#CC++
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲精品在线视频 | 亚洲欧洲精品一区 | tube国产| 久久久久国产精品免费免费搜索 | 9999国产精品欧美久久久久久 | 搞av.com| 96国产精品久久久久aⅴ四区 | 国产精品中文字幕在线观看 | 成人一级视频在线观看 | a级在线免费视频 | 天天综合网永久 | 久久亚洲天堂 | 国产视频一区二区 | 午夜小视频在线观看 | 国产亚洲精品久久19p | 日韩一区二区三区在线观看 | 欧美性网 | 免费永久av | 久久久久国产精品 | 精品视频在线一区 | 中文字幕一区在线观看视频 | 欧美在线| 九九九久久国产免费 | 人人插人人 | 一区二区三区免费 | 欧美日本在线观看 | 91成人精品视频 | 九九综合| 黄频视频 | 超碰在线观看97 | 亚洲成人一区 | 国产精品久久久久久久久久久免费看 | 欧美久久精品一级c片 | 久久亚洲欧美日韩精品专区 | 亚洲在线视频 | 成人在线国产 | 最新国产福利在线 | 成人午夜视频在线观看 | 日本电影一区二区 | 久久精品一二三影院 | 久久人 |